diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/Makefile.am libcdio-c742eed/Makefile.am
--- libcdio-f9bd26c/Makefile.am	2012-02-26 05:06:03 +0900
+++ libcdio-c742eed/Makefile.am	2012-02-26 05:07:34 +0900
@@ -38,6 +38,10 @@
 
 SUBDIRS = doc include lib src test example
 
+if BUILD_CD_PARANOIA
+paranoiapcs = libcdio_paranoia.pc libcdio_cdda.pc
+endif
+
 # pkg-config(1) related rules
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = libcdio.pc  \
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/configure.ac libcdio-c742eed/configure.ac
--- libcdio-f9bd26c/configure.ac	2012-02-26 05:07:53 +0900
+++ libcdio-c742eed/configure.ac	2012-02-26 05:07:34 +0900
@@ -51,10 +51,20 @@ AC_ARG_WITH(cd-info,
 	AC_HELP_STRING([--without-cd-info], [don't build program cd-info (default with)]),
 enable_cd_info="${withval}", enable_cd_info=yes)
 
+AC_ARG_WITH(cd-paranoia,
+	AC_HELP_STRING([--without-cd-paranoia], [don't build program cd-paranoia and paranoia libraries (default with)]),
+enable_cd_paranoia="${withval}", enable_cd_paranoia=yes)
+
 AC_ARG_WITH(cdda-player,
 	AC_HELP_STRING([--without-cdda-player], [don't build program cdda-player (default with)]),
 enable_cdda_player="${withval}", enable_cdda_player=yes)
 
+AC_ARG_WITH(cd-paranoia-name,
+	AC_HELP_STRING([--with-cd-paranoia-name], [name to use as the cd-paranoia program name (default cd-paranoia)]),
+cd_paranoia_name="${withval}", cd_paranoia_name="cd-paranoia")
+CDPARANOIA_NAME="$cd_paranoia_name"
+AC_SUBST(CDPARANOIA_NAME)
+
 AC_ARG_WITH(cd-read,
 	AC_HELP_STRING([--without-cd-read], [don't build program cd-read (default with)]),
 enable_cd_read="${withval}", enable_cd_read=yes)
@@ -162,6 +172,13 @@ if test "x$ac_cv_sys_largefiles" = "xyes"; then
     CPPFLAGS="$CPPFLAGS $LIBCDIO_LARGEFILE_FLAGS"
 fi
 
+# We use  cmp and cdparanoia in cd-paranoia regression testing
+AC_PATH_PROG(CMP, cmp, no)
+AC_SUBST(CMP)
+
+AC_PATH_PROG(OLD_CDPARANOIA, cdparanoia, no)
+AC_SUBST(OLD_CDPARANOIA)
+
 AC_DEFINE(LIBCDIO_CONFIG_H, 1, 
   [Is set when libcdio's config.h has been included. Applications wishing to sue their own config.h values (such as set by the application's configure script can define this before including any of libcdio's headers.])
 
@@ -287,6 +304,7 @@ AM_CONDITIONAL(CYGWIN, test "x$CYGWIN" = "xyes")
 AM_CONDITIONAL(BUILD_CD_DRIVE, test "x$enable_cd_drive" = "xyes")
 AM_CONDITIONAL(BUILD_CDINFO, test "x$enable_cd_info" = "xyes")
 AM_CONDITIONAL(BUILD_CD_READ, test "x$enable_cd_read" = "xyes")
+AM_CONDITIONAL(BUILD_CD_PARANOIA, test "x$enable_cd_paranoia" = "xyes")
 AM_CONDITIONAL(BUILD_ISO_INFO, test "x$enable_iso_info" = "xyes")
 AM_CONDITIONAL(BUILD_ISO_READ, test "x$enable_iso_read" = "xyes")
 AM_CONDITIONAL(BUILD_CDINFO_LINUX, test "x$enable_cd_info_linux" = "xyes")
@@ -302,6 +320,7 @@ LIBCDIO_LIBS='$(top_builddir)/lib/driver/libcdio.la'
 LIBCDIO_DEPS="$LIBCDIO_LIBS"
 LIBCDIOPP_LIBS='$(top_builddir)/lib/cdio++/libcdio++.la'
 LIBISO9660PP_LIBS='$(top_builddir)/lib/cdio++/libiso9660++.la'
+LIBCDIO_PARANOIA_LIBS='$(top_builddir)/lib/paranoia/libcdio_paranoia.la'
 LIBISO9660_CFLAGS='-I$(top_srcdir)/lib/iso9660/'
 LIBISO9660_LIBS='$(top_builddir)/lib/iso9660/libiso9660.la'
 LIBUDF_CFLAGS='-I$(top_srcdir)/lib/udf/'
@@ -311,6 +330,7 @@ AC_SUBST(LIBISO9660PP_LIBS)
 AC_SUBST(LIBCDIO_LIBS)
 AC_SUBST(LIBCDIOPP_LIBS)
 AC_SUBST(LIBCDIO_DEPS)
+AC_SUBST(LIBCDIO_PARANOIA_LIBS)
 AC_SUBST(LIBISO9660_LIBS)
 AC_SUBST(LIBUDF_LIBS)
 
@@ -642,17 +662,27 @@ AC_CONFIG_FILES([
        doc/doxygen/Doxyfile \
        doc/Makefile \
        lib/Makefile \
+       lib/cdda_interface/Makefile \
        lib/cdio++/Makefile \
        lib/driver/Makefile \
        lib/iso9660/Makefile \
+       lib/paranoia/Makefile \
        lib/udf/Makefile \
        libcdio.pc \
        libcdio++.pc \
        libcdio_cdda.pc \
+       libcdio_paranoia.pc \
        libiso9660.pc \
        libiso9660++.pc \
        libudf.pc \
        package/libcdio.spec \
+       src/cd-paranoia/Makefile \
+       src/cd-paranoia/usage.txt \
+       src/cd-paranoia/doc/Makefile \
+       src/cd-paranoia/doc/en/cd-paranoia.1 \
+       src/cd-paranoia/doc/en/Makefile \
+       src/cd-paranoia/doc/ja/cd-paranoia.1 \
+       src/cd-paranoia/doc/ja/Makefile \
        src/Makefile \
        test/check_common_fn \
        test/data/Makefile \
@@ -670,10 +700,12 @@ AC_CONFIG_FILES([
 AC_CONFIG_FILES([test/check_cue.sh], [chmod +x test/check_cue.sh])
 AC_CONFIG_FILES([test/check_iso.sh], [chmod +x test/check_iso.sh])
 AC_CONFIG_FILES([test/check_nrg.sh], [chmod +x test/check_nrg.sh])
+AC_CONFIG_FILES([test/check_paranoia.sh], [chmod +x test/check_paranoia.sh])
 AC_OUTPUT
 
 AC_MSG_RESULT([
 Using CD-ROM drivers : $cd_drivers
+Building cd-paranoia : $(test "x$enable_cd_paranoia" = "xyes" && echo yes || echo no)
 Building cd-info     : $(test "x$enable_cd_info" = "xyes" && echo yes || echo no)
 Building cd-read     : $(test "x$enable_cd_read" = "xyes" && echo yes || echo no)
 Building cdda-player : $(test "x$enable_cdda_player" = "xyes" && echo yes || echo no)
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/example/C++/Makefile.am libcdio-c742eed/example/C++/Makefile.am
--- libcdio-f9bd26c/example/C++/Makefile.am	2012-02-26 05:06:03 +0900
+++ libcdio-c742eed/example/C++/Makefile.am	2012-02-26 05:07:34 +0900
@@ -19,9 +19,12 @@
 #
 SUBDIRS = OO
 
+if BUILD_CD_PARANOIA
+paranoia_progs = paranoia paranoia2
+endif
 if BUILD_EXAMPLES
 noinst_PROGRAMS = device eject isofile isofile2 isolist \
-	          mmc1 mmc2
+	          mmc1 mmc2 $(paranoia_progs)
 endif
 
 INCLUDES = -I$(top_srcdir) $(LIBCDIO_CFLAGS)
@@ -34,6 +37,15 @@
 eject_SOURCES       = eject.cpp
 eject_LDADD         = $(LIBCDIO_LIBS)
 
+if BUILD_CD_PARANOIA
+paranoia_SOURCES  = paranoia.cpp
+paranoia_LDADD    = $(LIBCDIO_PARANOIA_LIBS) $(LIBCDIO_CDDA_LIBS) \
+	            $(LIBCDIO_LIBS)
+paranoia2_SOURCES = paranoia.cpp
+paranoia2_LDADD   = $(LIBCDIO_PARANOIA_LIBS) $(LIBCDIO_CDDA_LIBS) \
+	            $(LIBCDIO_LIBS)
+endif
+
 isofile_SOURCES   = isofile.cpp
 isofile_LDADD     = $(LIBISO9660_LIBS) $(LIBCDIO_LIBS) $(LTLIBICONV)
 isofile2_SOURCES  = isofile2.cpp
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/example/Makefile.am libcdio-c742eed/example/Makefile.am
--- libcdio-f9bd26c/example/Makefile.am	2012-02-26 05:06:03 +0900
+++ libcdio-c742eed/example/Makefile.am	2012-02-26 05:07:34 +0900
@@ -21,10 +21,13 @@
 if ENABLE_CPP
 SUBDIRS =  C++
 endif
+if BUILD_CD_PARANOIA
+paranoia_progs = paranoia paranoia2
+endif
 if BUILD_EXAMPLES
 noinst_PROGRAMS = audio cdchange cdtext device discid drives eject \
 	          isofile isofile2 isofuzzy isolist isolsn \
-	          mmc1 mmc2 mmc2a mmc3 tracks \
+	          mmc1 mmc2 mmc2a mmc3 $(paranoia_progs) tracks \
 	          sample3 sample4 udf1 udffile cdio-eject
 endif
 
@@ -54,6 +57,11 @@
 cdio_eject_DEPENDENCIES = $(LIBCDIO_DEPS)
 cdio_eject_LDADD        = $(LIBCDIO_LIBS) $(LTLIBICONV)
 
+if BUILD_CD_PARANOIA
+paranoia_LDADD  = $(LIBCDIO_PARANOIA_LIBS) $(LIBCDIO_CDDA_LIBS) $(LIBCDIO_LIBS) $(LTLIBICONV)
+paranoia2_LDADD = $(LIBCDIO_PARANOIA_LIBS) $(LIBCDIO_CDDA_LIBS) $(LIBCDIO_LIBS) $(LTLIBICONV)
+endif
+
 isofile_LDADD    = $(LIBISO9660_LIBS) $(LIBCDIO_LIBS) $(LTLIBICONV)
 isofile2_LDADD   = $(LIBISO9660_LIBS) $(LIBCDIO_LIBS) $(LTLIBICONV)
 isofuzzy_LDADD   = $(LIBISO9660_LIBS) $(LIBCDIO_LIBS) $(LTLIBICONV)
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/example/paranoia.c libcdio-c742eed/example/paranoia.c
--- libcdio-f9bd26c/example/paranoia.c	1970-01-01 09:00:00 +0900
+++ libcdio-c742eed/example/paranoia.c	2012-02-26 05:07:34 +0900
@@ -0,0 +1,180 @@
+/*
+  Copyright (C) 2005, 2006, 2008, 2009, 2010, 2011
+   Rocky Bernstein <rocky@gnu.org>
+
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* Simple program to show using libcdio's version of the CD-DA paranoia. 
+   library. */
+
+/* config.h has to come first else _FILE_OFFSET_BITS are redefined in
+   say opensolaris. */
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+# define __CDIO_CONFIG_H__ 1
+#endif
+
+#include <cdio/paranoia.h>
+#include <cdio/cd_types.h>
+#include <stdio.h>
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#include <fcntl.h>
+
+static void 
+put_num(long int num, int f, int bytes)
+{
+  unsigned int i;
+  unsigned char c;
+
+  for (i=0; bytes--; i++) {
+    c = (num >> (i<<3)) & 0xff;
+    if (write(f, &c, 1)==-1) {
+      perror("Could not write to output.");
+      exit(1);
+    }
+  }
+}
+
+#define writestr(fd, s) \
+  write(fd, s, sizeof(s)-1)  /* Subtract 1 for trailing '\0'. */
+
+/* Write a the header for a WAV file. */
+static void 
+write_WAV_header(int fd, int32_t i_bytecount){
+  ssize_t bytes_ret;
+  /* quick and dirty */
+  bytes_ret = writestr(fd, "RIFF");     /*  0-3 */
+  put_num(i_bytecount+44-8, fd, 4);     /*  4-7 */
+  bytes_ret = writestr(fd, "WAVEfmt "); /*  8-15 */
+  put_num(16, fd, 4);                   /* 16-19 */
+  put_num(1, fd, 2);                    /* 20-21 */
+  put_num(2, fd, 2);                    /* 22-23 */
+  put_num(44100, fd, 4);                /* 24-27 */
+  put_num(44100*2*2, fd, 4);            /* 28-31 */
+  put_num(4, fd, 2);                    /* 32-33 */
+  put_num(16, fd, 2);                   /* 34-35 */
+  bytes_ret = writestr(fd, "data");     /* 36-39 */
+  put_num(i_bytecount, fd, 4);          /* 40-43 */
+}
+
+int
+main(int argc, const char *argv[])
+{
+  cdrom_drive_t *d = NULL; /* Place to store handle given by cd-paranoia. */
+  char **ppsz_cd_drives;  /* List of all drives with a loaded CDDA in it. */
+
+  /* See if we can find a device with a loaded CD-DA in it. */
+  ppsz_cd_drives = cdio_get_devices_with_cap(NULL, CDIO_FS_AUDIO, false);
+
+  if (ppsz_cd_drives) {
+    /* Found such a CD-ROM with a CD-DA loaded. Use the first drive in
+       the list. */
+    d=cdda_identify(*ppsz_cd_drives, 1, NULL);
+  } else {
+    printf("Unable find or access a CD-ROM drive with an audio CD in it.\n");
+    exit(77);
+  }
+
+  /* Don't need a list of CD's with CD-DA's any more. */
+  cdio_free_device_list(ppsz_cd_drives);
+
+  if ( !d ) {
+    printf("Unable to identify audio CD disc.\n");
+    exit(77);
+  }
+
+  /* We'll set for verbose paranoia messages. */
+  cdda_verbose_set(d, CDDA_MESSAGE_PRINTIT, CDDA_MESSAGE_PRINTIT);
+
+  if ( 0 != cdda_open(d) ) {
+    printf("Unable to open disc.\n");
+    exit(77);
+  }
+
+  /* Okay now set up to read up to the first 300 frames of the first
+     audio track of the Audio CD. */
+  { 
+    cdrom_paranoia_t *p = paranoia_init(d);
+    lsn_t i_first_lsn = cdda_disc_firstsector(d);
+
+    if ( -1 == i_first_lsn ) {
+      printf("Trouble getting starting LSN\n");
+    } else {
+      lsn_t   i_cursor;
+      ssize_t bytes_ret;
+      track_t i_track    = cdda_sector_gettrack(d, i_first_lsn);
+      lsn_t   i_last_lsn = cdda_track_lastsector(d, i_track);
+      int     fd         = creat("track1s.wav", 0644);
+      if (-1 == fd) {
+        printf("Unable to create track1s.wav\n");
+        exit(1);
+      }
+
+      /* For demo purposes we'll read only 300 frames (about 4
+	 seconds).  We don't want this to take too long. On the other
+	 hand, I suppose it should be something close to a real test.
+       */
+      if ( i_last_lsn - i_first_lsn > 300) i_last_lsn = i_first_lsn + 299;
+
+      printf("Reading track %d from LSN %ld to LSN %ld\n", i_track, 
+	     (long int) i_first_lsn, (long int) i_last_lsn);
+
+      /* Set reading mode for full paranoia, but allow skipping sectors. */
+      paranoia_modeset(p, PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP);
+      paranoia_seek(p, i_first_lsn, SEEK_SET);
+      write_WAV_header(fd, (i_last_lsn-i_first_lsn+1) * CDIO_CD_FRAMESIZE_RAW);
+
+      for ( i_cursor = i_first_lsn; i_cursor <= i_last_lsn; i_cursor ++) {
+	/* read a sector */
+	int16_t *p_readbuf=paranoia_read(p, NULL);
+	char *psz_err=cdda_errors(d);
+	char *psz_mes=cdda_messages(d);
+
+	if (psz_mes || psz_err)
+	  printf("%s%s\n", psz_mes ? psz_mes: "", psz_err ? psz_err: "");
+
+	free(psz_err);
+	free(psz_mes);
+	if( !p_readbuf ) {
+	  printf("paranoia read error. Stopping.\n");
+	  break;
+	}
+	bytes_ret = write(fd, p_readbuf, CDIO_CD_FRAMESIZE_RAW);
+      }
+      close(fd);
+    }
+    paranoia_free(p);
+  }
+
+  cdda_close(d);
+
+  exit(0);
+}
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/example/paranoia2.c libcdio-c742eed/example/paranoia2.c
--- libcdio-f9bd26c/example/paranoia2.c	1970-01-01 09:00:00 +0900
+++ libcdio-c742eed/example/paranoia2.c	2012-02-26 05:07:34 +0900
@@ -0,0 +1,96 @@
+/*
+  Copyright (C) 2005, 2006, 2008, 2009 Rocky Bernstein <rocky@gnu.org>
+
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* Simple program to show using libcdio's version of the CD-DA
+   paranoia library. But in this version, we'll open a cdio object before
+   calling paranoia's open. I imagine in many cases such as media
+   players this may be what will be done since, one may want to get
+   CDDB/CD-Text info beforehand.
+ */
+
+#include <cdio/cdda.h>
+#include <cdio/cd_types.h>
+#include <stdio.h>
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+int
+main(int argc, const char *argv[])
+{
+  cdrom_drive_t *d = NULL; /* Place to store handle given by cd-paranoia. */
+  char **ppsz_cd_drives;  /* List of all drives with a loaded CDDA in it. */
+  CdIo_t *p_cdio = NULL;
+
+  /* See if we can find a device with a loaded CD-DA in it. */
+  ppsz_cd_drives = cdio_get_devices_with_cap(NULL, CDIO_FS_AUDIO, false);
+
+  if (ppsz_cd_drives) {
+    /* Found such a CD-ROM with a CD-DA loaded. Use the first drive in
+       the list. */
+    p_cdio = cdio_open(*ppsz_cd_drives, DRIVER_UNKNOWN);
+    d=cdio_cddap_identify_cdio(p_cdio, 1, NULL);
+  } else {
+    printf("Unable find or access a CD-ROM drive with an audio CD in it.\n");
+    exit(77);
+  }
+
+  /* Don't need a list of CD's with CD-DA's any more. */
+  cdio_free_device_list(ppsz_cd_drives);
+
+  if ( !d ) {
+    printf("Unable to identify audio CD disc.\n");
+    exit(77);
+  }
+
+  /* We'll set for verbose paranoia messages. */
+  cdio_cddap_verbose_set(d, CDDA_MESSAGE_PRINTIT, CDDA_MESSAGE_PRINTIT);
+
+  if ( 0 != cdio_cddap_open(d) ) {
+    printf("Unable to open disc.\n");
+    exit(77);
+  }
+
+  /* In the paranoia example was a reading. Here we are going to do
+     something trivial (but I think neat any way - get the Endian-ness
+     of the drive. */
+  {
+    const int i_endian = data_bigendianp(d);
+    switch (i_endian) {
+    case 0:
+      printf("Drive returns audio data Little Endian."
+	     " Your drive is like most.\n");
+      break;
+    case 1:
+      printf("Drive returns audio data Big Endian.\n");
+      break;
+    case -1:
+      printf("Don't know whether drive is Big or Little Endian.\n");
+      break;
+    default:
+      printf("Whoah - got a return result I'm not expecting %d.\n",
+	     i_endian);
+      break;
+    }
+  }
+
+  cdio_cddap_close_no_free_cdio(d);
+  cdio_destroy( p_cdio );
+
+  exit(0);
+}
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/include/cdio/Makefile.am libcdio-c742eed/include/cdio/Makefile.am
--- libcdio-f9bd26c/include/cdio/Makefile.am	2012-02-26 05:07:53 +0900
+++ libcdio-c742eed/include/cdio/Makefile.am	2012-02-26 05:07:34 +0900
@@ -18,6 +18,10 @@
 ########################################################
 #
 
+if BUILD_CD_PARANOIA
+paranoiaheaders = cdda.h 
+endif
+
 cdio_config.h: $(top_builddir)/config.h
 	echo  '#ifndef __CDIO_CONFIG_H__' > cdio_config.h
 	echo  '#define __CDIO_CONFIG_H__' >> cdio_config.h
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/lib/Makefile.am libcdio-c742eed/lib/Makefile.am
--- libcdio-f9bd26c/lib/Makefile.am	2012-02-26 05:06:04 +0900
+++ libcdio-c742eed/lib/Makefile.am	2012-02-26 05:07:35 +0900
@@ -17,8 +19,12 @@
 # make all libraries
 ########################################################
 
+if BUILD_CD_PARANOIA
+paranoiadirs = cdda_interface paranoia
+endif
+
 if ENABLE_CXX_BINDINGS
 cxxdirs = cdio++
 endif
 
-SUBDIRS = driver iso9660 udf $(cxxdirs)
+SUBDIRS = driver iso9660 udf $(paranoiadirs) $(cxxdirs)
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/lib/cdda_interface/Makefile.am libcdio-c742eed/lib/cdda_interface/Makefile.am
--- libcdio-f9bd26c/lib/cdda_interface/Makefile.am	1970-01-01 09:00:00 +0900
+++ libcdio-c742eed/lib/cdda_interface/Makefile.am	2012-02-26 05:07:35 +0900
@@ -0,0 +1,151 @@
+#   Copyright (C) 2004, 2005, 2006, 2007, 2008, 2011
+#    Rocky Bernstein <rocky@gnu.org>
+#
+#   This program is free software: you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation, either version 3 of the License, or
+#   (at your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+########################################################
+# Things to make the cdda_interface library
+########################################################
+
+#
+# From libtool documentation amended with guidance from N. Boullis: 
+#
+#  1. Start with version information of `0:0:0' for each libtool library.
+#
+#  2. It is probably not a good idea to update the version information 
+#     several times between public releases, but rather once per public
+#     release. (This seems to be more an aesthetic consideration than
+#     a hard technical one.)
+#
+#  3. If the library source code has changed at all since the last
+#     update, then increment REVISION (`C:R:A' becomes `C:R+1:A').
+#
+#  4. If any interfaces have been added, removed, or changed since the
+#     last update, increment CURRENT, and set REVISION to 0.
+#
+#  5. If any interfaces have been added since the last public release,
+#     then increment AGE.
+#
+#  6. If any interfaces have been removed or changed since the last
+#     public release, then set AGE to 0. A changed interface means an
+#     incompatibility with previous versions.
+
+EXTRA_DIST = libcdio_cdda.sym
+
+libcdio_cdda_la_CURRENT = 1
+libcdio_cdda_la_REVISION = 0
+libcdio_cdda_la_AGE = 0
+
+noinst_HEADERS  = common_interface.h drive_exceptions.h low_interface.h \
+		  smallft.h utils.h
+
+libcdio_cdda_sources =  common_interface.c cddap_interface.c interface.c \
+	scan_devices.c	smallft.c toc.c utils.c drive_exceptions.c
+
+lib_LTLIBRARIES = libcdio_cdda.la
+
+libcdio_cdda_la_SOURCES = $(libcdio_cdda_sources)
+libcdio_cdda_la_ldflags = -version-info $(libcdio_cdda_la_CURRENT):$(libcdio_cdda_la_REVISION):$(libcdio_cdda_la_AGE) @LT_NO_UNDEFINED@
+
+INCLUDES = $(LIBCDIO_CFLAGS)
+
+FLAGS=@LIBCDIO_CFLAGS@ @UCDROM_H@ @TYPESIZES@ @CFLAGS@
+
+OPT=$(FLAGS)
+DEBUG=$(FLAGS) -DCDDA_TEST
+
+## test:	
+##	$(MAKE) libcdio_cdda.a CFLAGS="$(DEBUG)"
+##	$(CC) $(DEBUG) -c test_interface.c
+##	$(LD) $(DEBUG) test_interface.o $(LDFLAGS) -o cdda_test $(LIBS) libcdio_cdda.a
+
+LIBS = $(LIBCDIO_LIBS) @COS_LIB@
+
+
+########################################################
+# Things to version the symbols in the libraries
+########################################################
+
+# An explanation of the versioning problem from Nicolas Boullis and
+# the versioned symbol solution he uses below...
+# 
+# Currently, libvcdinfo uses the cdio_open function from libcdio.
+# Let's imagine a program foobar that uses both the vcdinfo_open
+# function from libvcdinfo and the cdio_open function from libcdio.
+
+# Currently, libcdio has SONAME libcdio.so.0, libvcdinfo has SONAME
+# libvcdinfo.so.0 and requires libcdio.so.0, and foobar requires both
+# libvcdinfo.so.0 and libcdio.so.0. Everything looks fine.
+#
+# Now, for some reason, you decide to change the cdio_open function.
+# That's your right, but you have to bump the CURRENT version and (if I
+# understand it correctly, athough this is not that clear in libtool's
+# documentation) set the AGE to 0. Anyway, this bumps the SONAME, which is
+# sane since the interface changes incompatibly.
+
+# Now, you have a new libcdio with SONAME libcdio.so.1. But libvcdinfo and
+# foobar still require libcdio.so.0. Everything is still fine.
+
+# Now, after some minor changes, the author of foobar recompiles foobar.
+# Then, foobar now requires libvcdinfo.so.0 and libcdio.so.1. And foobar
+# now segfaults...
+
+# What is happening? When you run foobar, if brings both libvcdinfo.so.0
+# and libcdio.so.1, but libvcdinfo.so.0 also brings libcdio.so.0. So you
+# have both libcdio.so.0 and libcdio.so.1 that bring their symbols to the
+# global namespace. Hence, you have to incompatible versions of the
+# cdio_open function in the name space. When foobar calls cdio_open, it
+# may choose the wrong function, and segfaults...
+
+# With versioned symbols, the cdio_open function from libcdio.so.0 may be
+# known as (something that looks like) cdio_open@@CDIO_0. An the cdio_open
+# function from libcdio.so.1 as cdio_open@@CDIO_1. Both versions of
+# libcdio would still be brought in by the most recent foobar, but foobar
+# (and libvcdinfo) know which versioned function to use and then use the
+# good one.
+
+
+# This is some simple versioning where every symbol is versioned with
+# something that looks like the SONAME of the library. More complex (and
+# better) versioning is possible; it is for example what is used by glibc.
+# But good complex versioning is something that requires much more
+# work...
+
+
+# The below is a impliments symbol versioning.  First of all, I
+# compute MAJOR as CURENT - AGE; that is what is used within libtool
+# (at least on GNU/Linux systems) for the number in the SONAME.  The
+# nm command gives the list of symbols known in each of the object
+# files that will be part of the shared library. And the sed command
+# extracts from this list those symbols that will be shared. (This sed
+# command comes from libtool.)
+
+libcdio_cdda_la_MAJOR = $(shell expr $(libcdio_cdda_la_CURRENT) - $(libcdio_cdda_la_AGE))
+if BUILD_VERSIONED_LIBS
+libcdio_cdda_la_LDFLAGS = $(libcdio_cdda_la_ldflags) -Wl,--version-script=libcdio_cdda.la.ver
+libcdio_cdda_la_DEPENDENCIES = libcdio_cdda.la.ver
+
+libcdio_cdda.la.ver: $(libcdio_cdda_la_OBJECTS) $(srcdir)/libcdio_cdda.sym
+	echo 'CDIO_CDDA_$(libcdio_cdda_la_MAJOR) { ' > $@
+	objs=`for obj in $(libcdio_cdda_la_OBJECTS); do sed -ne "s/^pic_object='\(.*\)'$$/\1/p" $$obj; done`; \
+	if test -n "$$objs" ; then \
+	  nm $${objs} | sed -n -e 's/^.*[ 	][ABCDGIRSTW][ABCDGIRSTW]*[ 	][ 	]*\([_A-Za-z][_A-Za-z0-9]*\)$$/\1/p' | sort -u | { first=true; while read symbol; do if grep -q "^$${symbol}\$$" $(srcdir)/libcdio_cdda.sym; then if test $$first = true; then echo "  global:"; first=false; fi; echo "    $${symbol};"; fi; done; } >> $@; \
+	  nm $${objs} | sed -n -e 's/^.*[ 	][ABCDGIRSTW][ABCDGIRSTW]*[ 	][ 	]*\([_A-Za-z][_A-Za-z0-9]*\)$$/\1/p' | sort -u | { first=true; while read symbol; do if grep -q "^$${symbol}\$$" $(srcdir)/libcdio_cdda.sym; then :; else if test $$first = true; then echo "  local:"; first=false; fi; echo "    $${symbol};"; fi; done; } >> $@; \
+	fi
+	echo '};' >> $@
+else 
+libcdio_cdda_la_LDFLAGS = $(libcdio_cdda_la_ldflags)
+endif 
+
+MOSTLYCLEANFILES = libcdio_cdda.la.ver
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/lib/cdda_interface/cddap_interface.c libcdio-c742eed/lib/cdda_interface/cddap_interface.c
--- libcdio-f9bd26c/lib/cdda_interface/cddap_interface.c	1970-01-01 09:00:00 +0900
+++ libcdio-c742eed/lib/cdda_interface/cddap_interface.c	2012-02-26 05:07:35 +0900
@@ -0,0 +1,402 @@
+/*
+  $Id: cddap_interface.c,v 1.8 2008/06/13 19:26:22 flameeyes Exp $
+
+  Copyright (C) 2004, 2005, 2007, 2008 Rocky Bernstein <rocky@gnu.org>
+  Original interface.c Copyright (C) 1994-1997 
+             Eissfeldt heiko@colossus.escape.de
+  Current blenderization Copyright (C) 1998-1999 Monty xiphmont@mit.edu
+  Copyright (C) 1998 Monty xiphmont@mit.edu
+  
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ 
+  CD-ROM code which interfaces between user-level visible CD paranoia
+  routines and libddio routines. (There is some GNU/Linux-specific
+  code here too that should probably be removed.
+
+**/
+
+#include "config.h"
+#include "common_interface.h"
+#include "low_interface.h"
+#include "utils.h"
+
+/** The below variables are trickery to force the above enum symbol
+    values to be recorded in debug symbol tables. They are used to
+    allow one to refer to the enumeration value names in the typedefs
+    above in a debugger and debugger expressions
+*/
+
+paranoia_jitter_t     debug_paranoia_jitter;
+paranoia_cdda_enums_t debug_paranoia_cdda_enums;
+
+/*! reads TOC via libcdio and returns the number of tracks in the disc. 
+    0 is returned if there was an error.
+*/
+static int 
+cddap_readtoc (cdrom_drive_t *d)
+{
+  int i;
+  track_t i_track;
+
+  /* Save TOC Entries */
+  d->tracks = cdio_get_num_tracks(d->p_cdio) ;
+
+  if (CDIO_INVALID_TRACK == d->tracks) return 0;
+
+  i_track   = cdio_get_first_track_num(d->p_cdio);
+  
+  for ( i=0; i < d->tracks; i++) {
+    d->disc_toc[i].bTrack = i_track;
+    d->disc_toc[i].dwStartSector = cdio_get_track_lsn(d->p_cdio, i_track);
+    i_track++;
+  }
+
+  d->disc_toc[i].bTrack = i_track;
+  d->disc_toc[i].dwStartSector = cdio_get_track_lsn(d->p_cdio, 
+						    CDIO_CDROM_LEADOUT_TRACK);
+
+  d->cd_extra=FixupTOC(d, i_track);
+  return --i_track;  /* without lead-out */
+}
+
+
+/* Set operating speed */
+static int 
+cddap_setspeed(cdrom_drive_t *d, int i_speed)
+{
+  return cdio_set_speed(d->p_cdio, i_speed);
+}
+
+/* read 'i_sector' adjacent audio sectors
+ * into buffer '*p' beginning at sector 'begin'
+ */
+
+static long int
+read_blocks (cdrom_drive_t *d, void *p, lsn_t begin, long i_sectors)
+{
+  int retry_count = 0;
+  int err;
+  char *buffer=(char *)p;
+
+  do {
+    err = cdio_read_audio_sectors( d->p_cdio, buffer, begin, i_sectors);
+    
+    if ( DRIVER_OP_SUCCESS != err ) {
+      if (!d->error_retry) return -7;
+      
+      if (i_sectors==1) {
+	/* *Could* be I/O or media error.  I think.  If we're at
+	   30 retries, we better skip this unhappy little
+	   sector. */
+	if (retry_count>MAX_RETRIES-1) {
+	  char b[256];
+	  snprintf(b, sizeof(b), 
+		   "010: Unable to access sector %ld: skipping...\n",
+		   (long int) begin);
+	  cderror(d, b);
+	  return -10;
+	}
+      }
+
+      if(retry_count>4)
+	if(i_sectors>1)
+	  i_sectors=i_sectors*3/4;
+      retry_count++;
+      if (retry_count>MAX_RETRIES) {
+	cderror(d,"007: Unknown, unrecoverable error reading data\n");
+	return(-7);
+      }
+    } else
+      break;
+  } while (err);
+  
+  return(i_sectors);
+}
+
+typedef enum  {
+  JITTER_NONE = 0,
+  JITTER_SMALL= 1,
+  JITTER_LARGE= 2,
+  JITTER_MASSIVE=3
+} jitter_baddness_t;
+
+/* read 'i_sector' adjacent audio sectors
+ * into buffer '*p' beginning at sector 'begin'
+ */
+
+static long int
+jitter_read (cdrom_drive_t *d, void *p, lsn_t begin, long i_sectors,
+	     jitter_baddness_t jitter_badness)
+{
+  static int i_jitter=0;
+  int jitter_flag;
+  long i_sectors_orig = i_sectors;
+  long i_jitter_offset = 0;
+  
+  char *p_buf=malloc(CDIO_CD_FRAMESIZE_RAW*(i_sectors+1));
+  
+  if (d->i_test_flags & CDDA_TEST_ALWAYS_JITTER)
+    jitter_flag = 1;
+  else 
+#ifdef HAVE_DRAND48
+    jitter_flag = (drand48() > .9) ? 1 : 0;
+#else
+    jitter_flag = (rand() > .9) ? 1 : 0;
+#endif
+  
+  if (jitter_flag) {
+    int i_coeff = 0;
+    int i_jitter_sectors = 0;
+    switch(jitter_badness) {
+    case JITTER_SMALL  : i_coeff =   4; break;
+    case JITTER_LARGE  : i_coeff =  32; break;
+    case JITTER_MASSIVE: i_coeff = 128; break;
+    case JITTER_NONE   :
+    default            : ;
+    }
+#ifdef HAVE_DRAND48
+    i_jitter = i_coeff * (int)((drand48()-.5)*CDIO_CD_FRAMESIZE_RAW/8);
+#else
+    i_jitter = i_coeff * (int)((rand()-.5)*CDIO_CD_FRAMESIZE_RAW/8);
+#endif
+    
+    /* We may need to add another sector to compensate for the bytes that
+       will be dropped off when jittering, and the begin location may
+       be a little different.
+    */
+    i_jitter_sectors = i_jitter / CDIO_CD_FRAMESIZE_RAW;
+
+    if (i_jitter >= 0) 
+      i_jitter_offset  = i_jitter % CDIO_CD_FRAMESIZE_RAW;
+    else {
+      i_jitter_offset  = CDIO_CD_FRAMESIZE_RAW - 
+	(-i_jitter % CDIO_CD_FRAMESIZE_RAW);
+      i_jitter_sectors--;
+    }
+    
+    
+    if (begin + i_jitter_sectors > 0) {
+#if !TRACE_PARANOIA
+      char buffer[256];
+      sprintf(buffer, "jittering by %d, offset %ld\n", i_jitter, 
+	      i_jitter_offset);
+      cdmessage(d,buffer); 
+#endif
+
+      begin += i_jitter_sectors;
+      i_sectors ++; 
+    } else 
+      i_jitter_offset = 0;
+    
+  }
+
+  i_sectors = read_blocks(d, p_buf, begin, i_sectors);
+
+  if (i_sectors < 0) return i_sectors;
+  
+  if (i_sectors < i_sectors_orig) 
+    /* Had to reduce # of sectors due to read errors. So give full amount,
+       with no jittering. */
+    memcpy(p, p_buf, i_sectors*CDIO_CD_FRAMESIZE_RAW);
+  else {
+    /* Got full amount, but now adjust size for jittering. */
+    memcpy(p, p_buf+i_jitter_offset, i_sectors_orig*CDIO_CD_FRAMESIZE_RAW);
+    i_sectors = i_sectors_orig;
+  }
+
+  free(p_buf);
+  return(i_sectors);
+}
+
+/* read 'i_sector' adjacent audio sectors
+ * into buffer '*p' beginning at sector 'begin'
+ */
+
+static long int
+cddap_read (cdrom_drive_t *d, void *p, lsn_t begin, long i_sectors)
+{
+  jitter_baddness_t jitter_badness = d->i_test_flags & 0x3;
+
+  /* read d->nsectors at a time, max. */
+  i_sectors = ( i_sectors > d->nsectors && d->nsectors > 0 ) 
+    ? d->nsectors : i_sectors;
+
+  /* If we are testing under-run correction, we will deliberately set
+     what we read a frame short.  */
+  if (d->i_test_flags & CDDA_TEST_UNDERRUN ) 
+    i_sectors--;
+
+  if (jitter_badness) {
+    return jitter_read(d, p, begin, i_sectors, jitter_badness);
+  } else 
+    return read_blocks(d, p, begin, i_sectors);
+  
+}
+
+static int 
+verify_read_command(cdrom_drive_t *d)
+{
+  int i;
+  int16_t *buff=malloc(CDIO_CD_FRAMESIZE_RAW);
+  int audioflag=0;
+  int i_test_flags = d->i_test_flags;
+
+  d->i_test_flags = 0;
+
+  cdmessage(d,"Verifying drive can read CDDA...\n");
+
+  d->enable_cdda(d,1);
+
+  for(i=1;i<=d->tracks;i++){
+    if(cdda_track_audiop(d,i)==1){
+      long firstsector=cdda_track_firstsector(d,i);
+      long lastsector=cdda_track_lastsector(d,i);
+      long sector=(firstsector+lastsector)>>1;
+      audioflag=1;
+
+      if(d->read_audio(d,buff,sector,1)>0){
+	cdmessage(d,"\tExpected command set reads OK.\n");
+	d->enable_cdda(d,0);
+	free(buff);
+	d->i_test_flags = i_test_flags;
+	return(0);
+      }
+    }
+  }
+ 
+  d->enable_cdda(d,0);
+
+  if(!audioflag){
+    cdmessage(d,"\tCould not find any audio tracks on this disk.\n");
+    free(buff);
+    return(-403);
+  }
+
+  cdmessage(d,"\n\tUnable to read any data; "
+	    "drive probably not CDDA capable.\n");
+  
+  cderror(d,"006: Could not read any data from drive\n");
+
+  free(buff);
+  return(-6);
+}
+
+#include "drive_exceptions.h"
+
+#ifdef HAVE_LINUX_MAJOR_H
+static void 
+check_exceptions(cdrom_drive_t *d, const exception_t *list)
+{
+
+  int i=0;
+  while(list[i].model){
+    if(!strncmp(list[i].model,d->drive_model,strlen(list[i].model))){
+      if(list[i].bigendianp!=-1)d->bigendianp=list[i].bigendianp;
+      return;
+    }
+    i++;
+  }
+}
+#endif /* HAVE_LINUX_MAJOR_H */
+
+/* set function pointers to use the ioctl routines */
+int 
+cddap_init_drive (cdrom_drive_t *d)
+{
+  int ret;
+
+#if HAVE_LINUX_MAJOR_H
+  switch(d->drive_type){
+  case MATSUSHITA_CDROM_MAJOR:	/* sbpcd 1 */
+  case MATSUSHITA_CDROM2_MAJOR:	/* sbpcd 2 */
+  case MATSUSHITA_CDROM3_MAJOR:	/* sbpcd 3 */
+  case MATSUSHITA_CDROM4_MAJOR:	/* sbpcd 4 */
+    /* don't make the buffer too big; this sucker don't preempt */
+
+    cdmessage(d,"Attempting to set sbpcd buffer size...\n");
+
+    d->nsectors=8;
+
+#if BUFSIZE_DETERMINATION_FIXED
+    while(1){
+
+      /* this ioctl returns zero on error; exactly wrong, but that's
+         what it does. */
+
+      if (ioctl(d->ioctl_fd, CDROMAUDIOBUFSIZ, d->nsectors)==0) {
+	d->nsectors>>=1;
+	if(d->nsectors==0){
+	  char buffer[256];
+	  d->nsectors=8;
+	  sprintf(buffer,"\tTrouble setting buffer size.  Defaulting to %d sectors.\n",
+		  d->nsectors);
+	  cdmessage(d,buffer);
+	  break; /* Oh, well.  Try to read anyway.*/
+	}
+      } else {
+	char buffer[256];
+	sprintf(buffer,"\tSetting read block size at %d sectors (%ld bytes).\n",
+		d->nsectors,(long)d->nsectors*CDIO_CD_FRAMESIZE_RAW);
+	cdmessage(d,buffer);
+	break;
+      }
+    }
+#endif /* BUFSIZE_DETERMINATION_FIXED */
+
+    break;
+  case IDE0_MAJOR:
+  case IDE1_MAJOR:
+  case IDE2_MAJOR:
+  case IDE3_MAJOR:
+    d->nsectors=8; /* it's a define in the linux kernel; we have no
+		      way of determining other than this guess tho */
+    d->bigendianp=0;
+    d->is_atapi=1;
+
+    check_exceptions(d, atapi_list);
+
+    break;
+  default:
+    d->nsectors=25;  /* The max for SCSI MMC2 */
+  }
+#else
+  { 	 
+    char buffer[256]; 	 
+    d->nsectors = 8; 	 
+    sprintf(buffer,"\tSetting read block size at %d sectors (%ld bytes).\n", 	 
+	    d->nsectors,(long)d->nsectors*CDIO_CD_FRAMESIZE_RAW); 	 
+    cdmessage(d,buffer); 	 
+  } 	 
+#endif /*HAVE_LINUX_MAJOR_H*/
+
+  d->enable_cdda = dummy_exception;
+  d->set_speed   = cddap_setspeed;
+  d->read_toc    = cddap_readtoc;
+  d->read_audio  = cddap_read;
+
+  ret = d->tracks = d->read_toc(d);
+  if(d->tracks<1)
+    return(ret);
+
+  d->opened=1;
+
+  if( (ret=verify_read_command(d)) ) return(ret);
+
+  d->error_retry=1;
+
+  return(0);
+}
+
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/lib/cdda_interface/common_interface.c libcdio-c742eed/lib/cdda_interface/common_interface.c
--- libcdio-f9bd26c/lib/cdda_interface/common_interface.c	1970-01-01 09:00:00 +0900
+++ libcdio-c742eed/lib/cdda_interface/common_interface.c	2012-02-26 05:07:35 +0900
@@ -0,0 +1,271 @@
+/*
+  Copyright (C) 2004, 2005, 2007, 2008, 2010, 2011
+  Rocky Bernstein <rocky@gnu.org>
+  Copyright (C) 1998, 2002 Monty monty@xiph.org
+  
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/******************************************************************
+ *
+ * CDROM communication common to all interface methods is done here 
+ * (mostly ioctl stuff, but not ioctls specific to the 'cooked'
+ * interface) 
+ *
+ ******************************************************************/
+
+/* common_interface.h has to come first else _FILE_OFFSET_BITS are
+   redefined in say opensolaris. */
+#include "common_interface.h"
+#include <math.h>
+#include "utils.h"
+#include "smallft.h"
+
+/* Variables to hold debugger-helping enumerations */
+enum paranoia_cdda_enums;
+enum paranoia_jitter_enums;
+
+/*! Determine Endian-ness of the CD-drive based on reading data from
+  it. Some drives return audio data Big Endian while some (most)
+  return data Little Endian. Drives known to return data bigendian are
+  SCSI drives from Kodak, Ricoh, HP, Philips, Plasmon, Grundig
+  CDR100IPW, and Mitsumi CD-R. ATAPI and MMC drives are little endian.
+
+  rocky: As someone who didn't write the code, I have to say this is
+  nothing less than brilliant. An FFT is done both ways and the the
+  transform is looked at to see which has data in the FFT (or audible)
+  portion. (Or so that's how I understand it.)
+
+  @return 1 if big-endian, 0 if little-endian, -1 if we couldn't
+  figure things out or some error.
+ */
+int 
+data_bigendianp(cdrom_drive_t *d)
+{
+  float lsb_votes=0;
+  float msb_votes=0;
+  int i,checked;
+  int endiancache=d->bigendianp;
+  float *a=calloc(1024,sizeof(float));
+  float *b=calloc(1024,sizeof(float));
+  long readsectors=5;
+  int16_t *buff=malloc(readsectors*CDIO_CD_FRAMESIZE_RAW*sizeof(int16_t));
+  memset(buff, 0, readsectors*CDIO_CD_FRAMESIZE_RAW*sizeof(int16_t));
+
+  /* look at the starts of the audio tracks */
+  /* if real silence, tool in until some static is found */
+
+  /* Force no swap for now */
+  d->bigendianp=-1;
+  
+  cdmessage(d,"\nAttempting to determine drive endianness from data...");
+  d->enable_cdda(d,1);
+  for(i=0,checked=0;i<d->tracks;i++){
+    float lsb_energy=0;
+    float msb_energy=0;
+    if(cdda_track_audiop(d,i+1)==1){
+      long firstsector=cdda_track_firstsector(d,i+1);
+      long lastsector=cdda_track_lastsector(d,i+1);
+      int zeroflag=-1;
+      long beginsec=0;
+      
+      /* find a block with nonzero data */
+      
+      while(firstsector+readsectors<=lastsector){
+	int j;
+	
+	if(d->read_audio(d,buff,firstsector,readsectors)>0){
+	  
+	  /* Avoid scanning through jitter at the edges */
+	  for(beginsec=0;beginsec<readsectors;beginsec++){
+	    int offset=beginsec*CDIO_CD_FRAMESIZE_RAW/2;
+	    /* Search *half* */
+	    for(j=460;j<128+460;j++)
+	      if(buff[offset+j]!=0){
+		zeroflag=0;
+		break;
+	      }
+	    if(!zeroflag)break;
+	  }
+	  if(!zeroflag)break;
+	  firstsector+=readsectors;
+	}else{
+	  d->enable_cdda(d,0);
+	  free(a);
+	  free(b);
+	  free(buff);
+	  return(-1);
+	}
+      }
+
+      beginsec*=CDIO_CD_FRAMESIZE_RAW/2;
+      
+      /* un-interleave for an FFT */
+      if(!zeroflag){
+	int j;
+	
+	for(j=0;j<128;j++)
+	  a[j] = le16_to_cpu(buff[j*2+beginsec+460]);
+	for(j=0;j<128;j++)
+	  b[j] = le16_to_cpu(buff[j*2+beginsec+461]);
+
+	fft_forward(128,a,NULL,NULL);
+	fft_forward(128,b,NULL,NULL);
+
+	for(j=0;j<128;j++)
+	  lsb_energy+=fabs(a[j])+fabs(b[j]);
+	
+	for(j=0;j<128;j++)
+	  a[j] = be16_to_cpu(buff[j*2+beginsec+460]);
+
+	for(j=0;j<128;j++)
+	  b[j] = be16_to_cpu(buff[j*2+beginsec+461]);
+
+	fft_forward(128,a,NULL,NULL);
+	fft_forward(128,b,NULL,NULL);
+
+	for(j=0;j<128;j++)
+	  msb_energy+=fabs(a[j])+fabs(b[j]);
+      }
+    }
+    if(lsb_energy<msb_energy){
+      lsb_votes+=msb_energy/lsb_energy;
+      checked++;
+    }else
+      if(lsb_energy>msb_energy){
+	msb_votes+=lsb_energy/msb_energy;
+	checked++;
+      }
+
+    if(checked==5 && (lsb_votes==0 || msb_votes==0))break;
+    cdmessage(d,".");
+  }
+
+  free(buff);
+  free(a);
+  free(b);
+  d->bigendianp=endiancache;
+  d->enable_cdda(d,0);
+
+  /* How did we vote?  Be potentially noisy */
+  if (lsb_votes>msb_votes) {
+    char buffer[256];
+    cdmessage(d,"\n\tData appears to be coming back Little Endian.\n");
+    sprintf(buffer,"\tcertainty: %d%%\n",(int)
+	    (100.*lsb_votes/(lsb_votes+msb_votes)+.5));
+    cdmessage(d,buffer);
+    return(0);
+  } else {
+    if(msb_votes>lsb_votes){
+      char buffer[256];
+      cdmessage(d,"\n\tData appears to be coming back Big Endian.\n");
+      sprintf(buffer,"\tcertainty: %d%%\n",(int)
+	      (100.*msb_votes/(lsb_votes+msb_votes)+.5));
+      cdmessage(d,buffer);
+      return(1);
+    }
+
+    cdmessage(d,"\n\tCannot determine CDROM drive endianness.\n");
+    return(bigendianp());
+  }
+}
+
+/************************************************************************/
+
+/*! Here we fix up a couple of things that will never happen.  yeah,
+   right.  
+
+   The multisession stuff is from Hannu code; it assumes it knows the
+   leadout/leadin size.  [I think Hannu refers to Hannu Savolainen
+   from GNU/Linux Kernel code.]
+
+   @return -1 if we can't get multisession info, 0 if there is one
+   session only or the last session LBA is the same as the first audio
+   track and 1 if the multi-session lba is higher than first audio track
+*/
+int 
+FixupTOC(cdrom_drive_t *d, track_t i_tracks)
+{
+  int j;
+  
+  /* First off, make sure the 'starting sector' is >=0 */
+  
+  for( j=0; j<i_tracks; j++){
+    if (d->disc_toc[j].dwStartSector<0 ) {
+      cdmessage(d,"\n\tTOC entry claims a negative start offset: massaging"
+		".\n");
+      d->disc_toc[j].dwStartSector=0;
+    }
+    if( j<i_tracks-1 && d->disc_toc[j].dwStartSector>
+       d->disc_toc[j+1].dwStartSector ) {
+      cdmessage(d,"\n\tTOC entry claims an overly large start offset: massaging"
+		".\n");
+      d->disc_toc[j].dwStartSector=0;
+    }
+
+  }
+  /* Make sure the listed 'starting sectors' are actually increasing.
+     Flag things that are blatant/stupid/wrong */
+  {
+    lsn_t last=d->disc_toc[0].dwStartSector;
+    for ( j=1; j<i_tracks; j++){
+      if ( d->disc_toc[j].dwStartSector<last ) {
+	cdmessage(d,"\n\tTOC entries claim non-increasing offsets: massaging"
+		  ".\n");
+	 d->disc_toc[j].dwStartSector=last;
+	
+      }
+      last=d->disc_toc[j].dwStartSector;
+    }
+  }
+
+  d->audio_last_sector = CDIO_INVALID_LSN;
+  
+  {
+    lsn_t last_ses_lsn;
+    if (cdio_get_last_session (d->p_cdio, &last_ses_lsn) < 0)
+      return -1;
+    
+    /* A Red Book Disc must have only one session, otherwise this is a 
+     * CD Extra */
+    if (last_ses_lsn > d->disc_toc[0].dwStartSector) {
+      /* CD Extra discs have two session, the first one ending after 
+       * the last audio track 
+       * Thus the need to fix the length of the the audio data portion to 
+       * not cross the lead-out of this session */
+      for (j = i_tracks-1; j > 1; j--) {
+	if (cdio_get_track_format(d->p_cdio, j+1) != TRACK_FORMAT_AUDIO && 
+	    cdio_get_track_format(d->p_cdio, j) == TRACK_FORMAT_AUDIO) {
+	  /* First session lead-out is 1:30
+	   * Lead-ins are 1:00
+	   * Every session's first track have a 0:02 pregap
+	   *
+	   * That makes a control data section of (90+60+2)*75 sectors in the 
+	   * last audio track */
+	  const int gap = ((90+60+2) * CDIO_CD_FRAMES_PER_SEC);
+	  
+	  if ((last_ses_lsn - gap >= d->disc_toc[j-1].dwStartSector) &&
+	      (last_ses_lsn - gap < d->disc_toc[j].dwStartSector)) {
+	    d->audio_last_sector = last_ses_lsn - gap - 1;
+	    break;
+	  }
+	}
+      }
+      return 1;
+    }
+  }
+    
+  return 0;
+}
+
+
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/lib/cdda_interface/common_interface.h libcdio-c742eed/lib/cdda_interface/common_interface.h
--- libcdio-f9bd26c/lib/cdda_interface/common_interface.h	1970-01-01 09:00:00 +0900
+++ libcdio-c742eed/lib/cdda_interface/common_interface.h	2012-02-26 05:07:35 +0900
@@ -0,0 +1,54 @@
+/*
+  Copyright (C) 2004, 2005, 2008, 2009, 2010, 2011
+  Rocky Bernstein <rocky@gnu.org>
+  Copyright (C) 1998 Monty xiphmont@mit.edu
+  
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _CDDA_COMMON_INTERFACE_H_
+#define _CDDA_COMMON_INTERFACE_H_
+
+#if defined(HAVE_CONFIG_H) && !defined(__CDIO_CONFIG_H__)
+# include "config.h"
+# define __CDIO_CONFIG_H__ 1
+#endif
+
+#include <cdio/types.h>
+#include "low_interface.h"
+
+#if defined(HAVE_LSTAT) && !defined(HAVE_WIN32_CDROM) && !defined(HAVE_OS2_CDROM)
+/* Define this if the CD-ROM device is a file in the filesystem
+   that can be lstat'd
+*/
+#define DEVICE_IN_FILESYSTEM 1
+#else 
+#undef DEVICE_IN_FILESYSTEM
+#endif
+
+/** Test for presence of a cdrom by pinging with the 'CDROMVOLREAD' ioctl() */
+extern int ioctl_ping_cdrom(int fd);
+
+extern char *atapi_drive_info(int fd);
+
+/*! Here we fix up a couple of things that will never happen.  yeah,
+   right.  
+
+   rocky OMITTED FOR NOW:
+   The multisession stuff is from Hannu's code; it assumes it knows
+   the leadout/leadin size.
+*/
+extern int FixupTOC(cdrom_drive_t *d, track_t tracks);
+
+#endif /*_CDDA_COMMON_INTERFACE_H_*/
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/lib/cdda_interface/drive_exceptions.c libcdio-c742eed/lib/cdda_interface/drive_exceptions.c
--- libcdio-f9bd26c/lib/cdda_interface/drive_exceptions.c	1970-01-01 09:00:00 +0900
+++ libcdio-c742eed/lib/cdda_interface/drive_exceptions.c	2012-02-26 05:07:35 +0900
@@ -0,0 +1,82 @@
+/*
+  Copyright (C) 2004, 2008, 2011 Rocky Bernstein <rocky@gnu.org>
+  Copyright (C) 1998 Monty xiphmont@mit.edu
+  
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "common_interface.h"
+#include "drive_exceptions.h"
+
+int dummy_exception (cdrom_drive_t *d,int Switch)
+{
+  return(0);
+}
+
+#if HAVE_LINUX_MAJOR_H
+/* list of drives that affect autosensing in ATAPI specific portions of code 
+   (force drives to detect as ATAPI or SCSI, force ATAPI read command */
+
+const exception_t atapi_list[]={
+  {"SAMSUNG SCR-830 REV 2.09 2.09 ", 1,   0, dummy_exception,scsi_read_mmc2,0},
+  {"Memorex CR-622",                 1,   0, dummy_exception,          NULL,0},
+  {"SONY CD-ROM CDU-561",            0,   0, dummy_exception,          NULL,0},
+  {"Chinon CD-ROM CDS-525",          0,   0, dummy_exception,          NULL,0},
+  {NULL,0,0,NULL,NULL,0}};
+#endif /*HAVE_LINUX_MAJOR_H*/
+
+/* list of drives that affect MMC default settings */
+
+#ifdef NEED_MMC_LIST
+static exception_t mmc_list[]={
+  {"SAMSUNG SCR-830 REV 2.09 2.09 ", 1,   0, dummy_exception,scsi_read_mmc2,0},
+  {"Memorex CR-622",                 1,   0, dummy_exception,          NULL,0},
+  {"SONY CD-ROM CDU-561",            0,   0, dummy_exception,          NULL,0},
+  {"Chinon CD-ROM CDS-525",          0,   0, dummy_exception,          NULL,0},
+  {"KENWOOD CD-ROM UCR",            -1,   0,            NULL,scsi_read_D8,  0},
+  {NULL,0,0,NULL,NULL,0}};
+#endif /*NEED_MMC_LIST*/
+
+/* list of drives that affect SCSI default settings */
+
+#ifdef NEED_SCSI_LIST
+static exception_t scsi_list[]={
+  {"TOSHIBA",                     -1,0x82,scsi_enable_cdda,scsi_read_28,  0},
+  {"IBM",                         -1,0x82,scsi_enable_cdda,scsi_read_28,  0},
+  {"DEC",                         -1,0x82,scsi_enable_cdda,scsi_read_28,  0},
+  
+  {"IMS",                         -1,   0,scsi_enable_cdda,scsi_read_28,  1},
+  {"KODAK",                       -1,   0,scsi_enable_cdda,scsi_read_28,  1},
+  {"RICOH",                       -1,   0,scsi_enable_cdda,scsi_read_28,  1},
+  {"HP",                          -1,   0,scsi_enable_cdda,scsi_read_28,  1},
+  {"PHILIPS",                     -1,   0,scsi_enable_cdda,scsi_read_28,  1},
+  {"PLASMON",                     -1,   0,scsi_enable_cdda,scsi_read_28,  1},
+  {"GRUNDIG CDR100IPW",           -1,   0,scsi_enable_cdda,scsi_read_28,  1},
+  {"MITSUMI CD-R ",               -1,   0,scsi_enable_cdda,scsi_read_28,  1},
+  {"KENWOOD CD-ROM UCR",          -1,   0,            NULL,scsi_read_D8,  0},
+
+  {"YAMAHA",                      -1,   0,scsi_enable_cdda,        NULL,  0},
+
+  {"PLEXTOR",                     -1,   0,            NULL,        NULL,  0},
+  {"SONY",                        -1,   0,            NULL,        NULL,  0},
+
+  {"NEC",                         -1,   0,           NULL,scsi_read_D4_10,0},
+
+  /* the 7501 locks up if hit with the 10 byte version from the
+     autoprobe first */
+  {"MATSHITA CD-R   CW-7501",     -1,   0,           NULL,scsi_read_D4_12,-1},
+
+  {NULL,0,0,NULL,NULL,0}};
+
+#endif /* NEED_SCSI_LIST*/
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/lib/cdda_interface/drive_exceptions.h libcdio-c742eed/lib/cdda_interface/drive_exceptions.h
--- libcdio-f9bd26c/lib/cdda_interface/drive_exceptions.h	1970-01-01 09:00:00 +0900
+++ libcdio-c742eed/lib/cdda_interface/drive_exceptions.h	2012-02-26 05:07:35 +0900
@@ -0,0 +1,58 @@
+/*
+  $Id: drive_exceptions.h,v 1.6 2008/06/13 19:26:23 flameeyes Exp $
+
+  Copyright (C) 2004, 2008 Rocky Bernstein <rocky@gnu.org>
+  Copyright (C) 1998 Monty xiphmont@mit.edu
+  
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+extern int scsi_enable_cdda(cdrom_drive_t *d, int);
+extern long scsi_read_mmc(cdrom_drive_t *d, void *,long,long);
+extern long scsi_read_D4_10(cdrom_drive_t *, void *,long,long);
+extern long scsi_read_D4_12(cdrom_drive_t *, void *,long,long);
+extern long scsi_read_D8(cdrom_drive_t *, void *,long,long);
+extern long scsi_read_28(cdrom_drive_t *, void *,long,long);
+extern long scsi_read_A8(cdrom_drive_t *, void *,long,long);
+
+typedef struct exception {
+  const char *model;
+  int atapi; /* If the ioctl doesn't work */
+  unsigned char density;
+  int  (*enable)(cdrom_drive_t *,int);
+  long (*read)(cdrom_drive_t *,void *, long, long);
+  int  bigendianp;
+} exception_t;
+
+/* specific to general */
+
+#ifdef FINISHED_DRIVE_EXCEPTIONS
+extern long scsi_read_mmc2(cdrom_drive_t *d, void *,long,long);
+#else 
+#define scsi_read_mmc2 NULL
+#endif
+
+int dummy_exception (cdrom_drive_t *d,int Switch);
+
+#if HAVE_LINUX_MAJOR_H
+extern const exception_t atapi_list[];
+#endif
+
+#ifdef NEED_MMC_LIST
+extern const exception_t mmc_list[];
+#endif
+
+#ifdef NEED_SCSI_LIST
+extern const exception_t scsi_list[];
+#endif
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/lib/cdda_interface/interface.c libcdio-c742eed/lib/cdda_interface/interface.c
--- libcdio-f9bd26c/lib/cdda_interface/interface.c	1970-01-01 09:00:00 +0900
+++ libcdio-c742eed/lib/cdda_interface/interface.c	2012-02-26 05:07:35 +0900
@@ -0,0 +1,188 @@
+/*
+  $Id: interface.c,v 1.26 2008/04/16 17:00:40 karl Exp $
+
+  Copyright (C) 2005, 2008 Rocky Bernstein <rocky@gnu.org>
+  Copyright (C) 1998 Monty xiphmont@mit.edu
+  
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/******************************************************************
+ * Top-level interface module for cdrom drive access.  SCSI, ATAPI, etc
+ *    specific stuff are in other modules.  Note that SCSI does use
+ *    specialized ioctls; these appear in common_interface.c where the
+ *    generic_scsi stuff is in scsi_interface.c.
+ *
+ ******************************************************************/
+
+#include "common_interface.h"
+#include "low_interface.h"
+#include "utils.h"
+#include <cdio/bytesex.h>
+#include <cdio/mmc.h>
+
+static void _clean_messages(cdrom_drive_t *d)
+{
+  if(d){
+    if(d->messagebuf)free(d->messagebuf);
+    if(d->errorbuf)free(d->errorbuf);
+    d->messagebuf=NULL;
+    d->errorbuf=NULL;
+  }
+}
+
+/*!
+  Closes d and releases all storage associated with it except
+  the internal p_cdio pointer. 
+
+  @param d cdrom_drive_t object to be closed.
+  @return 0 if passed a null pointer and 1 if not in which case
+  some work was probably done.
+
+  @see cdio_cddap_close
+*/
+bool
+cdio_cddap_close_no_free_cdio(cdrom_drive_t *d)
+{
+  if(d){
+    if(d->opened)
+      d->enable_cdda(d,0);
+
+    _clean_messages(d);
+    if (d->cdda_device_name) free(d->cdda_device_name);
+    if (d->drive_model)      free(d->drive_model);
+    d->cdda_device_name = d->drive_model = NULL;
+    free(d);
+    return true;
+  }
+  return false;
+}
+
+/*!
+  Closes d and releases all storage associated with it.
+  Doubles as "cdrom_drive_free()". 
+
+  @param d cdrom_drive_t object to be closed.
+  @return 0 if passed a null pointer and 1 if not in which case
+  some work was probably done.
+
+  @see cdio_cddap_close_no_free_cdio
+*/
+int 
+cdio_cddap_close(cdrom_drive_t *d)
+{
+  if (d) {
+    CdIo_t *p_cdio = d->p_cdio;
+    cdio_cddap_close_no_free_cdio(d);
+    cdio_destroy (p_cdio);
+    return 1;
+  }
+  return 0;
+}
+
+/* finish initializing the drive! */
+int 
+cdio_cddap_open(cdrom_drive_t *d)
+{
+  int ret;
+  if(d->opened)return(0);
+
+  if ( (ret=cddap_init_drive(d)) )
+    return(ret);
+  
+  /* Check TOC, enable for CDDA */
+  
+  /* Some drives happily return a TOC even if there is no disc... */
+  {
+    int i;
+    for(i=0; i<d->tracks; i++)
+      if(d->disc_toc[i].dwStartSector<0 ||
+	 d->disc_toc[i+1].dwStartSector==0){
+	d->opened=0;
+	cderror(d,"009: CDROM reporting illegal table of contents\n");
+	return(-9);
+      }
+  }
+
+  if((ret=d->enable_cdda(d,1)))
+    return(ret);
+    
+  /*  d->select_speed(d,d->maxspeed); most drives are full speed by default */
+
+  if ( -1 == d->bigendianp ) {
+    d->bigendianp = data_bigendianp(d);
+  }
+  
+
+  return(0);
+}
+
+int 
+cdio_cddap_speed_set(cdrom_drive_t *d, int speed)
+{
+  return d->set_speed ? d->set_speed(d, speed) : 0;
+}
+
+long 
+cdio_cddap_read(cdrom_drive_t *d, void *buffer, lsn_t beginsector, 
+		long sectors)
+{
+  if (d->opened) {
+    if (sectors>0) {
+      sectors=d->read_audio(d, buffer, beginsector, sectors);
+
+      if (sectors > 0) {
+	/* byteswap? */
+	if ( d->bigendianp == -1 ) /* not determined yet */
+	  d->bigendianp = data_bigendianp(d);
+
+	if ( d->b_swap_bytes && d->bigendianp != bigendianp() ) {
+	  int i;
+	  uint16_t *p=(uint16_t *)buffer;
+	  long els=sectors*CDIO_CD_FRAMESIZE_RAW/2;
+	  
+	  for(i=0;i<els;i++)
+	    p[i]=UINT16_SWAP_LE_BE_C(p[i]);
+	}
+      }
+    }
+    return(sectors);
+  }
+  
+  cderror(d,"400: Device not open\n");
+  return(-400);
+}
+
+void 
+cdio_cddap_verbose_set(cdrom_drive_t *d,int err_action, int mes_action)
+{
+  d->messagedest=mes_action;
+  d->errordest=err_action;
+}
+
+extern char *
+cdio_cddap_messages(cdrom_drive_t *d)
+{
+  char *ret=d->messagebuf;
+  d->messagebuf=NULL;
+  return(ret);
+}
+
+extern char *
+cdio_cddap_errors(cdrom_drive_t *d)
+{
+  char *ret=d->errorbuf;
+  d->errorbuf=NULL;
+  return(ret);
+}
+
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/lib/cdda_interface/libcdio_cdda.sym libcdio-c742eed/lib/cdda_interface/libcdio_cdda.sym
--- libcdio-f9bd26c/lib/cdda_interface/libcdio_cdda.sym	1970-01-01 09:00:00 +0900
+++ libcdio-c742eed/lib/cdda_interface/libcdio_cdda.sym	2012-02-26 05:07:35 +0900
@@ -0,0 +1,23 @@
+cdio_cddap_find_a_cdrom
+cdio_cddap_identify
+cdio_cddap_identify_cdio
+cdio_cddap_speed_set
+cdio_cddap_verbose_set
+cdio_cddap_messages
+cdio_cddap_errors
+cdio_cddap_close_no_free_cdio
+cdio_cddap_close
+cdio_cddap_open
+cdio_cddap_read
+cdio_cddap_track_firstsector
+cdio_cddap_track_lastsector
+cdio_cddap_tracks
+cdio_cddap_sector_gettrack
+cdio_cddap_track_channels
+cdio_cddap_track_audiop
+cdio_cddap_track_copyp
+cdio_cddap_track_preemp
+cdio_cddap_disc_firstsector
+cdio_cddap_disc_lastsector
+data_bigendianp
+fft_forward
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/lib/cdda_interface/low_interface.h libcdio-c742eed/lib/cdda_interface/low_interface.h
--- libcdio-f9bd26c/lib/cdda_interface/low_interface.h	1970-01-01 09:00:00 +0900
+++ libcdio-c742eed/lib/cdda_interface/low_interface.h	2012-02-26 05:07:35 +0900
@@ -0,0 +1,66 @@
+/*
+  $Id: low_interface.h,v 1.9 2008/04/16 17:00:40 karl Exp $
+
+  Copyright (C) 2004, 2005, 2008 Rocky Bernstein <rocky@gnu.org>
+  Copyright (C) 1998 Monty xiphmont@mit.edu
+  
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/** internal include file for cdda interface kit for Linux */
+
+#ifndef _CDDA_LOW_INTERFACE_
+#define _CDDA_LOW_INTERFACE_
+
+#ifdef HAVE_STDIO_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#ifdef HAVE_LINUX_VERSION_H
+#include <linux/version.h>
+#endif
+
+#include <cdio/paranoia.h>
+#include <cdio/cdda.h>
+
+/* some include file locations have changed with newer kernels */
+
+#ifndef CDROMAUDIOBUFSIZ      
+#define CDROMAUDIOBUFSIZ        0x5382 /* set the audio buffer size */
+#endif
+
+#ifdef HAVE_LINUX_CDROM_H
+#include <linux/cdrom.h>
+#endif
+
+#ifdef HAVE_LINUX_MAJOR_H
+#include <linux/major.h>
+#endif
+
+#define MAX_RETRIES 8
+#define MAX_BIG_BUFF_SIZE 65536
+#define MIN_BIG_BUFF_SIZE 4096
+#define SG_OFF sizeof(struct sg_header)
+
+extern int  cddap_init_drive (cdrom_drive_t *d);
+#endif /*_CDDA_LOW_INTERFACE_*/
+
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/lib/cdda_interface/scan_devices.c libcdio-c742eed/lib/cdda_interface/scan_devices.c
--- libcdio-f9bd26c/lib/cdda_interface/scan_devices.c	1970-01-01 09:00:00 +0900
+++ libcdio-c742eed/lib/cdda_interface/scan_devices.c	2012-02-26 05:07:35 +0900
@@ -0,0 +1,343 @@
+/*
+  $Id: scan_devices.c,v 1.33 2008/06/16 19:45:44 flameeyes Exp $
+
+  Copyright (C) 2004, 2005, 2007, 2008, 2009 Rocky Bernstein <rocky@gnu.org>
+  Copyright (C) 1998 Monty xiphmont@mit.edu
+  
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/******************************************************************
+ * 
+ * Autoscan for or verify presence of a CD-ROM device
+ * 
+ ******************************************************************/
+
+#include "common_interface.h"
+#include "low_interface.h"
+#include "utils.h"
+#include "cdio/mmc.h"
+#include "cdio/util.h"
+#include <limits.h>
+#include <ctype.h>
+
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX 4096
+#endif
+
+#define MAX_DEV_LEN 20 /* Safe because strings only come from below */
+/* must be absolute paths! */
+static const char scsi_cdrom_prefixes[][16]={
+  "/dev/scd",
+  "/dev/sr",
+  ""};
+static const char scsi_generic_prefixes[][16]={
+  "/dev/sg",
+  ""};
+
+static const char devfs_scsi_test[]="/dev/scsi/";
+static const char devfs_scsi_cd[]="cd";
+static const char devfs_scsi_generic[]="generic";
+
+static const char cdrom_devices[][32]={
+  "/dev/cdrom",
+  "/dev/cdroms/cdrom?",
+  "/dev/hd?",
+  "/dev/sg?",
+  "/dev/cdu31a",
+  "/dev/cdu535",
+  "/dev/sbpcd",
+  "/dev/sbpcd?",
+  "/dev/sonycd",
+  "/dev/mcd",
+  "/dev/sjcd",
+  /* "/dev/aztcd", timeout is too long */
+  "/dev/cm206cd",
+  "/dev/gscd",
+  "/dev/optcd",
+  ""};
+
+static cdrom_drive_t *
+cdda_identify_device_cdio(CdIo_t *p_cdio, const char *psz_device, 
+			  int messagedest, char **ppsz_messages);
+
+/* Functions here look for a cdrom drive; full init of a drive type
+   happens in interface.c */
+
+cdrom_drive_t *
+cdio_cddap_find_a_cdrom(int messagedest, char **ppsz_messages){
+  /* Brute force... */
+  
+  int i=0;
+  cdrom_drive_t *d;
+
+  while(*cdrom_devices[i]!='\0'){
+
+    /* is it a name or a pattern? */
+    char *pos;
+    if((pos=strchr(cdrom_devices[i],'?'))){
+      int j;
+      /* try first eight of each device */
+      for(j=0;j<4;j++){
+	char *buffer=strdup(cdrom_devices[i]);
+
+	/* number, then letter */
+	
+	buffer[pos-(cdrom_devices[i])]=j+48;
+	if((d=cdda_identify(buffer, messagedest, ppsz_messages)))
+	  return(d);
+	idmessage(messagedest, ppsz_messages, "", NULL);
+	buffer[pos-(cdrom_devices[i])]=j+97;
+	if((d=cdda_identify(buffer, messagedest, ppsz_messages)))
+	  return(d);
+	idmessage(messagedest, ppsz_messages, "", NULL);
+	free(buffer);
+      }
+    }else{
+      /* Name.  Go for it. */
+      if((d=cdda_identify(cdrom_devices[i], messagedest, ppsz_messages)))
+	return(d);
+      
+      idmessage(messagedest, ppsz_messages, "", NULL);
+    }
+    i++;
+  }
+  {
+#if defined(HAVE_GETPWUID) && defined(HAVE_GETEUID)
+    struct passwd *temp;
+    temp=getpwuid(geteuid());
+    idmessage(messagedest, ppsz_messages,
+	      "\n\nNo cdrom drives accessible to %s found.\n",
+	      temp->pw_name);
+#else
+    idmessage(messagedest, ppsz_messages,
+	      "\n\nNo cdrom drives accessible found.\n", NULL);
+#endif
+  }
+  return(NULL);
+}
+
+#ifdef DEVICE_IN_FILESYSTEM
+static char *
+test_resolve_symlink(const char *file, int messagedest, char **ppsz_messages)
+{
+  char resolved[PATH_MAX];
+  struct stat st;
+  if (lstat(file,&st)){
+    idperror(messagedest, ppsz_messages, "\t\tCould not stat %s",file);
+    return(NULL);
+  }
+
+  if (cdio_realpath(file,resolved))
+    return(strdup(resolved));
+
+  idperror(messagedest, ppsz_messages, "\t\tCould not resolve symlink %s",
+	   file);
+  return(NULL);
+}
+#endif
+
+/** Returns a paranoia CD-ROM drive object with a CD-DA in it or NULL
+    if there was an error.
+    @see cdio_cddap_identify_cdio
+ */
+cdrom_drive_t *
+cdio_cddap_identify(const char *psz_dev, int messagedest,
+char **ppsz_messages)
+{
+  CdIo_t *p_cdio = NULL;
+
+  if (psz_dev) 
+    idmessage(messagedest, ppsz_messages, "Checking %s for cdrom...", 
+	      psz_dev);
+  else 
+    idmessage(messagedest, ppsz_messages, "Checking for cdrom...", NULL);
+
+#ifdef DEVICE_IN_FILESYSTEM
+  if (psz_dev) {
+    char *psz_device = test_resolve_symlink(psz_dev, messagedest, 
+					    ppsz_messages);
+    if ( psz_device ) {
+      cdrom_drive_t *d=NULL;
+      p_cdio = cdio_open(psz_device, DRIVER_UNKNOWN);
+      d = cdda_identify_device_cdio(p_cdio, psz_device, messagedest, 
+				    ppsz_messages);
+      free(psz_device);
+      return d;
+    }
+  }
+#endif
+
+  p_cdio = cdio_open(psz_dev, DRIVER_UNKNOWN);
+  if (p_cdio) {
+    if (!psz_dev) {
+      psz_dev = cdio_get_arg(p_cdio, "source");
+    }
+    return cdda_identify_device_cdio(p_cdio, psz_dev, messagedest, 
+				     ppsz_messages);
+  }
+  return NULL;
+}
+
+/** Returns a paranoia CD-ROM drive object with a CD-DA in it or NULL
+    if there was an error.  In contrast to cdio_cddap_identify, we
+    start out with an initialized p_cdio object. For example you may
+    have used that for other purposes such as to get CDDB/CD-Text
+    information.  @see cdio_cddap_identify
+ */
+cdrom_drive_t *
+cdio_cddap_identify_cdio(CdIo_t *p_cdio, int messagedest, char **ppsz_messages)
+{
+  if (!p_cdio) return NULL;
+  { 
+    const char *psz_device = cdio_get_arg(p_cdio, "source");
+    idmessage(messagedest, ppsz_messages, "Checking %s for cdrom...", 
+	      psz_device);
+    return cdda_identify_device_cdio(p_cdio, psz_device, messagedest, 
+				     ppsz_messages);
+  }
+
+}
+
+static cdrom_drive_t *
+cdda_identify_device_cdio(CdIo_t *p_cdio, const char *psz_device, 
+			  int messagedest, char **ppsz_messages)
+{
+  cdrom_drive_t *d=NULL;
+  int drive_type = 0;
+  char *description=NULL;
+#ifdef HAVE_LINUX_MAJOR_H
+  struct stat st;
+#endif
+
+  if (!p_cdio) {
+    idperror(messagedest, ppsz_messages, "\t\tUnable to open %s", psz_device);
+    return NULL;
+  }
+  
+#ifdef HAVE_LINUX_MAJOR_H
+  if ( 0 == stat(psz_device, &st) ) {
+    if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
+      drive_type=(int)(st.st_rdev>>8);
+      switch (drive_type) {
+      case IDE0_MAJOR:
+      case IDE1_MAJOR:
+      case IDE2_MAJOR:
+      case IDE3_MAJOR:
+	/* Yay, ATAPI... */
+	description=strdup("ATAPI compatible ");
+	break;
+      case CDU31A_CDROM_MAJOR:
+	/* major indicates this is a cdrom; no ping necessary. */
+	description=strdup("Sony CDU31A or compatible");
+	break;
+      case CDU535_CDROM_MAJOR:
+	/* major indicates this is a cdrom; no ping necessary. */
+	description=strdup("Sony CDU535 or compatible");
+	break;
+	
+      case MATSUSHITA_CDROM_MAJOR:
+      case MATSUSHITA_CDROM2_MAJOR:
+      case MATSUSHITA_CDROM3_MAJOR:
+      case MATSUSHITA_CDROM4_MAJOR:
+	/* major indicates this is a cdrom; no ping necessary. */
+	description=strdup("non-ATAPI IDE-style Matsushita/Panasonic CR-5xx or compatible");
+	break;
+      case SANYO_CDROM_MAJOR:
+	description=strdup("Sanyo proprietary or compatible: NOT CDDA CAPABLE");
+	break;
+      case MITSUMI_CDROM_MAJOR:
+      case MITSUMI_X_CDROM_MAJOR:
+	description=strdup("Mitsumi proprietary or compatible: NOT CDDA CAPABLE");
+	break;
+      case OPTICS_CDROM_MAJOR:
+	description=strdup("Optics Dolphin or compatible: NOT CDDA CAPABLE");
+	break;
+      case AZTECH_CDROM_MAJOR:
+	description=strdup("Aztech proprietary or compatible: NOT CDDA CAPABLE");
+	break;
+      case GOLDSTAR_CDROM_MAJOR:
+	description=strdup("Goldstar proprietary: NOT CDDA CAPABLE");
+	break;
+      case CM206_CDROM_MAJOR:
+	description=strdup("Philips/LMS CM206 proprietary: NOT CDDA CAPABLE");
+	break;
+	
+      case SCSI_CDROM_MAJOR:   
+      case SCSI_GENERIC_MAJOR: 
+	/* Nope nope nope */
+	description=strdup("SCSI CD-ROM");
+	break;
+      default:
+	/* What the hell is this? */
+	idmessage(messagedest, ppsz_messages,
+		  "\t\t%s is not a cooked ioctl CDROM.",
+		  psz_device);
+	return(NULL);
+      }
+    }
+  }
+#endif /*HAVE_LINUX_MAJOR_H*/
+
+  /* Minimum init */
+  
+  d=calloc(1, sizeof(cdrom_drive_t));
+  d->p_cdio           = p_cdio;
+  d->cdda_device_name = strdup(psz_device);
+  d->drive_type       = drive_type;
+  d->bigendianp       = -1; /* We don't know yet... */
+  d->nsectors         = -1; /* We don't know yet... */
+  d->messagedest      = messagedest;
+  d->b_swap_bytes     = true;
+  
+  {
+    cdio_hwinfo_t hw_info = {
+      "UNKNOWN", "Unknown model", "????"
+    };
+
+    if ( mmc_get_hwinfo( p_cdio, &hw_info ) ) {
+      unsigned int i_len = strlen(hw_info.psz_vendor) 
+	+ strlen(hw_info.psz_model) 
+	+ strlen(hw_info.psz_revision) + 5;
+      
+      if (description) {
+	i_len += strlen(description);
+	d->drive_model=malloc( i_len );
+	snprintf( d->drive_model, i_len, "%s %s %s %s", 
+		  hw_info.psz_vendor, hw_info.psz_model, hw_info.psz_revision,
+		  description );
+      } else {
+	d->drive_model=malloc( i_len );
+	snprintf( d->drive_model, i_len, "%s %s %s", 
+		  hw_info.psz_vendor, hw_info.psz_model, hw_info.psz_revision 
+		  );
+      }
+      idmessage(messagedest, ppsz_messages, "\t\tCDROM sensed: %s\n", 
+		d->drive_model);
+    }
+  }
+  
+  if (description)
+    free(description);
+
+  return(d);
+}
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/lib/cdda_interface/scsi_interface.c libcdio-c742eed/lib/cdda_interface/scsi_interface.c
--- libcdio-f9bd26c/lib/cdda_interface/scsi_interface.c	1970-01-01 09:00:00 +0900
+++ libcdio-c742eed/lib/cdda_interface/scsi_interface.c	2012-02-26 05:07:35 +0900
@@ -0,0 +1,1576 @@
+/*
+  $Id: scsi_interface.c,v 1.5 2008/06/25 08:01:53 rocky Exp $
+
+  Copyright (C) 2004, 2008 Rocky Bernstein <rocky@gnu.org>
+  Original interface.c Copyright (C) 1994-1997 
+             Eissfeldt heiko@colossus.escape.de
+  Current blenderization Copyright (C) 1998-1999 Monty xiphmont@mit.edu
+  Copyright (C) 1998 Monty xiphmont@mit.edu
+
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/******************************************************************
+ * 
+ * Generic SCSI interface specific code.
+ *
+ ******************************************************************/
+
+#define NEED_STRERROR_TR
+#define NEED_MMC_LIST
+#define NEED_SCSI_LIST
+
+#include "low_interface.h"
+#include "common_interface.h"
+#include "utils.h"
+#include <cdio/scsi_mmc.h>
+#include <cdio/bytesex.h>
+
+#include "drive_exceptions.h"
+
+static void 
+tweak_SG_buffer(cdrom_drive_t *d){
+  int table,reserved;
+  char buffer[256];
+
+  /* maximum transfer size? */
+  if(ioctl(d->cdda_fd,SG_GET_RESERVED_SIZE,&reserved)){
+    /* Up, guess not. */
+    cdmessage(d,"\tCould not get scatter/gather buffer size.\n");
+    return;
+  }
+
+  if(ioctl(d->cdda_fd,SG_GET_SG_TABLESIZE,&table))table=1;
+  {
+    int cur;
+
+    sprintf(buffer,"\tDMA scatter/gather table entries: %d\n\t"
+	    "table entry size: %d bytes\n\t"
+	    "maximum theoretical transfer: %d sectors\n",
+	    table,reserved,table*reserved/CDIO_CD_FRAMESIZE_RAW);
+    cdmessage(d,buffer);
+
+    cur=table*reserved;
+
+    /* not too much; new kernels have trouble with DMA allocation, so
+       be more conservative: 32kB max until I test more thoroughly */
+    cur=(cur>1024*32?1024*32:cur);
+    d->nsectors=cur/CDIO_CD_FRAMESIZE_RAW;
+    d->bigbuff=cur;
+
+    sprintf(buffer,"\tSetting default read size to %d sectors (%d bytes).\n\n",
+	    d->nsectors,d->nsectors*CDIO_CD_FRAMESIZE_RAW);
+    cdmessage(d,buffer);
+  } 
+
+  /* Disable command queue; we don't need it, no reason to have it on */
+  reserved=0;
+  if(ioctl(d->cdda_fd,SG_SET_COMMAND_Q,&reserved)){
+    cdmessage(d,"\tCouldn't disable command queue!  Continuing anyway...\n");
+  }
+
+}
+
+static void 
+reset_scsi(cdrom_drive_t *d)
+{
+  int arg;
+  d->enable_cdda(d,0);
+
+  cdmessage(d,"sending SG SCSI reset... ");
+  if(ioctl(d->cdda_fd,SG_SCSI_RESET,&arg))
+    cdmessage(d,"FAILED: EBUSY\n");
+  else
+    cdmessage(d,"OK\n");
+  
+  d->enable_cdda(d,1);
+}
+
+static void 
+clear_garbage(cdrom_drive_t *d)
+{
+  fd_set fdset;
+  struct timeval tv;
+  struct sg_header *sg_hd=(struct sg_header *)d->sg;
+  int flag=0;
+
+  /* clear out any possibly preexisting garbage */
+  FD_ZERO(&fdset);
+  FD_SET(d->cdda_fd,&fdset);
+  tv.tv_sec=0;
+  tv.tv_usec=0;
+
+  /* I like select */
+  while(select(d->cdda_fd+1,&fdset,NULL,NULL,&tv)==1){
+    
+    sg_hd->twelve_byte = 0;
+    sg_hd->result = 0;
+    sg_hd->reply_len = SG_OFF;
+    read(d->cdda_fd, sg_hd, 1);
+
+    /* reset for select */
+    FD_ZERO(&fdset);
+    FD_SET(d->cdda_fd,&fdset);
+    tv.tv_sec=0;
+    tv.tv_usec=0;
+    if(!flag && d->report_all)
+      cdmessage(d,"Clearing previously returned data from SCSI buffer\n");
+    flag=1;
+  }
+}
+
+/* process a complete scsi command. */
+static int 
+handle_scsi_cmd(cdrom_drive_t *d, 
+		unsigned int cmd_len,  unsigned int in_size, 
+		unsigned int out_size, unsigned char bytefill,
+		int bytecheck)
+{
+  int status = 0;
+  struct sg_header *sg_hd=(struct sg_header *)d->sg;
+  long writebytes=SG_OFF+cmd_len+in_size;
+
+  /* generic scsi device services */
+
+  /* clear out any possibly preexisting garbage */
+  clear_garbage(d);
+
+  memset(sg_hd,0,sizeof(sg_hd)); 
+  sg_hd->twelve_byte = cmd_len == 12;
+  sg_hd->result = 0;
+  sg_hd->reply_len = SG_OFF + out_size;
+
+  /* The following is one of the scariest hacks I've ever had to use.
+     The idea is this: We want to know if a command fails.  The
+     generic scsi driver (as of now) won't tell us; it hands back the
+     uninitialized contents of the preallocated kernel buffer.  We
+     force this buffer to a known value via another bug (nonzero data
+     length for a command that doesn't take data) such that we can
+     tell if the command failed.  Scared yet? */
+
+  if(bytecheck && out_size>in_size){
+    memset(d->sg_buffer+cmd_len+in_size,bytefill,out_size-in_size); 
+    /* the size does not remove cmd_len due to the way the kernel
+       driver copies buffers */
+    writebytes+=(out_size-in_size);
+  }
+
+  {
+    /* Select on write with a 5 second timeout.  This is a hack until
+       a better error reporting layer is in place in alpha 10; right
+       now, always print a message. */
+
+    fd_set fdset;
+    struct timeval tv;
+
+    FD_ZERO(&fdset);
+    FD_SET(d->cdda_fd,&fdset);
+    tv.tv_sec=60; /* Increased to 1m for plextor, as the drive will
+                     try to get through rough spots on its own and
+                     this can take time 19991129 */
+    tv.tv_usec=0;
+
+    while(1){
+      int ret=select(d->cdda_fd+1,NULL,&fdset,NULL,&tv);
+      if(ret>0)break;
+      if(ret<0 && errno!=EINTR)break;
+      if(ret==0){
+	fprintf(stderr,"\nSCSI transport error: timeout waiting to write"
+		" packet\n\n");
+	return(TR_EWRITE);
+      }
+    }
+  }
+
+  sigprocmask (SIG_BLOCK, &(d->sigset), NULL );
+  errno=0;
+  status = write(d->cdda_fd, sg_hd, writebytes );
+
+  if (status<0 || status != writebytes ) {
+    sigprocmask ( SIG_UNBLOCK, &(d->sigset), NULL );
+    if(errno==0)errno=EIO;
+    return(TR_EWRITE);
+  }
+  
+  {
+    /* Select on read (and write; this signals an error) with a 5
+       second timeout.  This is a hack until a better error reporting
+       layer is in place in alpha 10; right now, always print a
+       message. */
+
+    fd_set rset;
+    struct timeval tv;
+
+    FD_ZERO(&rset);
+    FD_SET(d->cdda_fd,&rset);
+    tv.tv_sec=60; /* Increased to 1m for plextor, as the drive will
+                     try to get through rough spots on its own and
+                     this can take time 19991129 */
+    tv.tv_usec=0;
+
+    while(1){
+      int ret=select(d->cdda_fd+1,&rset,NULL,NULL,&tv);
+      if(ret<0 && errno!=EINTR)break;
+      if(ret==0){
+	sigprocmask ( SIG_UNBLOCK, &(d->sigset), NULL );
+	fprintf(stderr,"\nSCSI transport error: timeout waiting to read"
+		" packet\n\n");
+	return(TR_EREAD);
+      }
+      if(ret>0){
+	/* is it readable or something else? */
+	if(FD_ISSET(d->cdda_fd,&rset))break;
+	sigprocmask ( SIG_UNBLOCK, &(d->sigset), NULL );
+	fprintf(stderr,"\nSCSI transport: error reading packet\n\n");
+	return(TR_EREAD);
+      }
+    }
+  }
+
+  errno=0;
+  status = read(d->cdda_fd, sg_hd, SG_OFF + out_size);
+  sigprocmask ( SIG_UNBLOCK, &(d->sigset), NULL );
+
+  if (status<0)return(TR_EREAD);
+
+  if(status != SG_OFF + out_size || sg_hd->result){
+    if(errno==0)errno=EIO;
+    return(TR_EREAD);
+  }
+
+  if(sg_hd->sense_buffer[0]){
+    char key=sg_hd->sense_buffer[2]&0xf;
+    char ASC=sg_hd->sense_buffer[12];
+    char ASCQ=sg_hd->sense_buffer[13];
+    switch(key){
+    case 0:
+      if(errno==0)errno=EIO;
+      return(TR_UNKNOWN);
+    case 1:
+      break;
+    case 2:
+      if(errno==0)errno=EBUSY;
+      return(TR_BUSY);
+    case 3: 
+      if(ASC==0x0C && ASCQ==0x09){
+	/* loss of streaming */
+	if(errno==0)errno=EIO;
+	return(TR_STREAMING);
+      }else{
+	if(errno==0)errno=EIO;
+	return(TR_MEDIUM);
+      }
+    case 4:
+      if(errno==0)errno=EIO;
+      return(TR_FAULT);
+    case 5:
+      if(errno==0)errno=EINVAL;
+      return(TR_ILLEGAL);
+    default:
+      if(errno==0)errno=EIO;
+      return(TR_UNKNOWN);
+    }
+  }
+
+  /* still not foolproof; the following doesn't guarantee that we got
+     all the data, just that the command was not rejected. */
+
+  /* Why do this with the above sense stuff?  For some reason,
+     commands still get through.  Perhaps no data comes back even
+     though the target reports success? */
+
+  if(bytecheck && in_size+cmd_len<out_size){
+    long i,flag=0;
+    for(i=in_size;i<out_size;i++)
+      if(d->sg_buffer[i]!=bytefill){
+	flag=1;
+	break;
+      }
+    
+    if(!flag){
+      errno=EINVAL;
+      return(TR_ILLEGAL);
+    }
+  }
+
+  errno=0;
+  return(0);
+}
+
+/* Group 1 (10b) command */
+
+static int 
+mode_sense_atapi(cdrom_drive_t *d, int size, int page)
+{
+  memcpy(d->sg_buffer,  
+	 (char [])  {CDIO_MMC_GPCMD_MODE_SENSE_10,  
+		       0x00, /* reserved */
+		       0x00, /* page */
+		       0,    /* reserved */
+		       0,    /* reserved */
+		       0,    /* reserved */
+		       0,    /* reserved */
+		       0,    /* MSB (0) */
+		       0,    /* sizeof(modesense - SG_OFF) */
+		       0},   /* reserved */ 
+         10);
+
+  d->sg_buffer[1]=d->lun<<5;
+  d->sg_buffer[2]=0x3F&page;
+  d->sg_buffer[8]=size+4;
+
+  if (handle_scsi_cmd (d, 10, 0, size+4,'\377',1)) return(1);
+
+  {
+    char *b=d->sg_buffer;
+    if(b[0])return(1); /* Handles only up to 256 bytes */
+    if(b[6])return(1); /* Handles only up to 256 bytes */
+
+    b[0]=b[1]-3;
+    b[1]=b[2];
+    b[2]=b[3];
+    b[3]=b[7];
+
+    memmove(b+4,b+8,size);
+  }
+  return(0);
+}
+
+/* group 0 (6b) command */
+
+static int 
+mode_sense_scsi(cdrom_drive_t *d, int size, int page)
+{
+  memcpy(d->sg_buffer,  
+	 (char [])  {CDIO_MMC_GPCMD_MODE_SENSE, 
+		       0x00, /* return block descriptor/lun */
+		       0x00, /* page */
+		       0,    /* reserved */
+		       0,   /* sizeof(modesense - SG_OFF) */
+		       0},   /* control */ 
+         6);
+  
+  d->sg_buffer[1]=d->lun<<5;
+  d->sg_buffer[2]=(0x3F&page);
+  d->sg_buffer[4]=size;
+
+  if (handle_scsi_cmd (d, 6, 0, size, '\377',1)) return(1);
+  return(0);
+}
+
+static int mode_sense(cdrom_drive_t *d,int size,int page){
+  if(d->is_atapi)
+    return(mode_sense_atapi(d,size,page));
+  return(mode_sense_scsi(d,size,page));
+}
+
+static int mode_select(cdrom_drive_t *d,int density,int secsize){
+  /* short circut the way Heiko does it; less flexible, but shorter */
+  if(d->is_atapi){
+    unsigned char *mode = d->sg_buffer + 18;
+
+    memcpy(d->sg_buffer,
+	   (char []) { CDIO_MMC_GPCMD_MODE_SELECT,
+			 0x10, /* no save page */
+			 0, /* reserved */
+			 0, /* reserved */
+			 0, /* reserved */
+			 0, /* reserved */
+			 0, /* reserved */
+			 0, /* reserved */
+			 12, /* sizeof(mode) */
+			 0, /* reserved */
+
+			 /* mode parameter header */
+			 0, 0, 0, 0,  0, 0, 0, 
+			 8, /* Block Descriptor Length */
+
+			 /* descriptor block */
+			 0,       /* Density Code */
+			 0, 0, 0, /* # of Blocks */
+			 0,       /* reserved */
+			 0, 0, 0},/* Blocklen */
+	   26);
+
+    d->sg_buffer[1]|=d->lun<<5;
+
+    /* prepare to read cds in the previous mode */
+    mode [0] = density;
+    mode [6] =  secsize >> 8;   /* block length "msb" */
+    mode [7] =  secsize & 0xFF; /* block length lsb */
+
+    /* do the scsi cmd */
+    return(handle_scsi_cmd (d,10, 16, 0,0,0));
+
+  }else{
+    unsigned char *mode = d->sg_buffer + 10;
+
+    memcpy(d->sg_buffer,
+	   (char []) { CDIO_MMC_GPCMD_MODE_SELECT, 
+			 0x10, /* no save page */
+			 0, /* reserved */
+			 0, /* reserved */
+			 12, /* sizeof(mode) */
+			 0, /* reserved */
+			 /* mode section */
+			 0, 
+			 0, 0, 
+			 8,       /* Block Descriptor Length */
+			 0,       /* Density Code */
+			 0, 0, 0, /* # of Blocks */
+			 0,       /* reserved */
+			 0, 0, 0},/* Blocklen */
+	   18);
+
+    /* prepare to read cds in the previous mode */
+    mode [0] = density;
+    mode [6] =  secsize >> 8;   /* block length "msb" */
+    mode [7] =  secsize & 0xFF; /* block length lsb */
+
+    /* do the scsi cmd */
+    return(handle_scsi_cmd (d,6, 12, 0,0,0));
+  }
+}
+
+/* get current sector size from SCSI cdrom drive */
+static unsigned int 
+get_orig_sectorsize(cdrom_drive_t *d)
+{
+  if(mode_sense(d,12,0x01))return(-1);
+
+  d->orgdens = d->sg_buffer[4];
+  return(d->orgsize = ((int)(d->sg_buffer[10])<<8)+d->sg_buffer[11]);
+}
+
+/* switch CDROM scsi drives to given sector size  */
+static int set_sectorsize (cdrom_drive_t *d,unsigned int secsize)
+{
+  return(mode_select(d,d->orgdens,secsize));
+}
+
+/* switch Toshiba/DEC and HP drives from/to cdda density */
+int 
+scsi_enable_cdda (cdrom_drive_t *d, int fAudioMode)
+{
+  if (fAudioMode) {
+    if(mode_select(d,d->density,CDIO_CD_FRAMESIZE_RAW)){
+      if(d->error_retry)
+	cderror(d,"001: Unable to set CDROM to read audio mode\n");
+      return(-1);
+    }
+  } else {
+    if(mode_select(d,d->orgdens,d->orgsize)){
+      if(d->error_retry)
+	cderror(d,"001: Unable to set CDROM to read audio mode\n");
+      return(-1);
+    }
+  }
+  return(0);
+}
+
+typedef struct scsi_TOC {  /* structure of scsi table of contents (cdrom) */
+  unsigned char reserved1;
+  unsigned char bFlags;
+  unsigned char bTrack;
+  unsigned char reserved2;
+  signed char start_MSB;
+  unsigned char start_1;
+  unsigned char start_2;
+  unsigned char start_LSB;
+} scsi_TOC;
+
+
+/* read the table of contents from the cd and fill the TOC array */
+/* Do it like the kernel ioctl driver; the 'all at once' approach
+   fails on at least one Kodak drive. */
+
+static int 
+scsi_read_toc (cdrom_drive_t *d)
+{
+  int i,first,last;
+  track_t i_tracks;
+
+  /* READTOC, MSF format flag, res, res, res, res, Start track, len msb,
+     len lsb, flags */
+
+  /* read the header first */
+  memcpy(d->sg_buffer, (char []){ CDIO_MMC_GPCMD_READ_TOC, 
+	                          0, 0, 0, 0, 0, 1, 0, 12, 0}, 10);
+  d->sg_buffer[1]=d->lun<<5;
+
+  if (handle_scsi_cmd (d,10, 0, 12,'\377',1)){
+    cderror(d,"004: Unable to read table of contents header\n");
+    return(-4);
+  }
+
+  first=d->sg_buffer[2];
+  last=d->sg_buffer[3];
+  i_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);
+  }
+
+  for (i = first; i <= last; i++){
+    memcpy(d->sg_buffer, (char []){ CDIO_MMC_GPCMD_READ_TOC, 
+	                            0, 0, 0, 0, 0, 0, 0, 12, 0}, 10);
+    d->sg_buffer[1]=d->lun<<5;
+    d->sg_buffer[6]=i;
+    
+    if (handle_scsi_cmd (d,10, 0, 12,'\377',1)){
+      cderror(d,"005: Unable to read table of contents entry\n");
+      return(-5);
+    }
+    {
+      scsi_TOC *toc=(scsi_TOC *)(d->sg_buffer+4);
+
+      d->disc_toc[i-first].bFlags=toc->bFlags;
+      d->disc_toc[i-first].bTrack=i;
+      d->disc_toc[i-first].dwStartSector= d->adjust_ssize * 
+	(((int)(toc->start_MSB)<<24) | 
+	 (toc->start_1<<16)|
+	 (toc->start_2<<8)|
+	 (toc->start_LSB));
+    }
+  }
+
+  memcpy(d->sg_buffer, (char []){ CDIO_MMC_GPCMD_READ_TOC, 
+	                          0, 0, 0, 0, 0, 0, 0, 12, 0}, 10);
+  d->sg_buffer[1]=d->lun<<5;
+  d->sg_buffer[6]=0xAA;
+    
+  if (handle_scsi_cmd (d,10, 0, 12,'\377',1)){
+    cderror(d,"002: Unable to read table of contents lead-out\n");
+    return(-2);
+  }
+  {
+    scsi_TOC *toc=(scsi_TOC *)(d->sg_buffer+4);
+    
+    d->disc_toc[i-first].bFlags=toc->bFlags;
+    d->disc_toc[i-first].bTrack=0xAA;
+    d->disc_toc[i-first].dwStartSector= d->adjust_ssize * 
+	(((int)(toc->start_MSB)<<24) | 
+	 (toc->start_1<<16)|
+	 (toc->start_2<<8)|
+	 (toc->start_LSB));
+  }
+
+  d->cd_extra = FixupTOC(d,i_tracks+1); /* include lead-out */
+  return(i_tracks);
+}
+
+/* a contribution from Boris for IMS cdd 522 */
+/* check this for ACER/Creative/Foo 525,620E,622E, etc? */
+static int 
+scsi_read_toc2 (cdrom_drive_t *d)
+{
+  uint32_t foo,bar;
+
+  int i;
+  track_t i_tracks;
+
+  memcpy(d->sg_buffer, (char[]){ 0xe5, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 10);
+  d->sg_buffer[5]=1;
+  d->sg_buffer[8]=255;
+
+  if (handle_scsi_cmd (d,10, 0, 256,'\377',1)){
+    cderror(d,"004: Unable to read table of contents header\n");
+    return(-4);
+  }
+
+  /* copy to our structure and convert start sector */
+  i_tracks = d->sg_buffer[1];
+  if (i_tracks > MAXTRK) {
+    cderror(d,"003: CDROM reporting illegal number of tracks\n");
+    return(-3);
+  }
+
+  for (i = 0; i < i_tracks; i++){
+    memcpy(d->sg_buffer, (char[]){ 0xe5, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 10);
+    d->sg_buffer[5]=i+1;
+    d->sg_buffer[8]=255;
+    
+    if (handle_scsi_cmd (d,10, 0, 256,'\377',1)){
+      cderror(d,"005: Unable to read table of contents entry\n");
+      return(-5);
+    }
+    
+    d->disc_toc[i].bFlags = d->sg_buffer[10];
+    d->disc_toc[i].bTrack = i + 1;
+
+    d->disc_toc[i].dwStartSector= d->adjust_ssize * 
+	(((signed char)(d->sg_buffer[2])<<24) | 
+	 (d->sg_buffer[3]<<16)|
+	 (d->sg_buffer[4]<<8)|
+	 (d->sg_buffer[5]));
+  }
+
+  d->disc_toc[i].bFlags = 0;
+  d->disc_toc[i].bTrack = i + 1;
+  memcpy (&foo, d->sg_buffer+2, 4);
+  memcpy (&bar, d->sg_buffer+6, 4);
+  d->disc_toc[i].dwStartSector = 
+    d->adjust_ssize * (UINT32_FROM_BE(foo) + UINT32_FROM_BE(bar));
+
+  d->disc_toc[i].dwStartSector= d->adjust_ssize * 
+    ((((signed char)(d->sg_buffer[2])<<24) | 
+      (d->sg_buffer[3]<<16)|
+      (d->sg_buffer[4]<<8)|
+      (d->sg_buffer[5]))+
+     
+     ((((signed char)(d->sg_buffer[6])<<24) | 
+       (d->sg_buffer[7]<<16)|
+       (d->sg_buffer[8]<<8)|
+       (d->sg_buffer[9]))));
+
+
+  d->cd_extra = FixupTOC(d,i_tracks+1);
+  return(i_tracks);
+}
+
+/* These do one 'extra' copy in the name of clean code */
+
+static int 
+i_read_28 (cdrom_drive_t *d, void *p, long int begin, long int sectors)
+{
+  int ret;
+  memcpy(d->sg_buffer,(char []){
+	   CDIO_MMC_GPCMD_READ_10, 
+	     0, 0, 0, 0, 0, 0, 0, 0, 0},
+	 10);
+
+  if(d->fua)
+    d->sg_buffer[1]=0x08;
+
+  d->sg_buffer[1]|=d->lun<<5;
+
+  d->sg_buffer[3] = (begin >> 16) & 0xFF;
+  d->sg_buffer[4] = (begin >> 8) & 0xFF;
+  d->sg_buffer[5] = begin & 0xFF;
+  d->sg_buffer[8] = sectors;
+  if((ret=handle_scsi_cmd(d,10,0,sectors * CDIO_CD_FRAMESIZE_RAW,'\177',1)))
+    return(ret);
+  if(p)memcpy(p,d->sg_buffer,sectors*CDIO_CD_FRAMESIZE_RAW);
+  return(0);
+}
+
+static int 
+i_read_A8 (cdrom_drive_t *d, void *p, long int begin, long int sectors)
+{
+  int ret;
+  memcpy(d->sg_buffer,(char []){
+	   CDIO_MMC_GPCMD_READ_12, 
+	     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	 12);
+
+  if(d->fua)
+    d->sg_buffer[1]=0x08;
+
+  d->sg_buffer[1]|=d->lun<<5;
+
+  d->sg_buffer[3] = (begin >> 16) & 0xFF;
+  d->sg_buffer[4] = (begin >> 8) & 0xFF;
+  d->sg_buffer[5] = begin & 0xFF;
+  d->sg_buffer[9] = sectors;
+  if((ret=handle_scsi_cmd(d,12,0,sectors * CDIO_CD_FRAMESIZE_RAW,'\177',1)))
+    return(ret);
+  if(p)memcpy(p,d->sg_buffer,sectors*CDIO_CD_FRAMESIZE_RAW);
+  return(0);
+}
+
+static int 
+i_read_D4_10 (cdrom_drive_t *d, void *p, long begin, long sectors)
+{
+  int ret;
+  memcpy(d->sg_buffer,(char []){0xd4, 0, 0, 0, 0, 0, 0, 0, 0, 0},10);
+
+  if(d->fua)
+    d->sg_buffer[1]=0x08;
+
+  d->sg_buffer[1]|=d->lun<<5;
+  d->sg_buffer[3] = (begin >> 16) & 0xFF;
+  d->sg_buffer[4] = (begin >> 8) & 0xFF;
+  d->sg_buffer[5] = begin & 0xFF;
+  d->sg_buffer[8] = sectors;
+  if((ret=handle_scsi_cmd(d,10,0,sectors * CDIO_CD_FRAMESIZE_RAW,'\177',1)))
+    return(ret);
+  if(p)memcpy(p,d->sg_buffer,sectors*CDIO_CD_FRAMESIZE_RAW);
+  return(0);
+}
+
+static int i_read_D4_12 (cdrom_drive_t *d, void *p, long begin, long sectors)
+{
+  int ret;
+  memcpy(d->sg_buffer,(char []){0xd4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},12);
+
+  if(d->fua)
+    d->sg_buffer[1]=0x08;
+
+  d->sg_buffer[1]|=d->lun<<5;
+  d->sg_buffer[3] = (begin >> 16) & 0xFF;
+  d->sg_buffer[4] = (begin >> 8) & 0xFF;
+  d->sg_buffer[5] = begin & 0xFF;
+  d->sg_buffer[9] = sectors;
+  if((ret=handle_scsi_cmd(d,12,0,sectors * CDIO_CD_FRAMESIZE_RAW,'\177',1)))
+    return(ret);
+  if(p)memcpy(p,d->sg_buffer,sectors*CDIO_CD_FRAMESIZE_RAW);
+  return(0);
+}
+
+static int 
+i_read_D5 (cdrom_drive_t *d, void *p, long int begin, long int sectors)
+{
+  int ret;
+  memcpy(d->sg_buffer,(char []){0xd5, 0, 0, 0, 0, 0, 0, 0, 0, 0},10);
+
+  if(d->fua)
+    d->sg_buffer[1]=0x08;
+
+  d->sg_buffer[1]|=d->lun<<5;
+  d->sg_buffer[3] = (begin >> 16) & 0xFF;
+  d->sg_buffer[4] = (begin >> 8) & 0xFF;
+  d->sg_buffer[5] = begin & 0xFF;
+  d->sg_buffer[8] = sectors;
+  if((ret=handle_scsi_cmd(d,10,0,sectors * CDIO_CD_FRAMESIZE_RAW,'\177',1)))
+    return(ret);
+  if(p)memcpy(p,d->sg_buffer,sectors*CDIO_CD_FRAMESIZE_RAW);
+  return(0);
+}
+
+static int 
+i_read_D8 (cdrom_drive_t *d, void *p, long int begin, long int sectors)
+{
+  int ret;
+  memcpy(d->sg_buffer,(char []){0xd8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},12);
+
+  if(d->fua)
+    d->sg_buffer[1]=0x08;
+
+  d->sg_buffer[1]|=d->lun<<5;
+  d->sg_buffer[3] = (begin >> 16) & 0xFF;
+  d->sg_buffer[4] = (begin >> 8) & 0xFF;
+  d->sg_buffer[5] = begin & 0xFF;
+  d->sg_buffer[9] = sectors;
+  if((ret=handle_scsi_cmd(d,12,0,sectors * CDIO_CD_FRAMESIZE_RAW,'\177',1)))
+    return(ret);
+  if(p)memcpy(p,d->sg_buffer,sectors*CDIO_CD_FRAMESIZE_RAW);
+  return(0);
+}
+
+static int 
+i_read_mmc (cdrom_drive_t *d, void *p, long int begin, long int sectors)
+{
+  int ret;
+  /*  if(begin<=12007 && begin+sectors>12000){
+    errno=EIO;
+    return(TR_ILLEGAL);
+  }*/
+
+  memcpy(d->sg_buffer,(char []){
+	   CDIO_MMC_GPCMD_READ_CD, 
+	   0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0},12);
+
+  d->sg_buffer[3] = (begin >> 16) & 0xFF;
+  d->sg_buffer[4] = (begin >> 8) & 0xFF;
+  d->sg_buffer[5] = begin & 0xFF;
+  d->sg_buffer[8] = sectors;
+  if((ret=handle_scsi_cmd(d,12,0,sectors * CDIO_CD_FRAMESIZE_RAW,'\177',1)))
+    return(ret);
+  if(p)memcpy(p,d->sg_buffer,sectors*CDIO_CD_FRAMESIZE_RAW);
+  return(0);
+}
+
+static int 
+i_read_mmc2 (cdrom_drive_t *d, void *p, long int begin, long int sectors)
+{
+  int ret;
+  memcpy(d->sg_buffer,(char []){
+	   CDIO_MMC_GPCMD_READ_CD, 
+	     0, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0},12);
+
+  d->sg_buffer[3] = (begin >> 16) & 0xFF;
+  d->sg_buffer[4] = (begin >> 8) & 0xFF;
+  d->sg_buffer[5] = begin & 0xFF;
+  d->sg_buffer[8] = sectors;
+  if((ret=handle_scsi_cmd(d,12,0,sectors * CDIO_CD_FRAMESIZE_RAW,'\177',1)))
+    return(ret);
+  if(p)memcpy(p,d->sg_buffer,sectors*CDIO_CD_FRAMESIZE_RAW);
+  return(0);
+}
+
+static int 
+i_read_mmc3 (cdrom_drive_t *d, void *p, long int begin, long int sectors)
+{
+  int ret;
+  memcpy(d->sg_buffer,(char []){
+	   CDIO_MMC_GPCMD_READ_CD, 
+	     4, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0},12);
+
+  d->sg_buffer[3] = (begin >> 16) & 0xFF;
+  d->sg_buffer[4] = (begin >> 8) & 0xFF;
+  d->sg_buffer[5] = begin & 0xFF;
+  d->sg_buffer[8] = sectors;
+  if((ret=handle_scsi_cmd(d,12,0,sectors * CDIO_CD_FRAMESIZE_RAW,'\177',1)))
+    return(ret);
+  if(p)memcpy(p,d->sg_buffer,sectors*CDIO_CD_FRAMESIZE_RAW);
+  return(0);
+}
+
+/* straight from the MMC3 spec */
+static inline void 
+LBA_to_MSF(lba_t lba, unsigned char *M, unsigned char *S, unsigned char *F)
+{
+  if (lba>=-CDIO_PREGAP_SECTORS){
+    *M   = ( lba+CDIO_PREGAP_SECTORS)/(CDIO_CD_FRAMES_PER_MIN);
+    lba -= (*M)*(CDIO_CD_FRAMES_PER_MIN);
+    *S   = (lba+CDIO_PREGAP_SECTORS)/CDIO_CD_FRAMES_PER_SEC;
+    lba -= (*S)*CDIO_CD_FRAMES_PER_SEC;
+    *F   = (lba+CDIO_PREGAP_SECTORS);
+  } else {
+    *M   = (lba+450150)/(CDIO_CD_FRAMES_PER_MIN);
+    lba -= (*M)*(CDIO_CD_FRAMES_PER_MIN);
+    *S   = (lba+450150)/CDIO_CD_FRAMES_PER_SEC;
+    lba -= (*S)*CDIO_CD_FRAMES_PER_SEC;
+    *F   = (lba+450150);
+  }
+}
+
+
+static int 
+i_read_msf (cdrom_drive_t *d, void *p, long int begin, long int sectors)
+{
+  int ret;
+  memcpy(d->sg_buffer,(char []){
+	   CDIO_MMC_GPCMD_READ_MSF, 
+	     0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0},12);
+
+  LBA_to_MSF(begin,d->sg_buffer+3,d->sg_buffer+4,d->sg_buffer+5);
+  LBA_to_MSF(begin+sectors,d->sg_buffer+6,d->sg_buffer+7,d->sg_buffer+8);
+
+  if((ret=handle_scsi_cmd(d,12,0,sectors * CDIO_CD_FRAMESIZE_RAW,'\177',1)))
+    return(ret);
+  if(p)memcpy(p,d->sg_buffer,sectors*CDIO_CD_FRAMESIZE_RAW);
+  return(0);
+}
+
+static int 
+i_read_msf2 (cdrom_drive_t *d, void *p, long int begin, long int sectors)
+{
+  int ret;
+  memcpy(d->sg_buffer,(char []){
+	   CDIO_MMC_GPCMD_READ_MSF, 
+	     0, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0},12);
+
+  LBA_to_MSF(begin,d->sg_buffer+3,d->sg_buffer+4,d->sg_buffer+5);
+  LBA_to_MSF(begin+sectors,d->sg_buffer+6,d->sg_buffer+7,d->sg_buffer+8);
+
+  if((ret=handle_scsi_cmd(d,12,0,sectors * CDIO_CD_FRAMESIZE_RAW,'\177',1)))
+    return(ret);
+  if(p)memcpy(p,d->sg_buffer,sectors*CDIO_CD_FRAMESIZE_RAW);
+  return(0);
+}
+
+static int 
+i_read_msf3 (cdrom_drive_t *d, void *p, long int begin, long int sectors)
+{
+  int ret;
+  memcpy(d->sg_buffer,(char []){
+	   CDIO_MMC_GPCMD_READ_MSF, 
+	     4, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0},12);
+
+  LBA_to_MSF(begin,d->sg_buffer+3,d->sg_buffer+4,d->sg_buffer+5);
+  LBA_to_MSF(begin+sectors,d->sg_buffer+6,d->sg_buffer+7,d->sg_buffer+8);
+
+  if((ret=handle_scsi_cmd(d,12,0,sectors * CDIO_CD_FRAMESIZE_RAW,'\177',1)))
+    return(ret);
+  if(p)memcpy(p,d->sg_buffer,sectors*CDIO_CD_FRAMESIZE_RAW);
+  return(0);
+}
+
+static long 
+scsi_read_map (cdrom_drive_t *d, void *p, long int begin, long int sectors,
+	       int (*map)(cdrom_drive_t *, void *, long, long))
+{
+  int retry_count,err;
+  char *buffer=(char *)p;
+
+  /* read d->nsectors at a time, max. */
+  sectors=(sectors>d->nsectors?d->nsectors:sectors);
+  sectors=(sectors<1?1:sectors);
+
+  retry_count=0;
+  
+  while(1) {
+    if((err=map(d,(p?buffer:NULL),begin,sectors))){
+      if(d->report_all){
+	struct sg_header *sg_hd=(struct sg_header *)d->sg;
+	char b[256];
+
+	sprintf(b,"scsi_read error: sector=%ld length=%ld retry=%d\n",
+		begin,sectors,retry_count);
+	cdmessage(d,b);
+	sprintf(b,"                 Sense key: %x ASC: %x ASCQ: %x\n",
+		(int)(sg_hd->sense_buffer[2]&0xf),
+		(int)(sg_hd->sense_buffer[12]),
+		(int)(sg_hd->sense_buffer[13]));
+	cdmessage(d,b);
+	sprintf(b,"                 Transport error: %s\n",strerror_tr[err]);
+	cdmessage(d,b);
+	sprintf(b,"                 System error: %s\n",strerror(errno));
+	cdmessage(d,b);
+
+	fprintf(stderr,"scsi_read error: sector=%ld length=%ld retry=%d\n",
+		begin,sectors,retry_count);
+	fprintf(stderr,"                 Sense key: %x ASC: %x ASCQ: %x\n",
+		(int)(sg_hd->sense_buffer[2]&0xf),
+		(int)(sg_hd->sense_buffer[12]),
+		(int)(sg_hd->sense_buffer[13]));
+	fprintf(stderr,"                 Transport error: %s\n",strerror_tr[err]);
+	fprintf(stderr,"                 System error: %s\n",strerror(errno));
+      }
+
+      if(!d->error_retry)return(-7);
+      switch(errno){
+      case EINTR:
+	usleep(100);
+	continue;
+      case ENOMEM:
+	/* D'oh.  Possible kernel error. Keep limping */
+	usleep(100);
+	if(sectors==1){
+	  /* Nope, can't continue */
+	  cderror(d,"300: Kernel memory error\n");
+	  return(-300);  
+	}
+	if(d->report_all){
+	  char b[256];
+	  sprintf(b,"scsi_read: kernel couldn't alloc %ld bytes.  "
+		  "backing off...\n",sectors*CDIO_CD_FRAMESIZE_RAW);
+	    
+	  cdmessage(d,b);
+	}
+	sectors--;
+	continue;
+      default:
+	if(sectors==1){
+	  if(errno==EIO)
+	    if(d->fua==-1) /* testing for FUA support */
+	      return(-7);
+	  
+	  /* *Could* be I/O or media error.  I think.  If we're at
+	     30 retries, we better skip this unhappy little
+	     sector. */
+	  if(retry_count>MAX_RETRIES-1){
+	    char b[256];
+	    sprintf(b,"010: Unable to access sector %ld\n",
+		    begin);
+	    cderror(d,b);
+	    return(-10);
+	    
+	  }
+	  break;
+	}
+
+	/* Hmm.  OK, this is just a tad silly.  just in case this was
+           a timeout and a reset happened, we need to set the drive
+           back to cdda */
+	reset_scsi(d);
+      }
+    }else{
+
+      /* Did we get all the bytes we think we did, or did the kernel
+         suck? */
+      if(buffer){
+	long i;
+	for(i=sectors*CDIO_CD_FRAMESIZE_RAW;i>1;i-=2)
+	  if(buffer[i-1]!='\177' || buffer[i-2]!='\177')
+	    break;
+
+	i/=CDIO_CD_FRAMESIZE_RAW;
+	if(i!=sectors){
+	  if(d->report_all){
+	    char b[256];
+	    sprintf(b,"scsi_read underrun: pos=%ld len=%ld read=%ld retry=%d\n",
+		    begin,sectors,i,retry_count);
+	    
+	    cdmessage(d,b);
+	  }
+	  reset_scsi(d);
+	}
+	
+	if(i>0)return(i);
+      }else
+	break;
+    }
+    
+    retry_count++;
+    if(sectors==1 && retry_count>MAX_RETRIES){
+      cderror(d,"007: Unknown, unrecoverable error reading data\n");
+      return(-7);
+    }
+    if(sectors>1)sectors=sectors/2;
+    d->enable_cdda(d,0);
+    d->enable_cdda(d,1);
+
+  }
+  return(sectors);
+}
+
+long int 
+scsi_read_28 (cdrom_drive_t *d, void *p, long int begin, long int sectors)
+{
+  return(scsi_read_map(d,p,begin,sectors,i_read_28));
+}
+
+long int 
+scsi_read_A8 (cdrom_drive_t *d, void *p, long int begin, long int sectors)
+{
+  return(scsi_read_map(d,p,begin,sectors,i_read_A8));
+}
+
+long int 
+scsi_read_D4_10 (cdrom_drive_t *d, void *p, long int begin, long int sectors)
+{
+  return(scsi_read_map(d,p,begin,sectors,i_read_D4_10));
+}
+
+long int 
+scsi_read_D4_12 (cdrom_drive_t *d, void *p, long int begin, 
+			  long int sectors)
+{
+  return(scsi_read_map(d,p,begin,sectors,i_read_D4_12));
+}
+
+static long int 
+scsi_read_D5 (cdrom_drive_t *d, void *p, long begin, long sectors)
+{
+  return(scsi_read_map(d,p,begin,sectors,i_read_D5));
+}
+
+long scsi_read_D8 (cdrom_drive_t *d, void *p, long begin, 
+			       long sectors)
+{
+  return(scsi_read_map(d,p,begin,sectors,i_read_D8));
+}
+
+long scsi_read_mmc (cdrom_drive_t *d, void *p, long begin, 
+			       long sectors)
+{
+  return(scsi_read_map(d,p,begin,sectors,i_read_mmc));
+}
+
+long scsi_read_mmc2 (cdrom_drive_t *d, void *p, long begin, 
+			       long sectors)
+{
+  return(scsi_read_map(d,p,begin,sectors,i_read_mmc2));
+}
+
+static long 
+scsi_read_mmc3 (cdrom_drive_t *d, void *p, long begin, long sectors)
+{
+  return(scsi_read_map(d,p,begin,sectors,i_read_mmc3));
+}
+
+static long 
+scsi_read_msf (cdrom_drive_t *d, void *p, long begin, long sectors)
+{
+  return(scsi_read_map(d,p,begin,sectors,i_read_msf));
+}
+
+static long 
+scsi_read_msf2 (cdrom_drive_t *d, void *p, long begin, long sectors)
+{
+  return(scsi_read_map(d,p,begin,sectors,i_read_msf2));
+}
+
+static long 
+scsi_read_msf3 (cdrom_drive_t *d, void *p, long begin, long sectors)
+{
+  return(scsi_read_map(d,p,begin,sectors,i_read_msf3));
+}
+
+
+/* Some drives, given an audio read command, return only 2048 bytes
+   of data as opposed to 2352 bytes.  Look for bytess at the end of the
+   single sector verification read */
+
+static int 
+count_2352_bytes(cdrom_drive_t *d)
+{
+  long int i;
+  for (i=CDIO_CD_FRAMESIZE_RAW-1; i>=0; i--)
+    if(d->sg_buffer[i]!=(unsigned char)'\177')
+      return(((i+3)>>2)<<2);
+
+  return(0);
+}
+
+static int 
+verify_nonzero(cdrom_drive_t *d)
+{
+  long i,flag=0;
+  for (i=0; i<CDIO_CD_FRAMESIZE_RAW ;i++)
+    if(d->sg_buffer[i]!=0){
+      flag=1;
+      break;
+    }
+  
+  return(flag);
+}
+
+/* So many different read commands, densities, features...
+   Verify that our selected 'read' command actually reads 
+   nonzero data, else search through other possibilities */
+
+static int 
+verify_read_command(cdrom_drive_t *d)
+{
+  int i,j,k;
+  int audioflag=0;
+
+  int  (*enablecommand)  (cdrom_drive_t *d, int speed);
+  long (*readcommand)   (cdrom_drive_t *d, void *p, long begin, 
+		       long int sectors);
+  unsigned char density;
+  
+  int16_t *buff=malloc(CDIO_CD_FRAMESIZE_RAW);
+
+  cdmessage(d,"Verifying CDDA command set...\n");
+
+  /* try the expected command set; grab the center of each track, look
+     for data */
+
+  if(d->enable_cdda(d,1)==0){
+    
+    for(i=1;i<=d->tracks;i++){
+      if(cdda_track_audiop(d,i)==1){
+	long firstsector=cdda_track_firstsector(d,i);
+	long lastsector=cdda_track_lastsector(d,i);
+	long sector=(firstsector+lastsector)>>1;
+	audioflag=1;
+
+	if(d->read_audio(d,buff,sector,1)>0){
+	  if(count_2352_bytes(d)==CDIO_CD_FRAMESIZE_RAW){
+	    cdmessage(d,"\tExpected command set reads OK.\n");
+	    d->enable_cdda(d,0);
+	    free(buff);
+	    return(0);
+	  }
+	}
+      }
+    }
+    
+    d->enable_cdda(d,0);
+  }
+
+  if(!audioflag){
+    cdmessage(d,"\tCould not find any audio tracks on this disk.\n");
+    return(-403);
+  }
+
+
+  {
+    const char *es="",*rs="";
+    d->bigendianp=-1;
+    density=d->density;
+    readcommand=d->read_audio;
+    enablecommand=d->enable_cdda;
+
+
+    /* No nonzeroes?  D'oh.  Exhaustive search */
+    cdmessage(d,"\tExpected command set FAILED!\n"
+	      "\tPerforming full probe for CDDA command set...\n");
+    
+    /* loops:  
+       density/enable no,  0x0/org,  0x04/org, 0x82/org
+       read command read_10 read_12 read_nec read_sony read_mmc read_mmc2 */
+
+    /* NEC test must come before sony; the nec drive expects d8 to be
+       10 bytes, and a 12 byte verson (Sony) crashes the drive */
+
+    for(j=0;j>=0;j++){
+      int densitypossible=1;
+
+      switch(j){
+      case 0:
+	d->read_audio=scsi_read_28;
+	rs="28 0x,00";
+	break;
+      case 1:
+	d->read_audio=scsi_read_A8;
+	rs="a8 0x,00";
+	break;
+      case 2:
+	d->read_audio=scsi_read_mmc;
+	rs="be 00,10";
+	densitypossible=0;
+	break;
+      case 3:
+	d->read_audio=scsi_read_mmc2;
+	rs="be 00,f8";
+	densitypossible=0;
+	break;
+      case 4:
+	d->read_audio=scsi_read_mmc3;
+	rs="be 04,f8";
+	densitypossible=0;
+	break;
+
+      case 5:
+	d->read_audio=scsi_read_msf;
+	rs="b9 00,10";
+	densitypossible=0;
+	break;
+      case 6:
+	d->read_audio=scsi_read_msf2;
+	rs="b9 00,f8";
+	densitypossible=0;
+	break;
+      case 7:
+	d->read_audio=scsi_read_msf3;
+	rs="b9 04,f8";
+	densitypossible=0;
+	break;
+
+      case 8:
+	d->read_audio=scsi_read_D4_10;
+	rs="d4(10)0x";
+	break;
+      case 9:
+	d->read_audio=scsi_read_D4_12;
+	rs="d4(12)0x";
+	break;
+      case 10:
+	d->read_audio=scsi_read_D5;
+	rs="d5 0x,00";
+	break;
+      case 11:
+	d->read_audio=scsi_read_D8;
+	rs="d8 0x,00";
+	j=-2;
+	break;
+      }
+      
+      for(i=0;i>=0;i++){
+	switch(i){
+	case 0:
+	  d->density=0;
+	  d->enable_cdda=dummy_exception;
+	  es="none    ";
+	  if(!densitypossible)i=-2; /* short circuit MMC style commands */
+	  break;
+	case 1:
+	  d->density=0;
+	  d->enable_cdda=scsi_enable_cdda;
+	  es="yes/0x00";
+	  break;
+	case 2:
+	  d->density=0x04;
+	  d->enable_cdda=scsi_enable_cdda;
+	  es="yes/0x04";
+	  break;
+	case 3:
+	  d->density=0x82;
+	  d->enable_cdda=scsi_enable_cdda;
+	  es="yes/0x82";
+	case 4:
+	  d->density=0x81;
+	  d->enable_cdda=scsi_enable_cdda;
+	  es="yes/0x81";
+	  i=-2;
+	  break;
+	}
+
+	cdmessage(d,"\ttest -> density: [");
+	cdmessage(d,es);
+	cdmessage(d,"]  command: [");
+	cdmessage(d,rs);
+	cdmessage(d,"]\n");
+
+	{
+	  int densityflag=0;
+	  int rejectflag=0;
+	  int zeroflag=0;
+	  int lengthflag=0;
+
+	  if(d->enable_cdda(d,1)==0){
+	    for(k=1;k<=d->tracks;k++){
+	      if(cdda_track_audiop(d,k)==1){
+		long firstsector=cdda_track_firstsector(d,k);
+		long lastsector=cdda_track_lastsector(d,k);
+		long sector=(firstsector+lastsector)>>1;
+		
+		if(d->read_audio(d,buff,sector,1)>0){
+		  if((lengthflag=count_2352_bytes(d))==CDIO_CD_FRAMESIZE_RAW){
+		    if(verify_nonzero(d)){
+		      cdmessage(d,"\t\tCommand set FOUND!\n");
+		      
+		      free(buff);
+		      d->enable_cdda(d,0);
+		      return(0);
+		    }else{
+		      zeroflag++;
+		    }
+		  }
+		}else{
+		  rejectflag++;
+		  break;
+		}
+	      }
+	    }
+	    d->enable_cdda(d,0);
+	  }else{
+	    densityflag++;
+	  }
+	  
+	  if(densityflag)
+	    cdmessage(d,"\t\tDrive rejected density set\n");
+	  if(rejectflag){
+	    char buffer[256];
+	    sprintf(buffer,"\t\tDrive rejected read command packet(s)\n");
+	    cdmessage(d,buffer);
+	  }
+	  if(lengthflag>0 && lengthflag<CDIO_CD_FRAMESIZE_RAW){
+	    char buffer[256];
+	    sprintf(buffer,"\t\tDrive returned at least one packet, but with\n"
+		        "\t\tincorrect size (%d)\n",lengthflag);
+	    cdmessage(d,buffer);
+	  }
+	  if(zeroflag){
+	    char buffer[256];
+	    sprintf(buffer,"\t\tDrive returned %d packet(s), but contents\n"
+		        "\t\twere entirely zero\n",zeroflag);
+	    cdmessage(d,buffer);
+	  }
+	}
+      }
+    }
+
+    /* D'oh. */
+    d->density=density;
+    d->read_audio=readcommand;
+    d->enable_cdda=enablecommand;
+
+    cdmessage(d,"\tUnable to find any suitable command set from probe;\n"
+	      "\tdrive probably not CDDA capable.\n");
+
+    cderror(d,"006: Could not read any data from drive\n");
+
+  }
+  free(buff);
+  return(-6);
+}
+
+static void 
+check_fua_bit(cdrom_drive_t *d){
+  long i;
+
+  if(d->read_audio==scsi_read_mmc)return;
+  if(d->read_audio==scsi_read_mmc2)return;
+  if(d->read_audio==scsi_read_mmc3)return;
+
+  cdmessage(d,"This command set may use a Force Unit Access bit.");
+  cdmessage(d,"\nChecking drive for FUA bit support...\n");
+  
+  d->enable_cdda(d,1);
+  d->fua=1;
+
+  {
+    int16_t *buff=malloc(CDIO_CD_FRAMESIZE_RAW);
+    for(i=1;i<=d->tracks;i++){
+      if(cdda_track_audiop(d,i)==1){
+        long firstsector=cdda_track_firstsector(d,i);
+        long lastsector=cdda_track_lastsector(d,i);
+        long sector=(firstsector+lastsector)>>1;
+      
+        if(d->read_audio(d,buff,sector,1)>0){
+	  cdmessage(d,"\tDrive accepted FUA bit.\n");
+	  d->enable_cdda(d,0);
+	  free(buff);
+	  return;
+        }
+      }
+    }
+  
+    d->fua=0;
+    cdmessage(d,"\tDrive rejected FUA bit.\n");
+    free(buff);
+    return;
+  }
+}
+
+static int 
+check_atapi(cdrom_drive_t *d){
+  int atapiret=-1;
+  int fd = d->cdda_fd; /* this is the correct fd (not ioctl_fd), as the 
+			  generic device is the device we need to check */
+			  
+  cdmessage(d,"\nChecking for SCSI emulation...\n");
+
+  if (ioctl(fd,SG_EMULATED_HOST,&atapiret)){
+    cderror(d,"\tSG_EMULATED_HOST ioctl() failed!\n");
+    return(-1);
+  } else {
+    if(atapiret==1){
+      cdmessage(d,"\tDrive is ATAPI (using SCSI host adaptor emulation)\n");
+      /* Disable kernel SCSI command translation layer for access through sg */
+      if (ioctl(fd,SG_SET_TRANSFORM,0))
+	cderror(d,"\tCouldn't disable kernel command translation layer\n");
+      d->is_atapi=1;
+    }else{
+      cdmessage(d,"\tDrive is SCSI\n");
+      d->is_atapi=0;
+    }
+
+    return(d->is_atapi);
+  }
+}  
+
+static int check_mmc(cdrom_drive_t *d){
+  char *b;
+  cdmessage(d,"\nChecking for MMC style command set...\n");
+
+  d->is_mmc=0;
+  if(mode_sense(d,22,0x2A)==0){
+  
+    b=d->sg_buffer;
+    b+=b[3]+4;
+    
+    if((b[0]&0x3F)==0x2A){
+      /* MMC style drive! */
+      d->is_mmc=1;
+      
+      if(b[1]>=4){
+	if(b[5]&0x1){
+	  cdmessage(d,"\tDrive is MMC style\n");
+	  return(1);
+	}else{
+	  cdmessage(d,"\tDrive is MMC, but reports CDDA incapable.\n");
+	  cdmessage(d,"\tIt will likely not be able to read audio data.\n");
+	  return(1);
+	}
+      }
+    }
+  }
+  
+  cdmessage(d,"\tDrive does not have MMC CDDA support\n");
+  return(0);
+}
+
+static void 
+check_exceptions(cdrom_drive_t *d, exception_t *list)
+{
+  int i=0;
+  while(list[i].model){
+    if(!strncmp(list[i].model,d->drive_model,strlen(list[i].model))){
+      if(list[i].density)d->density=list[i].density;
+      if(list[i].enable)d->enable_cdda=list[i].enable;
+      if(list[i].read)d->read_audio=list[i].read;
+      if(list[i].bigendianp!=-1)d->bigendianp=list[i].bigendianp;
+      return;
+    }
+    i++;
+  }
+}
+
+/* request vendor brand and model */
+unsigned char *
+scsi_inquiry(cdrom_drive_t *d){
+  memcpy(d->sg_buffer,(char[]){ 0x12,0,0,0,56,0},6);
+
+  if(handle_scsi_cmd(d,6, 0, 56,'\377',1)) {
+    cderror(d,"008: Unable to identify CDROM model\n");
+    return(NULL);
+  }
+  return (d->sg_buffer);
+}
+
+
+int 
+scsi_init_drive(cdrom_drive_t *d){
+  int ret;
+
+  check_atapi(d);
+  check_mmc(d);
+
+  /* generic Sony type defaults; specialize from here */
+  d->density = 0x0;
+  d->enable_cdda = dummy_exception;
+  d->read_audio = scsi_read_D8;
+  d->fua=0x0;
+  if(d->is_atapi)d->lun=0; /* it should already be; just to make sure */
+      
+  if(d->is_mmc){
+
+    d->read_audio = scsi_read_mmc2;
+    d->bigendianp=0;
+
+    check_exceptions(d,mmc_list);
+
+  }else{
+    
+    if(d->is_atapi){
+      /* Not MMC maybe still uses CDIO_MMC_GPCMD_READ_CD */
+
+      d->read_audio = scsi_read_mmc2;
+      d->bigendianp=0;
+
+      check_exceptions(d,atapi_list);
+
+    }else{
+
+      check_exceptions(d,scsi_list);
+
+    }
+  }
+
+  /* we really do want the sector size at 2048 to begin.*/  
+  if (!d->is_atapi)
+    set_sectorsize(d, CDIO_CD_FRAMESIZE); 
+
+  d->enable_cdda(d,0);
+
+  d->read_toc = (!memcmp(d->drive_model, "IMS", 3) && !d->is_atapi) 
+    ? scsi_read_toc2 : scsi_read_toc;
+  d->set_speed = NULL;
+  
+
+  if (!d->is_atapi) {
+    unsigned int sector_size= get_orig_sectorsize(d);
+    
+    if ( (sector_size < CDIO_CD_FRAMESIZE)
+	 && set_sectorsize(d, CDIO_CD_FRAMESIZE) )
+      d->adjust_ssize = CDIO_CD_FRAMESIZE / sector_size;
+    else
+      d->adjust_ssize = 1;
+  } else
+    d->adjust_ssize = 1;
+  
+  d->tracks=d->read_toc(d);
+  if(d->tracks<1)
+    return(d->tracks);
+
+  tweak_SG_buffer(d);
+  d->opened=1;
+
+  if((ret=verify_read_command(d)))return(ret);
+  check_fua_bit(d);
+
+  d->error_retry=1;
+  d->sg=realloc(d->sg,d->nsectors*CDIO_CD_FRAMESIZE_RAW + SG_OFF + 128);
+  d->sg_buffer=d->sg+SG_OFF;
+  d->report_all=1;
+  return(0);
+}
+
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/lib/cdda_interface/smallft.c libcdio-c742eed/lib/cdda_interface/smallft.c
--- libcdio-f9bd26c/lib/cdda_interface/smallft.c	1970-01-01 09:00:00 +0900
+++ libcdio-c742eed/lib/cdda_interface/smallft.c	2012-02-26 05:07:35 +0900
@@ -0,0 +1,561 @@
+/*
+  $Id: smallft.c,v 1.2 2008/04/16 17:00:40 karl Exp $
+
+  Copyright (C) 2008 Rocky Bernstein <rocky@gnu.org>
+  Copyright (C) 1998 Monty xiphmont@mit.edu
+
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/******************************************************************
+ * FFT implementation from OggSquish, minus cosine transforms,
+ * minus all but radix 2/4 case
+ *
+ * See OggSquish or NetLib for the version that can do other than just
+ * power-of-two sized vectors.
+ ******************************************************************/
+
+#include <stdlib.h>
+#include <math.h>
+#include "smallft.h"
+
+static void drfti1(int n, float *wa, int *ifac){
+  static int ntryh[4] = { 4,2,3,5 };
+  static float tpi = 6.28318530717958647692528676655900577;
+  float arg,argh,argld,fi;
+  int ntry=0,i,j=-1;
+  int k1, l1, l2, ib;
+  int ld, ii, ip, is, nq, nr;
+  int ido, ipm, nfm1;
+  int nl=n;
+  int nf=0;
+
+ L101:
+  j++;
+  if (j < 4)
+    ntry=ntryh[j];
+  else
+    ntry+=2;
+
+ L104:
+  nq=nl/ntry;
+  nr=nl-ntry*nq;
+  if (nr!=0) goto L101;
+
+  nf++;
+  ifac[nf+1]=ntry;
+  nl=nq;
+  if(ntry!=2)goto L107;
+  if(nf==1)goto L107;
+
+  for (i=1;i<nf;i++){
+    ib=nf-i+1;
+    ifac[ib+1]=ifac[ib];
+  }
+  ifac[2] = 2;
+
+ L107:
+  if(nl!=1)goto L104;
+  ifac[0]=n;
+  ifac[1]=nf;
+  argh=tpi/n;
+  is=0;
+  nfm1=nf-1;
+  l1=1;
+
+  if(nfm1==0)return;
+
+  for (k1=0;k1<nfm1;k1++){
+    ip=ifac[k1+2];
+    ld=0;
+    l2=l1*ip;
+    ido=n/l2;
+    ipm=ip-1;
+
+    for (j=0;j<ipm;j++){
+      ld+=l1;
+      i=is;
+      argld=(float)ld*argh;
+      fi=0.;
+      for (ii=2;ii<ido;ii+=2){
+	fi+=1.;
+	arg=fi*argld;
+	wa[i++]=cos(arg);
+	wa[i++]=sin(arg);
+      }
+      is+=ido;
+    }
+    l1=l2;
+  }
+}
+
+static void fdrffti(int n, float *wsave, int *ifac){
+
+  if (n == 1) return;
+  drfti1(n, wsave+n, ifac);
+}
+
+static void dradf2(int ido,int l1,float *cc,float *ch,float *wa1){
+  int i,k;
+  float ti2,tr2;
+  int t0,t1,t2,t3,t4,t5,t6;
+
+  t1=0;
+  t0=(t2=l1*ido);
+  t3=ido<<1;
+  for(k=0;k<l1;k++){
+    ch[t1<<1]=cc[t1]+cc[t2];
+    ch[(t1<<1)+t3-1]=cc[t1]-cc[t2];
+    t1+=ido;
+    t2+=ido;
+  }
+    
+  if(ido<2)return;
+  if(ido==2)goto L105;
+
+  t1=0;
+  t2=t0;
+  for(k=0;k<l1;k++){
+    t3=t2;
+    t4=(t1<<1)+(ido<<1);
+    t5=t1;
+    t6=t1+t1;
+    for(i=2;i<ido;i+=2){
+      t3+=2;
+      t4-=2;
+      t5+=2;
+      t6+=2;
+      tr2=wa1[i-2]*cc[t3-1]+wa1[i-1]*cc[t3];
+      ti2=wa1[i-2]*cc[t3]-wa1[i-1]*cc[t3-1];
+      ch[t6]=cc[t5]+ti2;
+      ch[t4]=ti2-cc[t5];
+      ch[t6-1]=cc[t5-1]+tr2;
+      ch[t4-1]=cc[t5-1]-tr2;
+    }
+    t1+=ido;
+    t2+=ido;
+  }
+
+  if(ido%2==1)return;
+
+ L105:
+  t3=(t2=(t1=ido)-1);
+  t2+=t0;
+  for(k=0;k<l1;k++){
+    ch[t1]=-cc[t2];
+    ch[t1-1]=cc[t3];
+    t1+=ido<<1;
+    t2+=ido;
+    t3+=ido;
+  }
+}
+
+static void dradf4(int ido,int l1,float *cc,float *ch,float *wa1,
+	    float *wa2,float *wa3){
+  static float hsqt2 = .70710678118654752440084436210485;
+  int i,k,t0,t1,t2,t3,t4,t5,t6;
+  float ci2,ci3,ci4,cr2,cr3,cr4,ti1,ti2,ti3,ti4,tr1,tr2,tr3,tr4;
+  t0=l1*ido;
+  
+  t1=t0;
+  t4=t1<<1;
+  t2=t1+(t1<<1);
+  t3=0;
+
+  for(k=0;k<l1;k++){
+    tr1=cc[t1]+cc[t2];
+    tr2=cc[t3]+cc[t4];
+
+    ch[t5=t3<<2]=tr1+tr2;
+    ch[(ido<<2)+t5-1]=tr2-tr1;
+    ch[(t5+=(ido<<1))-1]=cc[t3]-cc[t4];
+    ch[t5]=cc[t2]-cc[t1];
+
+    t1+=ido;
+    t2+=ido;
+    t3+=ido;
+    t4+=ido;
+  }
+
+  if(ido<2)return;
+  if(ido==2)goto L105;
+
+
+  t1=0;
+  for(k=0;k<l1;k++){
+    t2=t1;
+    t4=t1<<2;
+    t5=(t6=ido<<1)+t4;
+    for(i=2;i<ido;i+=2){
+      t3=(t2+=2);
+      t4+=2;
+      t5-=2;
+
+      t3+=t0;
+      cr2=wa1[i-2]*cc[t3-1]+wa1[i-1]*cc[t3];
+      ci2=wa1[i-2]*cc[t3]-wa1[i-1]*cc[t3-1];
+      t3+=t0;
+      cr3=wa2[i-2]*cc[t3-1]+wa2[i-1]*cc[t3];
+      ci3=wa2[i-2]*cc[t3]-wa2[i-1]*cc[t3-1];
+      t3+=t0;
+      cr4=wa3[i-2]*cc[t3-1]+wa3[i-1]*cc[t3];
+      ci4=wa3[i-2]*cc[t3]-wa3[i-1]*cc[t3-1];
+
+      tr1=cr2+cr4;
+      tr4=cr4-cr2;
+      ti1=ci2+ci4;
+      ti4=ci2-ci4;
+
+      ti2=cc[t2]+ci3;
+      ti3=cc[t2]-ci3;
+      tr2=cc[t2-1]+cr3;
+      tr3=cc[t2-1]-cr3;
+
+      ch[t4-1]=tr1+tr2;
+      ch[t4]=ti1+ti2;
+
+      ch[t5-1]=tr3-ti4;
+      ch[t5]=tr4-ti3;
+
+      ch[t4+t6-1]=ti4+tr3;
+      ch[t4+t6]=tr4+ti3;
+
+      ch[t5+t6-1]=tr2-tr1;
+      ch[t5+t6]=ti1-ti2;
+    }
+    t1+=ido;
+  }
+  if(ido&1)return;
+
+ L105:
+  
+  t2=(t1=t0+ido-1)+(t0<<1);
+  t3=ido<<2;
+  t4=ido;
+  t5=ido<<1;
+  t6=ido;
+
+  for(k=0;k<l1;k++){
+    ti1=-hsqt2*(cc[t1]+cc[t2]);
+    tr1=hsqt2*(cc[t1]-cc[t2]);
+
+    ch[t4-1]=tr1+cc[t6-1];
+    ch[t4+t5-1]=cc[t6-1]-tr1;
+
+    ch[t4]=ti1-cc[t1+t0];
+    ch[t4+t5]=ti1+cc[t1+t0];
+
+    t1+=ido;
+    t2+=ido;
+    t4+=t3;
+    t6+=ido;
+  }
+}
+
+static void drftf1(int n,float *c,float *ch,float *wa,int *ifac){
+  int i,k1,l1,l2;
+  int na,kh,nf;
+  int ip,iw,ido,ix2,ix3;
+
+  nf=ifac[1];
+  na=1;
+  l2=n;
+  iw=n;
+
+  for(k1=0;k1<nf;k1++){
+    kh=nf-k1;
+    ip=ifac[kh+1];
+    l1=l2/ip;
+    ido=n/l2;
+    iw-=(ip-1)*ido;
+    na=1-na;
+
+    if(ip!=4)goto L102;
+
+    ix2=iw+ido;
+    ix3=ix2+ido;
+    if(na!=0)
+      dradf4(ido,l1,ch,c,wa+iw-1,wa+ix2-1,wa+ix3-1);
+    else
+      dradf4(ido,l1,c,ch,wa+iw-1,wa+ix2-1,wa+ix3-1);
+    goto L110;
+
+ L102:
+    if(ip!=2)goto L104;
+    if(na!=0)goto L103;
+
+    dradf2(ido,l1,c,ch,wa+iw-1);
+    goto L110;
+
+  L103:
+    dradf2(ido,l1,ch,c,wa+iw-1);
+    goto L110;
+
+  L104:
+    return; /* We're restricted to powers of two.  just fail */
+
+  L110:
+    l2=l1;
+  }
+
+  if(na==1)return;
+
+  for(i=0;i<n;i++)c[i]=ch[i];
+}
+
+static void fdrfftf(int n,float *r,float *wsave,int *ifac){
+  if(n==1)return;
+  drftf1(n,r,wsave,wsave+n,ifac);
+}
+
+static void dradb2(int ido,int l1,float *cc,float *ch,float *wa1){
+  int i,k,t0,t1,t2,t3,t4,t5,t6;
+  float ti2,tr2;
+
+  t0=l1*ido;
+  
+  t1=0;
+  t2=0;
+  t3=(ido<<1)-1;
+  for(k=0;k<l1;k++){
+    ch[t1]=cc[t2]+cc[t3+t2];
+    ch[t1+t0]=cc[t2]-cc[t3+t2];
+    t2=(t1+=ido)<<1;
+  }
+
+  if(ido<2)return;
+  if(ido==2)goto L105;
+
+  t1=0;
+  t2=0;
+  for(k=0;k<l1;k++){
+    t3=t1;
+    t5=(t4=t2)+(ido<<1);
+    t6=t0+t1;
+    for(i=2;i<ido;i+=2){
+      t3+=2;
+      t4+=2;
+      t5-=2;
+      t6+=2;
+      ch[t3-1]=cc[t4-1]+cc[t5-1];
+      tr2=cc[t4-1]-cc[t5-1];
+      ch[t3]=cc[t4]-cc[t5];
+      ti2=cc[t4]+cc[t5];
+      ch[t6-1]=wa1[i-2]*tr2-wa1[i-1]*ti2;
+      ch[t6]=wa1[i-2]*ti2+wa1[i-1]*tr2;
+    }
+    t2=(t1+=ido)<<1;
+  }
+
+  if(ido%2==1)return;
+
+L105:
+  t1=ido-1;
+  t2=ido-1;
+  for(k=0;k<l1;k++){
+    ch[t1]=cc[t2]+cc[t2];
+    ch[t1+t0]=-(cc[t2+1]+cc[t2+1]);
+    t1+=ido;
+    t2+=ido<<1;
+  }
+}
+
+static void dradb4(int ido,int l1,float *cc,float *ch,float *wa1,
+			  float *wa2,float *wa3){
+  static float sqrt2=1.4142135623730950488016887242097;
+  int i,k,t0,t1,t2,t3,t4,t5,t6,t7,t8;
+  float ci2,ci3,ci4,cr2,cr3,cr4,ti1,ti2,ti3,ti4,tr1,tr2,tr3,tr4;
+  t0=l1*ido;
+  
+  t1=0;
+  t2=ido<<2;
+  t3=0;
+  t6=ido<<1;
+  for(k=0;k<l1;k++){
+    t4=t3+t6;
+    t5=t1;
+    tr3=cc[t4-1]+cc[t4-1];
+    tr4=cc[t4]+cc[t4]; 
+    tr1=cc[t3]-cc[(t4+=t6)-1];
+    tr2=cc[t3]+cc[t4-1];
+    ch[t5]=tr2+tr3;
+    ch[t5+=t0]=tr1-tr4;
+    ch[t5+=t0]=tr2-tr3;
+    ch[t5+=t0]=tr1+tr4;
+    t1+=ido;
+    t3+=t2;
+  }
+
+  if(ido<2)return;
+  if(ido==2)goto L105;
+
+  t1=0;
+  for(k=0;k<l1;k++){
+    t5=(t4=(t3=(t2=t1<<2)+t6))+t6;
+    t7=t1;
+    for(i=2;i<ido;i+=2){
+      t2+=2;
+      t3+=2;
+      t4-=2;
+      t5-=2;
+      t7+=2;
+      ti1=cc[t2]+cc[t5];
+      ti2=cc[t2]-cc[t5];
+      ti3=cc[t3]-cc[t4];
+      tr4=cc[t3]+cc[t4];
+      tr1=cc[t2-1]-cc[t5-1];
+      tr2=cc[t2-1]+cc[t5-1];
+      ti4=cc[t3-1]-cc[t4-1];
+      tr3=cc[t3-1]+cc[t4-1];
+      ch[t7-1]=tr2+tr3;
+      cr3=tr2-tr3;
+      ch[t7]=ti2+ti3;
+      ci3=ti2-ti3;
+      cr2=tr1-tr4;
+      cr4=tr1+tr4;
+      ci2=ti1+ti4;
+      ci4=ti1-ti4;
+
+      ch[(t8=t7+t0)-1]=wa1[i-2]*cr2-wa1[i-1]*ci2;
+      ch[t8]=wa1[i-2]*ci2+wa1[i-1]*cr2;
+      ch[(t8+=t0)-1]=wa2[i-2]*cr3-wa2[i-1]*ci3;
+      ch[t8]=wa2[i-2]*ci3+wa2[i-1]*cr3;
+      ch[(t8+=t0)-1]=wa3[i-2]*cr4-wa3[i-1]*ci4;
+      ch[t8]=wa3[i-2]*ci4+wa3[i-1]*cr4;
+    }
+    t1+=ido;
+  }
+
+  if(ido%2 == 1)return;
+
+ L105:
+
+  t1=ido;
+  t2=ido<<2;
+  t3=ido-1;
+  t4=ido+(ido<<1);
+  for(k=0;k<l1;k++){
+    t5=t3;
+    ti1=cc[t1]+cc[t4];
+    ti2=cc[t4]-cc[t1];
+    tr1=cc[t1-1]-cc[t4-1];
+    tr2=cc[t1-1]+cc[t4-1];
+    ch[t5]=tr2+tr2;
+    ch[t5+=t0]=sqrt2*(tr1-ti1);
+    ch[t5+=t0]=ti2+ti2;
+    ch[t5+=t0]=-sqrt2*(tr1+ti1);
+
+    t3+=ido;
+    t1+=t2;
+    t4+=t2;
+  }
+}
+
+static void drftb1(int n, float *c, float *ch, float *wa, int *ifac){
+  int i,k1,l1,l2;
+  int na;
+  int nf,ip,iw,ix2,ix3,ido;
+
+  nf=ifac[1];
+  na=0;
+  l1=1;
+  iw=1;
+
+  for(k1=0;k1<nf;k1++){
+    ip=ifac[k1 + 2];
+    l2=ip*l1;
+    ido=n/l2;
+    if(ip!=4)goto L103;
+    ix2=iw+ido;
+    ix3=ix2+ido;
+
+    if(na!=0)
+      dradb4(ido,l1,ch,c,wa+iw-1,wa+ix2-1,wa+ix3-1);
+    else
+      dradb4(ido,l1,c,ch,wa+iw-1,wa+ix2-1,wa+ix3-1);
+    na=1-na;
+    goto L115;
+
+  L103:
+    if(ip!=2)goto L106;
+
+    if(na!=0)
+      dradb2(ido,l1,ch,c,wa+iw-1);
+    else
+      dradb2(ido,l1,c,ch,wa+iw-1);
+    na=1-na;
+    goto L115;
+
+  L106:
+    return; /* silently fail.  we only do powers of two in this version */
+
+  L115:
+    l1=l2;
+    iw+=(ip-1)*ido;
+  }
+
+  if(na==0)return;
+
+  for(i=0;i<n;i++)c[i]=ch[i];
+}
+
+static void fdrfftb(int n, float *r, float *wsave, int *ifac){
+  if (n == 1)return;
+  drftb1(n, r, wsave, wsave+n, ifac);
+}
+
+void fft_forward(int n, float *buf,float *trigcache,int *splitcache){
+  int flag=0;
+
+  if(!trigcache || !splitcache){
+    trigcache=calloc(3*n,sizeof(float));
+    splitcache=calloc(32,sizeof(int));
+    fdrffti(n, trigcache, splitcache);
+    flag=1;
+  }
+
+  fdrfftf(n, buf, trigcache, splitcache);
+
+  if(flag){
+    free(trigcache);
+    free(splitcache);
+  }
+}
+
+void fft_backward(int n, float *buf, float *trigcache,int *splitcache){
+  int i;
+  int flag=0;
+
+  if(!trigcache || !splitcache){
+    trigcache=calloc(3*n,sizeof(float));
+    splitcache=calloc(32,sizeof(int));
+    fdrffti(n, trigcache, splitcache);
+    flag=1;
+  }
+
+  fdrfftb(n, buf, trigcache, splitcache);
+
+  for(i=0;i<n;i++)buf[i]/=n;
+
+  if(flag){
+    free(trigcache);
+    free(splitcache);
+  }
+}
+
+void fft_i(int n, float **trigcache, int **splitcache){
+  *trigcache=calloc(3*n,sizeof(float));
+  *splitcache=calloc(32,sizeof(int));
+  fdrffti(n, *trigcache, *splitcache);
+}
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/lib/cdda_interface/smallft.h libcdio-c742eed/lib/cdda_interface/smallft.h
--- libcdio-f9bd26c/lib/cdda_interface/smallft.h	1970-01-01 09:00:00 +0900
+++ libcdio-c742eed/lib/cdda_interface/smallft.h	2012-02-26 05:07:35 +0900
@@ -0,0 +1,28 @@
+/*
+  $Id: smallft.h,v 1.2 2008/04/16 17:00:40 karl Exp $
+
+  Copyright (C) 2008 Rocky Bernstein <rocky@gnu.org>
+  Copyright (C) 1998 Monty xiphmont@mit.edu
+
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/******************************************************************
+ * FFT implementation from OggSquish, minus cosine transforms.
+ * Only convenience functions exposed
+ ******************************************************************/
+
+extern void fft_forward(int n, float *buf, float *trigcache, int *sp);
+extern void fft_backward(int n, float *buf, float *trigcache, int *sp);
+extern void fft_i(int n, float **trigcache, int **splitcache);
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/lib/cdda_interface/test_interface.c libcdio-c742eed/lib/cdda_interface/test_interface.c
--- libcdio-f9bd26c/lib/cdda_interface/test_interface.c	1970-01-01 09:00:00 +0900
+++ libcdio-c742eed/lib/cdda_interface/test_interface.c	2012-02-26 05:07:35 +0900
@@ -0,0 +1,234 @@
+/*
+  $Id: test_interface.c,v 1.4 2008/06/13 19:26:23 flameeyes Exp $
+
+  Copyright (C) 2004, 2008 Rocky Bernstein <rocky@gnu.org>
+  Copyright (C) 1998 Monty xiphmont@mit.edu
+  
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/******************************************************************
+ *
+ * Fake interface backend for testing paranoia layer
+ * NOTE: THIS CODE HAVE BEEN FOLDED INTO THE MAINLINE CODE SO IT IS
+ * NOT USED ANYMORE. (It's not clear that it had been used
+ * for a while in the non-libcdio cdparaonoia either.)
+ *
+ ******************************************************************/
+
+#ifdef CDDA_TEST
+#include "low_interface.h"
+#include "utils.h"
+
+/* Build which test model? */
+#define  CDDA_TEST_OK
+#undef  CDDA_TEST_JITTER_SMALL
+#undef  CDDA_TEST_JITTER_LARGE
+#undef  CDDA_TEST_JITTER_MASSIVE
+#undef  CDDA_TEST_FRAG_SMALL
+#undef  CDDA_TEST_FRAG_LARGE
+#undef  CDDA_TEST_FRAG_MASSIVE
+#undef  CDDA_TEST_BOGUS_BYTES
+#undef  CDDA_TEST_DROPDUPE_BYTES
+#undef  CDDA_TEST_SCRATCH
+#undef  CDDA_TEST_UNDERRUN
+
+#undef  CDDA_TEST_ALLJITTER
+#undef  CDDA_TEST_SOMEJITTER
+#undef CDDA_TEST_SEEKJITTER
+
+static int test_readtoc (cdrom_drive *d){
+  int tracks=0;
+  long bytes;
+  long sectors;
+
+  /* only one track, as many sectors as the file */
+
+  bytes=lseek(d->cdda_fd,0,SEEK_END);
+  lseek(d->cdda_fd,0,SEEK_SET);
+  sectors=bytes/CDIO_CD_FRAMESIZE_RAW;
+
+  d->disc_toc[0].bFlags = 0;
+  d->disc_toc[0].bTrack = 1;
+  d->disc_toc[0].dwStartSector = 37;
+
+  d->disc_toc[1].bFlags = 0x4;
+  d->disc_toc[1].bTrack = CDROM_LEADOUT;
+  d->disc_toc[1].dwStartSector = sectors+37;
+
+  tracks=2;
+  d->cd_extra=0;
+  return(--tracks);  /* without lead-out */
+}
+
+/* we emulate jitter, scratches, atomic jitter and bogus bytes on
+   boundaries, etc */
+
+static long 
+test_read(cdrom_drive *d, void *p, long begin, long sectors)
+{
+
+#if defined(CDDA_TEST_SEEKJITTER) \
+  || defined(CDDA_TEST_ALLJITTER) \
+  || defined(CDDA_TEST_SOMEJITTER)
+  int jitter_flag;
+#endif
+
+  int los_flag;
+  static int jitter=0;
+  int bytes_so_far=0;
+  long bytestotal;
+  static FILE *fd=NULL;
+  static long lastread=0;
+
+  if(!fd)fd=fdopen(d->cdda_fd,"r");
+
+#ifdef CDDA_TEST_UNDERRUN
+  sectors-=1;
+#endif
+
+#ifdef CDDA_TEST_SEEKJITTER
+  if(lastread!=begin)jitter_flag=1;
+#else
+#ifdef CDDA_TEST_ALLJITTER
+  jitter_flag=1;
+#else
+#ifdef CDDA_TEST_SOMEJITTER
+  jitter_flag=(drand48()>.9?1:0);
+  los_flag=(drand48()>.9?1:0);
+#else
+  los_flag=1;
+#endif
+#endif
+#endif
+
+  lastread=begin+sectors;
+  bytestotal=sectors*CDIO_CD_FRAMESIZE_RAW;
+
+  begin*=CDIO_CD_FRAMESIZE_RAW;
+
+  while(bytes_so_far<bytestotal){
+    int inner_bytes=bytestotal-bytes_so_far;
+    char *inner_buf=(char *)p +  bytes_so_far;
+    long seeki;
+    long rbytes;
+    long this_bytes=inner_bytes;
+
+#ifdef CDDA_TEST_OK
+    
+#else
+#ifdef CDDA_TEST_JITTER_SMALL
+    if(jitter_flag)jitter=4*(int)((drand48()-.5)*CDIO_CD_FRAMESIZE_RAW/8);
+
+#else
+#ifdef CDDA_TEST_JITTER_LARGE
+    if(jitter_flag)jitter=32*(int)((drand48()-.5)*CDIO_CD_FRAMESIZE_RAW/8);
+
+#else
+#ifdef CDDA_TEST_JITTER_MASSIVE
+    if(jitter_flag)jitter=128*(int)((drand48()-.5)*CDIO_CD_FRAMESIZE_RAW/8);
+
+#else
+#ifdef CDDA_TEST_FRAG_SMALL
+    if(los_flag)this_bytes=256*(int)(drand48()*CDIO_CD_FRAMESIZE_RAW/8);
+    if(jitter_flag)jitter=4*(int)((drand48()-.5)*CDIO_CD_FRAMESIZE_RAW/8);
+
+#else
+#ifdef CDDA_TEST_FRAG_LARGE
+    if(los_flag)this_bytes=16*(int)(drand48()*CDIO_CD_FRAMESIZE_RAW/8);
+    if(jitter_flag)jitter=4*(int)((drand48()-.5)*CDIO_CD_FRAMESIZE_RAW/8);
+
+#else
+#ifdef CDDA_TEST_FRAG_MASSIVE
+    if(los_flag)this_bytes=8*(int)(drand48()*CDIO_CD_FRAMESIZE_RAW/8);
+    if(jitter_flag)jitter=32*(int)((drand48()-.5)*CDIO_CD_FRAMESIZE_RAW/8);
+
+#else
+#ifdef CDDA_TEST_DROPDUPE_BYTES
+    if(los_flag)this_bytes=CDIO_CD_FRAMESIZE_RAW;
+    if(jitter_flag)
+      if (drand48()>.8)
+	this_jitter=32;
+      else
+	this_jitter=0;
+
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+
+
+    if(begin+jitter+bytes_so_far<0)jitter=0;    
+    seeki=begin+bytes_so_far+jitter;
+
+    if(fseek(fd,seeki,SEEK_SET)<0){
+      return(0);
+    }
+    rbytes=fread(inner_buf,1,this_bytes,fd);
+    bytes_so_far+=rbytes;
+    if(rbytes==0)break;
+
+#ifdef CDDA_TEST_SEEKJITTER
+    jitter_flag=0;
+    los_flag=0;
+#else
+#ifdef CDDA_TEST_ALLJITTER
+    jitter_flag=1;
+    los_flag=0;
+#else
+#ifdef CDDA_TEST_SOMEJITTER
+    jitter_flag=(drand48()>.9?1:0);
+  los_flag=(drand48()>.9?1:0);
+#else
+  los_flag=1;
+#endif
+#endif
+#endif
+
+  }
+
+#ifdef CDDA_TEST_SCRATCH
+  {
+    long location=300*CDIO_CD_FRAMESIZE_RAW+(drand48()*56)+512;
+
+    if(begin<=location && begin+bytestotal>location){
+      memset(p+location-begin,(int)(drand48()*256),1100);
+    }
+  }
+#endif
+
+  return(sectors);
+}
+
+/* set function pointers to use the ioctl routines */
+int test_init_drive (cdrom_drive *d){
+
+  d->nsectors=13;
+  d->enable_cdda = dummy_exception;
+  d->read_audio = test_read;
+  d->read_toc = test_readtoc;
+  d->set_speed = dummy_exception;
+  d->tracks=d->read_toc(d);
+  if(d->tracks==-1)
+    return(d->tracks);
+  d->opened=1;
+  srand48(0);
+  return(0);
+}
+
+#endif
+
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/lib/cdda_interface/toc.c libcdio-c742eed/lib/cdda_interface/toc.c
--- libcdio-f9bd26c/lib/cdda_interface/toc.c	1970-01-01 09:00:00 +0900
+++ libcdio-c742eed/lib/cdda_interface/toc.c	2012-02-26 05:07:35 +0900
@@ -0,0 +1,211 @@
+/*
+  $Id: toc.c,v 1.7 2008/04/16 17:00:40 karl Exp $
+
+  Copyright (C) 2005, 2008 Rocky Bernstein <rocky@gnu.org>
+  Copyright (C) 1998 Monty xiphmont@mit.edu
+  derived from code (C) 1994-1996 Heiko Eissfeldt
+
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/******************************************************************
+ * Table of contents convenience functions
+ ******************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+# define __CDIO_CONFIG_H__ 1
+#endif
+
+#include "low_interface.h"
+#include "utils.h"
+
+/*! Return the lsn for the start of track i_track */
+lsn_t
+cdda_track_firstsector(cdrom_drive_t *d, track_t i_track)
+{
+  if(!d->opened){
+    cderror(d,"400: Device not open\n");
+    return(-1);
+  }
+
+  if (i_track == 0) {
+    if (d->disc_toc[0].dwStartSector == 0) {
+      /* first track starts at lsn 0 -> no pre-gap */
+      cderror(d,"401: Invalid track number\n");
+      return(-1);
+    }
+    else {
+      return 0; /* pre-gap of first track always starts at lba 0 */
+    }
+  }
+
+  if( i_track>d->tracks) {
+    cderror(d,"401: Invalid track number\n");
+    return(-1);
+  }
+
+  {
+    const track_t i_first_track = cdio_get_first_track_num(d->p_cdio);
+    return(d->disc_toc[i_track-i_first_track].dwStartSector);
+  }
+}
+
+/*! Get first lsn of the first audio track. -1 is returned on error. */
+lsn_t
+cdda_disc_firstsector(cdrom_drive_t *d)
+{
+  int i;
+  if(!d->opened){
+    cderror(d,"400: Device not open\n");
+    return(-1);
+  }
+
+  /* look for an audio track */
+  for ( i=0; i<d->tracks; i++ )
+    if( cdda_track_audiop(d, i+1)==1 ) {
+      if (i == 0) /* disc starts at lba 0 if first track is an audio track */
+       return 0;
+      else
+       return cdda_track_firstsector(d, i+1);
+    }
+
+  cderror(d,"403: No audio tracks on disc\n");  
+  return(-1);
+}
+
+/*! Get last lsn of the track. The lsn is generally one less than the
+  start of the next track. -1 is returned on error. */
+lsn_t
+cdda_track_lastsector(cdrom_drive_t *d, track_t i_track)
+{
+  if (!d->opened) {
+    cderror(d,"400: Device not open\n");
+    return -1;
+  }
+
+  if (i_track == 0) {
+    if (d->disc_toc[0].dwStartSector == 0) {
+      /* first track starts at lba 0 -> no pre-gap */
+      cderror(d,"401: Invalid track number\n");
+      return(-1);
+    }
+    else {
+      return d->disc_toc[0].dwStartSector-1;
+    }
+  }
+
+  if ( i_track<1 || i_track>d->tracks ) {
+    cderror(d,"401: Invalid track number\n");
+    return -1;
+  }
+  
+  /* CD Extra have their first session ending at the last audio track */
+  if (d->cd_extra > 0 && i_track+1 <= d->tracks) {
+    if (d->audio_last_sector >= d->disc_toc[i_track-1].dwStartSector &&
+        d->audio_last_sector < d->disc_toc[i_track].dwStartSector) {
+      return d->audio_last_sector;
+    }
+  }
+
+  /* Safe, we've always the leadout at disc_toc[tracks] */
+  return(d->disc_toc[i_track].dwStartSector-1);
+}
+
+/*! Get last lsn of the last audio track. The last lssn generally one
+  less than the start of the next track after the audio track. -1 is
+  returned on error. */
+lsn_t
+cdda_disc_lastsector(cdrom_drive_t *d)
+{
+  if (!d->opened) {
+    cderror(d,"400: Device not open\n");
+    return -1;
+  } else {
+    /* look for an audio track */
+    const track_t i_first_track = cdio_get_first_track_num(d->p_cdio);
+    track_t i = cdio_get_last_track_num(d->p_cdio);
+    for ( ; i >= i_first_track; i-- )
+      if ( cdda_track_audiop(d,i) )
+	return (cdda_track_lastsector(d,i));
+  }
+  cderror(d,"403: No audio tracks on disc\n");  
+  return -1;
+}
+
+/*! Return the number of tracks on the CD. */
+track_t
+cdda_tracks(cdrom_drive_t *d)
+{
+  if (!d->opened){
+    cderror(d,"400: Device not open\n");
+    return -1;
+  }
+  return(d->tracks);
+}
+
+/*! Return the track containing the given LSN. If the LSN is before
+    the first track (in the pregap), 0 is returned. If there was an
+    error or the LSN after the LEADOUT (beyond the end of the CD), then
+    CDIO_INVALID_TRACK is returned.
+ */
+int 
+cdda_sector_gettrack(cdrom_drive_t *d, lsn_t lsn)
+{
+  if (!d->opened) {
+    cderror(d,"400: Device not open\n");
+    return -1;
+  } else {
+    if (lsn < d->disc_toc[0].dwStartSector)
+      return 0; /* We're in the pre-gap of first track */
+
+    return cdio_get_track(d->p_cdio, lsn);
+  }
+}
+
+/*! Return the number of channels in track: 2 or 4; -2 if not
+  implemented or -1 for error.
+  Not meaningful if track is not an audio track.
+*/
+int 
+cdda_track_channels(cdrom_drive_t *d, track_t i_track)
+{
+  return(cdio_get_track_channels(d->p_cdio, i_track));
+}
+
+/*! Return 1 is track is an audio track, 0 otherwise. */
+int 
+cdda_track_audiop(cdrom_drive_t *d, track_t i_track)
+{
+  track_format_t track_format = cdio_get_track_format(d->p_cdio, i_track);
+  return TRACK_FORMAT_AUDIO == track_format ? 1 : 0;
+}
+
+/*! Return 1 is track is an audio track, 0 otherwise. */
+int 
+cdda_track_copyp(cdrom_drive_t *d, track_t i_track)
+{
+  track_flag_t track_flag = cdio_get_track_copy_permit(d->p_cdio, i_track);
+  return CDIO_TRACK_FLAG_TRUE == track_flag ? 1 : 0;
+}
+
+/*! Return 1 is audio track has linear preemphasis set, 0 otherwise. 
+    Only makes sense for audio tracks.
+ */
+int 
+cdda_track_preemp(cdrom_drive_t *d, track_t i_track)
+{
+  track_flag_t track_flag = cdio_get_track_preemphasis(d->p_cdio, i_track);
+  return CDIO_TRACK_FLAG_TRUE == track_flag ? 1 : 0;
+}
+
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/lib/cdda_interface/utils.c libcdio-c742eed/lib/cdda_interface/utils.c
--- libcdio-f9bd26c/lib/cdda_interface/utils.c	1970-01-01 09:00:00 +0900
+++ libcdio-c742eed/lib/cdda_interface/utils.c	2012-02-26 05:07:35 +0900
@@ -0,0 +1,162 @@
+/*
+  Copyright (C) 2004, 2008, 2010, 2011 Rocky Bernstein <rocky@gnu.org>
+  Copyright (C) 1998 Monty xiphmont@mit.edu
+  
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+# define __CDIO_CONFIG_H__ 1
+#endif
+
+#include "common_interface.h"
+#include "utils.h"
+void 
+cderror(cdrom_drive_t *d,const char *s)
+{
+  ssize_t bytes_ret;
+  if(s && d){
+    switch(d->errordest){
+    case CDDA_MESSAGE_PRINTIT:
+      bytes_ret = write(STDERR_FILENO, s, strlen(s));
+      if (strlen(s) != bytes_ret)
+	  
+      break;
+    case CDDA_MESSAGE_LOGIT:
+      d->errorbuf=catstring(d->errorbuf,s);
+      break;
+    case CDDA_MESSAGE_FORGETIT:
+    default: ;
+    }
+  }
+}
+
+void 
+cdmessage(cdrom_drive_t *d, const char *s)
+{
+  ssize_t bytes_ret;
+  if(s && d){
+    switch(d->messagedest){
+    case CDDA_MESSAGE_PRINTIT:
+      bytes_ret = write(STDERR_FILENO, s, strlen(s));
+      break;
+    case CDDA_MESSAGE_LOGIT:
+      d->messagebuf=catstring(d->messagebuf,s);
+      break;
+    case CDDA_MESSAGE_FORGETIT:
+    default: ;
+    }
+  }
+}
+
+void 
+idperror(int messagedest,char **messages,const char *f,
+	 const char *s)
+{
+
+  char *buffer;
+  int malloced=0;
+  if(!f)
+    buffer=(char *)s;
+  else
+    if(!s)
+      buffer=(char *)f;
+    else{
+      buffer=malloc(strlen(f)+strlen(s)+9);
+      sprintf(buffer,f,s);
+      malloced=1;
+    }
+
+  if(buffer){
+    ssize_t bytes_ret;
+    switch(messagedest){
+    case CDDA_MESSAGE_PRINTIT:
+      bytes_ret = write(STDERR_FILENO,buffer,strlen(buffer));
+      if(errno){
+	bytes_ret = write(STDERR_FILENO,": ",2);
+	bytes_ret = write(STDERR_FILENO,strerror(errno),strlen(strerror(errno)));
+	bytes_ret = write(STDERR_FILENO,"\n",1);
+      }
+      break;
+    case CDDA_MESSAGE_LOGIT:
+      if(messages){
+	*messages=catstring(*messages,buffer);
+	if(errno){
+	  *messages=catstring(*messages,": ");
+	  *messages=catstring(*messages,strerror(errno));
+	  *messages=catstring(*messages,"\n");
+	}
+      }
+      break;
+    case CDDA_MESSAGE_FORGETIT:
+    default: ;
+    }
+  }
+  if(malloced)free(buffer);
+}
+
+void 
+idmessage(int messagedest,char **messages,const char *f,
+	  const char *s)
+{
+  char *buffer;
+  int malloced=0;
+  if(!f)
+    buffer=(char *)s;
+  else
+    if(!s)
+      buffer=(char *)f;
+    else{
+      const unsigned int i_buffer=strlen(f)+strlen(s)+10;
+      buffer=malloc(i_buffer);
+      sprintf(buffer,f,s);
+      strncat(buffer,"\n", i_buffer);
+      malloced=1;
+    }
+
+  if(buffer) {
+    ssize_t bytes_ret;
+    switch(messagedest){
+    case CDDA_MESSAGE_PRINTIT:
+      bytes_ret = write(STDERR_FILENO,buffer,strlen(buffer));
+      if(!malloced)
+	  bytes_ret = write(STDERR_FILENO,"\n",1);
+      break;
+    case CDDA_MESSAGE_LOGIT:
+      if(messages){
+	*messages=catstring(*messages,buffer);
+	if(!malloced)*messages=catstring(*messages,"\n");
+	}
+      break;
+    case CDDA_MESSAGE_FORGETIT:
+    default: ;
+    }
+  }
+  if(malloced)free(buffer);
+}
+
+char *
+catstring(char *buff, const char *s) {
+  if (s) {
+    const unsigned int add_len = strlen(s) + 9;
+    if(buff) {
+      buff = realloc(buff, strlen(buff) + add_len);
+    } else {
+      buff=calloc(add_len, 1);
+    }
+    strncat(buff, s, add_len);
+  }
+  return(buff);
+}
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/lib/cdda_interface/utils.h libcdio-c742eed/lib/cdda_interface/utils.h
--- libcdio-f9bd26c/lib/cdda_interface/utils.h	1970-01-01 09:00:00 +0900
+++ libcdio-c742eed/lib/cdda_interface/utils.h	2012-02-26 05:07:35 +0900
@@ -0,0 +1,79 @@
+/*
+  $Id: utils.h,v 1.8 2008/04/16 17:00:41 karl Exp $
+
+  Copyright (C) 2004, 2005, 2008 Rocky Bernstein <rocky@gnu.org>
+  Copyright (C) 1998 Monty xiphmont@mit.edu
+  
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <cdio/bytesex.h>
+#include <stdio.h>
+
+/* I wonder how many alignment issues this is gonna trip in the
+   future...  it shouldn't trip any...  I guess we'll find out :) */
+
+static inline int 
+bigendianp(void)
+{
+  int test=1;
+  char *hack=(char *)(&test);
+  if(hack[0])return(0);
+  return(1);
+}
+
+extern char *catstring(char *buff, const char *s);
+
+
+/*#if BYTE_ORDER == LITTLE_ENDIAN*/
+
+#ifndef WORDS_BIGENDIAN
+
+static inline int16_t be16_to_cpu(int16_t x){
+  return(UINT16_SWAP_LE_BE_C(x));
+}
+
+static inline int16_t le16_to_cpu(int16_t x){
+  return(x);
+}
+
+#else
+
+static inline int16_t be16_to_cpu(int16_t x){
+  return(x);
+}
+
+static inline int16_t le16_to_cpu(int16_t x){
+  return(UINT16_SWAP_LE_BE_C(x));
+}
+
+
+#endif
+
+static inline int16_t cpu_to_be16(int16_t x){
+  return(be16_to_cpu(x));
+}
+
+static inline int16_t cpu_to_le16(int16_t x){
+  return(le16_to_cpu(x));
+}
+
+void cderror(cdrom_drive_t *d, const char *s);
+
+void cdmessage(cdrom_drive_t *d,const char *s);
+
+void idperror(int messagedest, char **messages, const char *f, const char *s);
+
+void idmessage(int messagedest, char **messages, const char *f, const char *s);
+
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/lib/paranoia/Makefile.am libcdio-c742eed/lib/paranoia/Makefile.am
--- libcdio-f9bd26c/lib/paranoia/Makefile.am	1970-01-01 09:00:00 +0900
+++ libcdio-c742eed/lib/paranoia/Makefile.am	2012-02-26 05:07:35 +0900
@@ -0,0 +1,152 @@
+#   Copyright (C) 2004, 2006, 2008, 2011 Rocky Bernstein <rocky@gnu.org>
+#
+#   This program is free software: you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation, either version 3 of the License, or
+#   (at your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+########################################################
+# Things to make the libcdio_paranoia library
+########################################################
+
+#
+# From libtool documentation amended with guidance from N. Boullis: 
+#
+#  1. Start with version information of `0:0:0' for each libtool library.
+#
+#  2. It is probably not a good idea to update the version information 
+#     several times between public releases, but rather once per public
+#     release. (This seems to be more an aesthetic consideration than
+#     a hard technical one.)
+#
+#  3. If the library source code has changed at all since the last
+#     update, then increment REVISION (`C:R:A' becomes `C:R+1:A').
+#
+#  4. If any interfaces have been added, removed, or changed since the
+#     last update, increment CURRENT, and set REVISION to 0.
+#
+#  5. If any interfaces have been added since the last public release,
+#     then increment AGE.
+#
+#  6. If any interfaces have been removed or changed since the last
+#     public release, then set AGE to 0. A changed interface means an
+#     incompatibility with previous versions.
+
+EXTRA_DIST = libcdio_paranoia.sym
+
+libcdio_paranoia_la_CURRENT = 1
+libcdio_paranoia_la_REVISION = 0
+libcdio_paranoia_la_AGE = 0
+
+noinst_HEADERS  = gap.h isort.h overlap.h p_block.h
+
+libcdio_paranoia_sources = gap.c isort.c overlap.c overlap.h \
+	p_block.c paranoia.c 
+
+lib_LTLIBRARIES = libcdio_paranoia.la
+
+libcdio_paranoia_la_SOURCES = $(libcdio_paranoia_sources)
+libcdio_paranoia_la_ldflags = -version-info $(libcdio_paranoia_la_CURRENT):$(libcdio_paranoia_la_REVISION):$(libcdio_paranoia_la_AGE) @LT_NO_UNDEFINED@
+
+INCLUDES = $(LIBCDIO_CFLAGS)
+
+FLAGS=@LIBCDIO_CFLAGS@ @TYPESIZES@ @CFLAGS@ -I.. -I../..
+OPT=$(FLAGS)
+DEBUG=$(FLAGS)
+
+## SUFFIXES = .t
+## TFILES = isort.t gap.t p_block.t paranoia.t
+##test:	$(TFILES)
+##.c.t:
+##	$(CC) -g -DTEST $(DEBUG) -o $@ $< $(LIBS)
+##	$@
+##debug: 
+##	$(MAKE) libcdio_paranoia.a CFLAGS="$(DEBUG)"
+
+LIBS = $(LIBCDIO_LIBS) $(LIBCDIO_CDDA_LIBS)
+
+
+########################################################
+# Things to version the symbols in the libraries
+########################################################
+
+# An explanation of the versioning problem from Nicolas Boullis and
+# the versioned symbol solution he uses below...
+# 
+# Currently, libvcdinfo uses the cdio_open function from libcdio.
+# Let's imagine a program foobar that uses both the vcdinfo_open
+# function from libvcdinfo and the cdio_open function from libcdio.
+
+# Currently, libcdio has SONAME libcdio.so.0, libvcdinfo has SONAME
+# libvcdinfo.so.0 and requires libcdio.so.0, and foobar requires both
+# libvcdinfo.so.0 and libcdio.so.0. Everything looks fine.
+#
+# Now, for some reason, you decide to change the cdio_open function.
+# That's your right, but you have to bump the CURRENT version and (if I
+# understand it correctly, athough this is not that clear in libtool's
+# documentation) set the AGE to 0. Anyway, this bumps the SONAME, which is
+# sane since the interface changes incompatibly.
+
+# Now, you have a new libcdio with SONAME libcdio.so.1. But libvcdinfo and
+# foobar still require libcdio.so.0. Everything is still fine.
+
+# Now, after some minor changes, the author of foobar recompiles foobar.
+# Then, foobar now requires libvcdinfo.so.0 and libcdio.so.1. And foobar
+# now segfaults...
+
+# What is happening? When you run foobar, if brings both libvcdinfo.so.0
+# and libcdio.so.1, but libvcdinfo.so.0 also brings libcdio.so.0. So you
+# have both libcdio.so.0 and libcdio.so.1 that bring their symbols to the
+# global namespace. Hence, you have to incompatible versions of the
+# cdio_open function in the name space. When foobar calls cdio_open, it
+# may choose the wrong function, and segfaults...
+
+# With versioned symbols, the cdio_open function from libcdio.so.0 may be
+# known as (something that looks like) cdio_open@@CDIO_0. An the cdio_open
+# function from libcdio.so.1 as cdio_open@@CDIO_1. Both versions of
+# libcdio would still be brought in by the most recent foobar, but foobar
+# (and libvcdinfo) know which versioned function to use and then use the
+# good one.
+
+
+# This is some simple versioning where every symbol is versioned with
+# something that looks like the SONAME of the library. More complex (and
+# better) versioning is possible; it is for example what is used by glibc.
+# But good complex versioning is something that requires much more
+# work...
+
+
+# The below is a impliments symbol versioning.  First of all, I
+# compute MAJOR as CURENT - AGE; that is what is used within libtool
+# (at least on GNU/Linux systems) for the number in the SONAME.  The
+# nm command gives the list of symbols known in each of the object
+# files that will be part of the shared library. And the sed command
+# extracts from this list those symbols that will be shared. (This sed
+# command comes from libtool.)
+
+libcdio_paranoia_la_MAJOR = $(shell expr $(libcdio_paranoia_la_CURRENT) - $(libcdio_paranoia_la_AGE))
+if BUILD_VERSIONED_LIBS
+libcdio_paranoia_la_LDFLAGS = $(libcdio_paranoia_la_ldflags) -Wl,--version-script=libcdio_paranoia.la.ver
+libcdio_paranoia_la_DEPENDENCIES = libcdio_paranoia.la.ver
+
+libcdio_paranoia.la.ver: $(libcdio_paranoia_la_OBJECTS) $(srcdir)/libcdio_paranoia.sym
+	echo 'CDIO_PARANOIA_$(libcdio_paranoia_la_MAJOR) { ' > $@
+	objs=`for obj in $(libcdio_paranoia_la_OBJECTS); do sed -ne "s/^pic_object='\(.*\)'$$/\1/p" $$obj; done`; \
+	if test -n "$$objs" ; then \
+	  nm $${objs} | sed -n -e 's/^.*[ 	][ABCDGIRSTW][ABCDGIRSTW]*[ 	][ 	]*\([_A-Za-z][_A-Za-z0-9]*\)$$/\1/p' | sort -u | { first=true; while read symbol; do if grep -q "^$${symbol}\$$" $(srcdir)/libcdio_paranoia.sym; then if test $$first = true; then echo "  global:"; first=false; fi; echo "    $${symbol};"; fi; done; } >> $@; \
+	  nm $${objs} | sed -n -e 's/^.*[ 	][ABCDGIRSTW][ABCDGIRSTW]*[ 	][ 	]*\([_A-Za-z][_A-Za-z0-9]*\)$$/\1/p' | sort -u | { first=true; while read symbol; do if grep -q "^$${symbol}\$$" $(srcdir)/libcdio_paranoia.sym; then :; else if test $$first = true; then echo "  local:"; first=false; fi; echo "    $${symbol};"; fi; done; } >> $@; \
+	fi
+	echo '};' >> $@
+else 
+libcdio_paranoia_la_LDFLAGS = $(libcdio_paranoia_la_ldflags)
+endif 
+
+MOSTLYCLEANFILES = libcdio_paranoia.la.ver
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/lib/paranoia/gap.c libcdio-c742eed/lib/paranoia/gap.c
--- libcdio-f9bd26c/lib/paranoia/gap.c	1970-01-01 09:00:00 +0900
+++ libcdio-c742eed/lib/paranoia/gap.c	2012-02-26 05:07:35 +0900
@@ -0,0 +1,551 @@
+/*
+  Copyright (C) 2004, 2008, 2011 Rocky Bernstein <rocky@gnu.org>
+  Copyright (C) 1998 Monty xiphmont@mit.edu
+  
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/***
+ * Gap analysis support code for paranoia
+ *
+ ***/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+# define __CDIO_CONFIG_H__ 1
+#endif
+#include "p_block.h"
+#include <cdio/paranoia.h>
+#include "gap.h"
+#include <string.h>
+
+/**** Gap analysis code ***************************************************/
+
+/* ===========================================================================
+ * i_paranoia_overlap_r (internal)
+ *
+ * This function seeks backward through two vectors (starting at the given
+ * offsets) to determine how many consecutive samples agree.  It returns
+ * the number of matching samples, which may be 0.
+ *
+ * Unlike its sibling, i_paranoia_overlap_f, this function doesn't need to
+ * be given the size of the vectors (all vectors stop at offset 0).
+ *
+ * This function is used by i_analyze_rift_r() below to find where a
+ * leading rift ends.
+ */
+long int
+i_paranoia_overlap_r(int16_t *buffA,int16_t *buffB,
+			  long offsetA, long offsetB)
+{
+  long beginA=offsetA;
+  long beginB=offsetB;
+
+  /* Start at the given offsets and work our way backwards until we hit
+   * the beginning of one of the vectors.
+   */
+  for( ; beginA>=0 && beginB>=0; beginA--,beginB-- )
+    if (buffA[beginA] != buffB[beginB]) break;
+
+  /* These values will either point to the first mismatching sample, or
+   * -1 if we hit the beginning of a vector.  So increment to point to the
+   * last matching sample.
+   *
+   * ??? Why?  This would appear to return one less sample than actually
+   * matched.  E.g., no matching samples returns -1!  Is this a bug?
+   */
+  beginA++;
+  beginB++;
+  
+  return(offsetA-beginA);
+}
+
+
+/* ===========================================================================
+ * i_paranoia_overlap_f (internal)
+ *
+ * This function seeks forward through two vectors (starting at the given
+ * offsets) to determine how many consecutive samples agree.  It returns
+ * the number of matching samples, which may be 0.
+ *
+ * Unlike its sibling, i_paranoia_overlap_r, this function needs to given
+ * the size of the vectors.
+ *
+ * This function is used by i_analyze_rift_f() below to find where a
+ * trailing rift ends.
+ */
+long int 
+i_paranoia_overlap_f(int16_t *buffA,int16_t *buffB,
+		     long offsetA, long offsetB,
+		     long sizeA,long sizeB)
+{
+  long endA=offsetA;
+  long endB=offsetB;
+  
+  /* Start at the given offsets and work our way forward until we hit
+   * the end of one of the vectors.
+   */
+  for(;endA<sizeA && endB<sizeB;endA++,endB++)
+    if(buffA[endA]!=buffB[endB])break;
+  
+  /* ??? Note that we don't do any post-loop tweaking of endA.  Why the
+   * asymmetry with i_paranoia_overlap_r?
+   */
+
+  return(endA-offsetA);
+}
+
+
+/* ===========================================================================
+ * i_stutter_or_gap (internal)
+ *
+ * This function compares (gap) samples of two vectors at the given offsets.
+ * It returns 0 if all the samples are identical, or nonzero if they differ.
+ *
+ * This is used by i_analyze_rift_[rf] below to determine whether a rift
+ * contains samples dropped by the other vector (that should be inserted),
+ * or whether the rift contains a stutter (that should be dropped).  See
+ * i_analyze_rift_[rf] for more details.
+ */
+int 
+i_stutter_or_gap(int16_t *A, int16_t *B,long offA, long offB, long int gap)
+{
+  long a1=offA;
+  long b1=offB;
+  
+  /* If the rift was so big that there aren't enough samples in the other
+   * vector to compare against the full gap, then just compare what we
+   * have available.  E.g.:
+   *
+   *            (5678)|(newly matching run ...)
+   *    (... 12345678)| (345678) |(newly matching run ...)
+   *
+   * In this case, a1 would be -2, since we'd want to compare 6 samples
+   * against a vector that had only 4.  So we start 2 samples later, and
+   * compare the 4 available samples.
+   *
+   * Again, this approach to identifying stutters is simply a heuristic,
+   * so this may not produce correct results in all cases.
+   */
+  if(a1<0){
+    /* Note that a1 is negative, so we're increasing b1 and decreasing (gap).
+     */
+    b1-=a1;
+    gap+=a1;
+    a1=0;
+  }
+
+  /* Note that we don't have an equivalent adjustment for leading rifts.
+   * Thus, it's possible for the following memcmp() to run off the end
+   * of A.  See the bug note in i_analyze_rift_r().
+   */
+  
+  /* Multiply gap by 2 because samples are 2 bytes long and memcmp compares
+   * at the byte level.
+   */
+  return(memcmp(A+a1,B+b1,gap*2));
+}
+
+/* riftv is the first value into the rift -> or <- */
+
+
+/* ===========================================================================
+ * i_analyze_rift_f (internal)
+ *
+ * This function examines a trailing rift to see how far forward the rift goes
+ * and to determine what kind of rift it is.  This function is called by
+ * i_stage2_each() when a trailing rift is detected.  (aoffset,boffset) are
+ * the offsets into (A,B) of the first mismatching sample.
+ *
+ * This function returns:
+ *  matchA  > 0 if there are (matchA) samples missing from A
+ *  matchA  < 0 if there are (-matchA) duplicate samples (stuttering) in A
+ *  matchB  > 0 if there are (matchB) samples missing from B
+ *  matchB  < 0 if there are (-matchB) duplicate samples in B
+ *  matchC != 0 if there are (matchC) samples of garbage, after which
+ *              both A and B are in sync again
+ */
+void 
+i_analyze_rift_f(int16_t *A,int16_t *B,
+		 long sizeA, long sizeB,
+		 long aoffset, long boffset, 
+		 long *matchA,long *matchB,long *matchC)
+{
+  
+  long apast=sizeA-aoffset;
+  long bpast=sizeB-boffset;
+  long i;
+  
+  *matchA=0, *matchB=0, *matchC=0;
+  
+  /* Look forward to see where we regain agreement between vectors
+   * A and B (of at least MIN_WORDS_RIFT samples).  We look for one of
+   * the following possible matches:
+   * 
+   *                         edge
+   *                          v
+   * (1)  (... A matching run)|(aoffset matches ...)
+   *      (... B matching run)| (rift) |(boffset+i matches ...)
+   *
+   * (2)  (... A matching run)| (rift) |(aoffset+i matches ...)
+   *      (... B matching run)|(boffset matches ...)
+   *
+   * (3)  (... A matching run)| (rift) |(aoffset+i matches ...)
+   *      (... B matching run)| (rift) |(boffset+i matches ...)
+   *
+   * Anything that doesn't match one of these three is too corrupt to
+   * for us to recover from.  E.g.:
+   *
+   *      (... A matching run)| (rift) |(eventual match ...)
+   *      (... B matching run)| (big rift) |(eventual match ...)
+   *
+   * We won't find the eventual match, since we wouldn't be sure how
+   * to fix the rift.
+   */
+  
+  for(i=0;;i++){
+    /* Search for whatever case we hit first, so as to end up with the
+     * smallest rift.
+     *
+     * ??? Why do we start at 0?  It should never match.
+     */
+
+    /* Don't search for (1) past the end of B */
+    if (i<bpast)
+
+      /* See if we match case (1) above, which either means that A dropped
+       * samples at the rift, or that B stuttered.
+       */
+      if(i_paranoia_overlap_f(A,B,aoffset,boffset+i,sizeA,sizeB)>=MIN_WORDS_RIFT){
+	*matchA=i;
+	break;
+      }
+    
+    /* Don't search for (2) or (3) past the end of A */
+    if (i<apast) {
+
+      /* See if we match case (2) above, which either means that B dropped
+       * samples at the rift, or that A stuttered.
+       */
+      if(i_paranoia_overlap_f(A,B,aoffset+i,boffset,sizeA,sizeB)>=MIN_WORDS_RIFT){
+	*matchB=i;
+	break;
+      }
+
+      /* Don't search for (3) past the end of B */
+      if (i<bpast)
+
+        /* See if we match case (3) above, which means that a fixed-length
+         * rift of samples is getting read unreliably.
+         */
+	if(i_paranoia_overlap_f(A,B,aoffset+i,boffset+i,sizeA,sizeB)>=MIN_WORDS_RIFT){
+	  *matchC=i;
+	  break;
+	}
+    }else
+
+      /* Stop searching when we've reached the end of both vectors.
+       * In theory we could stop when there aren't MIN_WORDS_RIFT samples
+       * left in both vectors, but this case should happen fairly rarely.
+       */
+      if(i>=bpast)break;
+    
+    /* Try the search again with a larger tentative rift. */
+  }
+  
+  if(*matchA==0 && *matchB==0 && *matchC==0)return;
+  
+  if(*matchC)return;
+
+  /* For case (1) or (2), we need to determine whether the rift contains
+   * samples dropped by the other vector (that should be inserted), or
+   * whether the rift contains a stutter (that should be dropped).  To
+   * distinguish, we check the contents of the rift against the good samples
+   * just before the rift.  If the contents match, then the rift contains
+   * a stutter.
+   *
+   * A stutter in the second vector:
+   *     (...good samples... 1234)|(567 ...newly matched run...)
+   *     (...good samples... 1234)| (1234) | (567 ...newly matched run)
+   *
+   * Samples missing from the first vector:
+   *     (...good samples... 1234)|(901 ...newly matched run...)
+   *     (...good samples... 1234)| (5678) |(901 ...newly matched run...)
+   *
+   * Of course, there's no theoretical guarantee that a non-stutter
+   * truly represents missing samples, but given that we're dealing with
+   * verified fragments in stage 2, we can have some confidence that this
+   * is the case.
+   */
+  if(*matchA){
+    /* For case (1), we need to determine whether A dropped samples at the
+     * rift or whether B stuttered.
+     *
+     * If the rift doesn't match the good samples in A (and hence in B),
+     * it's not a stutter, and the rift should be inserted into A.
+     */
+    if(i_stutter_or_gap(A,B,aoffset-*matchA,boffset,*matchA))
+      return;
+
+    /* It is a stutter, so we need to signal that we need to remove
+     * (matchA) bytes from B.
+     */
+    *matchB = -*matchA;
+    *matchA=0;
+    return;
+
+  }else{
+    /* Case (2) is the inverse of case (1) above. */
+    if(i_stutter_or_gap(B,A,boffset-*matchB,aoffset,*matchB))
+      return;
+
+    *matchA = -*matchB;
+    *matchB=0;
+    return;
+  }
+}
+
+
+/* riftv must be first even val of rift moving back */
+
+/* ===========================================================================
+ * i_analyze_rift_r (internal)
+ *
+ * This function examines a leading rift to see how far back the rift goes
+ * and to determine what kind of rift it is.  This function is called by
+ * i_stage2_each() when a leading rift is detected.  (aoffset,boffset) are
+ * the offsets into (A,B) of the first mismatching sample.
+ *
+ * This function returns:
+ *  matchA  > 0 if there are (matchA) samples missing from A
+ *  matchA  < 0 if there are (-matchA) duplicate samples (stuttering) in A
+ *  matchB  > 0 if there are (matchB) samples missing from B
+ *  matchB  < 0 if there are (-matchB) duplicate samples in B
+ *  matchC != 0 if there are (matchC) samples of garbage, after which
+ *              both A and B are in sync again
+ */
+void 
+i_analyze_rift_r(int16_t *A,int16_t *B,
+		 long sizeA, long sizeB,
+		 long aoffset, long boffset, 
+		 long *matchA,long *matchB,long *matchC)
+{
+  
+  long apast=aoffset+1;
+  long bpast=boffset+1;
+  long i;
+  
+  *matchA=0, *matchB=0, *matchC=0;
+
+  /* Look backward to see where we regain agreement between vectors
+   * A and B (of at least MIN_WORDS_RIFT samples).  We look for one of
+   * the following possible matches:
+   * 
+   *                                    edge
+   *                                      v
+   * (1)             (... aoffset matches)|(A matching run ...)
+   *      (... boffset-i matches)| (rift) |(B matching run ...)
+   *
+   * (2)  (... aoffset-i matches)| (rift) |(A matching run ...)
+   *                (... boffset matches)|(B matching run ...)
+   *
+   * (3)  (... aoffset-i matches)| (rift) |(A matching run ...)
+   *      (... boffset-i matches)| (rift) |(B matching run ...)
+   *
+   * Anything that doesn't match one of these three is too corrupt to
+   * for us to recover from.  E.g.:
+   *
+   *         (... eventual match)| (rift) |(A matching run ...)
+   *    (... eventual match) | (big rift) |(B matching run ...)
+   *
+   * We won't find the eventual match, since we wouldn't be sure how
+   * to fix the rift.
+   */
+  
+  for(i=0;;i++){
+    /* Search for whatever case we hit first, so as to end up with the
+     * smallest rift.
+     *
+     * ??? Why do we start at 0?  It should never match.
+     */
+
+    /* Don't search for (1) past the beginning of B */
+    if (i<bpast)
+
+      /* See if we match case (1) above, which either means that A dropped
+       * samples at the rift, or that B stuttered.
+       */
+      if(i_paranoia_overlap_r(A,B,aoffset,boffset-i)>=MIN_WORDS_RIFT){
+	*matchA=i;
+	break;
+      }
+
+    /* Don't search for (2) or (3) past the beginning of A */
+    if (i<apast) {
+
+      /* See if we match case (2) above, which either means that B dropped
+       * samples at the rift, or that A stuttered.
+       */
+      if(i_paranoia_overlap_r(A,B,aoffset-i,boffset)>=MIN_WORDS_RIFT){
+	*matchB=i;
+	break;
+      }
+
+      /* Don't search for (3) past the beginning of B */
+      if (i<bpast)
+
+	/* See if we match case (3) above, which means that a fixed-length
+	 * rift of samples is getting read unreliably.
+	 */
+	if(i_paranoia_overlap_r(A,B,aoffset-i,boffset-i)>=MIN_WORDS_RIFT){
+	  *matchC=i;
+	  break;
+	}
+    }else
+
+      /* Stop searching when we've reached the end of both vectors.
+       * In theory we could stop when there aren't MIN_WORDS_RIFT samples
+       * left in both vectors, but this case should happen fairly rarely.
+       */
+      if(i>=bpast)break;
+
+    /* Try the search again with a larger tentative rift. */
+  }
+
+  if(*matchA==0 && *matchB==0 && *matchC==0)return;
+
+  if(*matchC)return;
+
+  /* For case (1) or (2), we need to determine whether the rift contains
+   * samples dropped by the other vector (that should be inserted), or
+   * whether the rift contains a stutter (that should be dropped).  To
+   * distinguish, we check the contents of the rift against the good samples
+   * just after the rift.  If the contents match, then the rift contains
+   * a stutter.
+   *
+   * A stutter in the second vector:
+   *              (...newly matched run... 234)|(5678 ...good samples...)
+   *     (...newly matched run... 234)| (5678) |(5678 ...good samples...)
+   *
+   * Samples missing from the first vector:
+   *              (...newly matched run... 890)|(5678 ...good samples...)
+   *     (...newly matched run... 890)| (1234) |(5678 ...good samples...)
+   *
+   * Of course, there's no theoretical guarantee that a non-stutter
+   * truly represents missing samples, but given that we're dealing with
+   * verified fragments in stage 2, we can have some confidence that this
+   * is the case.
+   */
+
+  if(*matchA){
+    /* For case (1), we need to determine whether A dropped samples at the
+     * rift or whether B stuttered.
+     *
+     * If the rift doesn't match the good samples in A (and hence in B),
+     * it's not a stutter, and the rift should be inserted into A.
+     *
+     * ???BUG??? It's possible for aoffset+1+*matchA to be > sizeA, in
+     * which case the comparison in i_stutter_or_gap() will extend beyond
+     * the bounds of A.  Thankfully, this isn't writing data and thus
+     * trampling memory, but it's still a memory access error that should
+     * be fixed.
+     *
+     * This bug is not fixed yet.
+     */
+    if(i_stutter_or_gap(A,B,aoffset+1,boffset-*matchA+1,*matchA))
+      return;
+
+    /* It is a stutter, so we need to signal that we need to remove
+     * (matchA) bytes from B.
+     */
+    *matchB = -*matchA;
+    *matchA=0;
+    return;
+
+  }else{
+    /* Case (2) is the inverse of case (1) above. */
+    if(i_stutter_or_gap(B,A,boffset+1,aoffset-*matchB+1,*matchB))
+      return;
+
+    *matchA = -*matchB;
+    *matchB=0;
+    return;
+  }
+}
+
+
+/* ===========================================================================
+ * analyze_rift_silence_f (internal)
+ *
+ * This function examines the fragment and root from the rift onward to
+ * see if they have a rift's worth of silence (or if they end with silence).
+ * It sets (*matchA) to -1 if A's rift is silence, (*matchB) to -1 if B's
+ * rift is silence, and sets them to 0 otherwise.
+ *
+ * Note that, unlike every other function in cdparanoia, this function
+ * considers any repeated value to be silence (which, in effect, it is).
+ * All other functions only consider repeated zeroes to be silence.
+ *
+ * ??? Is this function name just a misnomer, as it's really looking for
+ * repeated garbage?
+ *
+ * This function is called by i_stage2_each() if it runs into a trailing rift
+ * that i_analyze_rift_f couldn't diagnose.  This checks for another variant:
+ * where one vector has silence and the other doesn't.  We then assume
+ * that the silence (and anything following it) is garbage.
+ *
+ * Note that while this function checks both A and B for silence, the caller
+ * assumes that only one or the other has silence.
+ */
+void
+analyze_rift_silence_f(int16_t *A,int16_t *B,long sizeA,long sizeB,
+		       long aoffset, long boffset,
+		       long *matchA, long *matchB)
+{
+  *matchA=-1;
+  *matchB=-1;
+
+  /* Search for MIN_WORDS_RIFT samples, or to the end of the vector,
+   * whichever comes first.
+   */
+  sizeA=min(sizeA,aoffset+MIN_WORDS_RIFT);
+  sizeB=min(sizeB,boffset+MIN_WORDS_RIFT);
+
+  aoffset++;
+  boffset++;
+
+  /* Check whether A has only "silence" within the search range.  Note
+   * that "silence" here is a single, repeated value (zero or not).
+   */
+  while(aoffset<sizeA){
+    if(A[aoffset]!=A[aoffset-1]){
+      *matchA=0;
+      break;
+    }
+    aoffset++;
+  }
+
+  /* Check whether B has only "silence" within the search range.  Note
+   * that "silence" here is a single, repeated value (zero or not).
+   *
+   * Also note that while the caller assumes that only matchA or matchB
+   * is set, we check both vectors here.
+   */
+  while(boffset<sizeB){
+    if(B[boffset]!=B[boffset-1]){
+      *matchB=0;
+      break;
+    }
+    boffset++;
+  }
+}
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/lib/paranoia/gap.h libcdio-c742eed/lib/paranoia/gap.h
--- libcdio-f9bd26c/lib/paranoia/gap.h	1970-01-01 09:00:00 +0900
+++ libcdio-c742eed/lib/paranoia/gap.h	2012-02-26 05:07:35 +0900
@@ -0,0 +1,43 @@
+/*
+  $Id: gap.h,v 1.2 2008/04/17 17:39:48 karl Exp $
+
+  Copyright (C) 2004, 2008 Rocky Bernstein <rocky@gnu.org>
+  Copyright (C) 1998 Monty xiphmont@mit.edu
+  
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _GAP_H_
+#define _GAP_H_
+
+extern long i_paranoia_overlap_r(int16_t *buffA,int16_t *buffB,
+				 long offsetA, long offsetB);
+extern long i_paranoia_overlap_f(int16_t *buffA,int16_t *buffB,
+				 long offsetA, long offsetB,
+				 long sizeA,long sizeB);
+extern int i_stutter_or_gap(int16_t *A, int16_t *B,long offA, long offB,
+			    long gap);
+extern void i_analyze_rift_f(int16_t *A,int16_t *B,
+			     long sizeA, long sizeB,
+			     long aoffset, long boffset, 
+			     long *matchA,long *matchB,long *matchC);
+extern void i_analyze_rift_r(int16_t *A,int16_t *B,
+			     long sizeA, long sizeB,
+			     long aoffset, long boffset, 
+			     long *matchA,long *matchB,long *matchC);
+
+extern void analyze_rift_silence_f(int16_t *A,int16_t *B,long sizeA,long sizeB,
+				   long aoffset, long boffset,
+				   long *matchA, long *matchB);
+#endif /*_GAP_H*/
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/lib/paranoia/isort.c libcdio-c742eed/lib/paranoia/isort.c
--- libcdio-f9bd26c/lib/paranoia/isort.c	1970-01-01 09:00:00 +0900
+++ libcdio-c742eed/lib/paranoia/isort.c	2012-02-26 05:07:35 +0900
@@ -0,0 +1,301 @@
+/*
+  Copyright (C) 2004, 2005, 2008, 2011 Rocky Bernstein <rocky@gnu.org>
+  Copyright (C) 1998 Monty xiphmont@mit.edu
+  
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* sorted vector abstraction for paranoia */
+
+/* Old isort got a bit complex.  This re-constrains complexity to
+   give a go at speed through a more alpha-6-like mechanism. */
+
+
+/* "Sort" is a bit of a misnomer in this implementation.  It's actually
+ * basically a hash table of sample values (with a linked-list collision
+ * resolution), which lets you quickly determine where in a vector a
+ * particular sample value occurs.
+ *
+ * Collisions aren't due to hash collisions, as the table has one bucket
+ * for each possible sample value.  Instead, the "collisions" represent
+ * multiple occurrences of a given value.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+# define __CDIO_CONFIG_H__ 1
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include "p_block.h"
+#include "isort.h"
+
+
+/* ===========================================================================
+ * sort_alloc()
+ *
+ * Allocates and initializes a new, empty sort_info object, which can be
+ * used to index up to (size) samples from a vector.
+ */
+
+sort_info_t *
+sort_alloc(long size)
+{
+  sort_info_t *ret=calloc(1, sizeof(sort_info_t));
+
+  ret->vector=NULL;
+  ret->sortbegin=-1;
+  ret->size=-1;
+  ret->maxsize=size;
+
+  ret->head=calloc(65536,sizeof(sort_link_t *));
+  ret->bucketusage=calloc(1, 65536*sizeof(long));
+  ret->revindex=calloc(size,sizeof(sort_link_t));
+  ret->lastbucket=0;
+
+  return(ret);
+}
+
+
+/* ===========================================================================
+ * sort_unsortall() (internal)
+ *
+ * This function resets the index for further use with a different vector
+ * or range, without the overhead of an unnecessary free/alloc.
+ */
+
+void 
+sort_unsortall(sort_info_t *i)
+{
+  /* If there were few enough different samples encountered (and hence few
+   * enough buckets used), we can just zero out those buckets.  If there
+   * were many (2000 is picked somewhat arbitrarily), it's faster simply to
+   * zero out all buckets with a memset() rather than walking the data
+   * structure and zeroing them out one by one.
+   */
+  if (i->lastbucket>2000) { /* a guess */
+    memset(i->head,0,65536*sizeof(sort_link_t *));
+  } else {
+    long b;
+    for (b=0; b<i->lastbucket; b++)
+      i->head[i->bucketusage[b]]=NULL;
+  }
+
+  i->lastbucket=0;
+  i->sortbegin=-1;
+
+  /* Curiously, this function preserves the vector association created
+   * by sort_setup(), but it is used only internally by sort_setup, so
+   * preserving this association is unnecessary.
+   */
+}
+
+
+/* ===========================================================================
+ * sort_free()
+ *
+ * Releases all memory consumed by a sort_info object.
+ */
+
+void 
+sort_free(sort_info_t *i)
+{
+  free(i->revindex);
+  free(i->head);
+  free(i->bucketusage);
+  free(i);
+}
+
+
+/* ===========================================================================
+ * sort_sort() (internal)
+ *
+ * This function builds the index to allow for fast searching for sample
+ * values within a portion (sortlo - sorthi) of the object's associated
+ * vector.  It is called internally and only when needed.
+ */
+
+static void 
+sort_sort(sort_info_t *i,long sortlo,long sorthi)
+{
+  long j;
+
+  /* We walk backward through the range to index because we insert new
+   * samples at the head of each bucket's list.  At the end, they'll be
+   * sorted from first to last occurrence.
+   */
+  for (j=sorthi-1; j>=sortlo; j--) {
+    /* i->vector[j] = the signed 16-bit sample to index.
+     * hv           = pointer to the head of the sorted list of occurences
+     *                of this sample
+     * l            = the node to associate with this sample
+     *
+     * We add 32768 to convert the signed 16-bit integer to an unsigned
+     * range from 0 to 65535.
+     *
+     * Note that l is located within i->revindex at a position
+     * corresponding to the sample's position in the vector.  This allows
+     * ipos() to determine the sample position from a returned sort_link.
+     */
+    sort_link_t **hv = i->head+i->vector[j]+32768;
+    sort_link_t *l   = i->revindex+j;
+
+    /* If this is the first time we've encountered this sample, add its
+     * bucket to the list of buckets used.  This list is used only for
+     * resetting the index quickly.
+     */
+    if(*hv==NULL){
+      i->bucketusage[i->lastbucket] = i->vector[j]+32768;
+      i->lastbucket++;
+    }
+
+    /* Point the new node at the old head, then assign the new node as
+     * the new head.
+     */
+    l->next=*hv;    
+    *hv=l;
+  }
+
+  /* Mark the index as initialized.
+   */
+  i->sortbegin=0;
+}
+
+
+/* ===========================================================================
+ * sort_setup()
+ *
+ * This function initializes a previously allocated sort_info_t.  The
+ * sort_info_t is associated with a vector of samples of length
+ * (size), whose position begins at (*abspos) within the CD's stream
+ * of samples.  Only the range of samples between (sortlo, sorthi)
+ * will eventually be indexed for fast searching.  (sortlo, sorthi)
+ * are absolute sample positions.
+ *
+ * ???: Why is abspos a pointer?  Why not just store a copy?
+ *
+ * Note: size *must* be <= the size given to the preceding sort_alloc(),
+ * but no error checking is done here.
+ */
+
+void 
+sort_setup(sort_info_t *i, int16_t *vector, long int *abspos, 
+	   long int size, long int sortlo, long int sorthi)
+{
+  /* Reset the index if it has already been built.
+   */
+  if (i->sortbegin!=-1)
+    sort_unsortall(i);
+
+  i->vector=vector;
+  i->size=size;
+  i->abspos=abspos;
+
+  /* Convert the absolute (sortlo, sorthi) to offsets within the vector.
+   * Note that the index will not be built until sort_getmatch() is called.
+   * Here we're simply hanging on to the range to index until then.
+   */
+  i->lo = min(size, max(sortlo - *abspos, 0));
+  i->hi = max(0, min(sorthi - *abspos, size));
+}
+
+/* ===========================================================================
+ * sort_getmatch()
+ *
+ * This function returns a sort_link_t pointer which refers to the
+ * first sample equal to (value) in the vector.  It only searches for
+ * hits within (overlap) samples of (post), where (post) is an offset
+ * within the vector.  The caller can determine the position of the
+ * matched sample using ipos(sort_info *, sort_link *).
+ *
+ * This function returns NULL if no matches were found.
+ */
+
+sort_link_t *
+sort_getmatch(sort_info_t *i, long post, long overlap, int value)
+{
+  sort_link_t *ret;
+
+  /* If the vector hasn't been indexed yet, index it now.
+   */
+  if (i->sortbegin==-1)
+    sort_sort(i,i->lo,i->hi);
+  /* Now we reuse lo and hi */
+
+  /* We'll only return samples within (overlap) samples of (post).
+   * Clamp the boundaries to search to the boundaries of the array,
+   * convert the signed sample to an unsigned offset, and store the
+   * state so that future calls to sort_nextmatch do the right thing.
+   *
+   * Reusing lo and hi this way is awful.
+   */
+  post=max(0,min(i->size,post));
+  i->val=value+32768;
+  i->lo=max(0,post-overlap);       /* absolute position */
+  i->hi=min(i->size,post+overlap); /* absolute position */
+
+  /* Walk through the linked list of samples with this value, until
+   * we find the first one within the bounds specified.  If there
+   * aren't any, return NULL.
+   */
+  ret=i->head[i->val];
+
+  while (ret) {
+    /* ipos() calculates the offset (in terms of the original vector)
+     * of this hit.
+     */
+
+    if (ipos(i,ret)<i->lo) {
+      ret=ret->next;
+    } else {
+      if (ipos(i,ret)>=i->hi)
+	ret=NULL;
+      break;
+    }
+  }
+  /*i->head[i->val]=ret;*/
+  return(ret);
+}
+
+
+/* ===========================================================================
+ * sort_nextmatch()
+ *
+ * This function returns a sort_link_t pointer which refers to the next sample
+ * matching the criteria previously passed to sort_getmatch().  See
+ * sort_getmatch() for details.
+ *
+ * This function returns NULL if no further matches were found.
+ */
+
+sort_link_t *
+sort_nextmatch(sort_info_t *i, sort_link_t *prev)
+{
+  sort_link_t *ret=prev->next;
+
+  /* If there aren't any more hits, or we've passed the boundary requested
+   * of sort_getmatch(), we're done.
+   */
+  if (!ret || ipos(i,ret)>=i->hi)
+    return(NULL); 
+
+  return(ret);
+}
+
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/lib/paranoia/isort.h libcdio-c742eed/lib/paranoia/isort.h
--- libcdio-f9bd26c/lib/paranoia/isort.h	1970-01-01 09:00:00 +0900
+++ libcdio-c742eed/lib/paranoia/isort.h	2012-02-26 05:07:35 +0900
@@ -0,0 +1,161 @@
+/*
+  $Id: isort.h,v 1.6 2008/04/17 17:39:48 karl Exp $
+
+  Copyright (C) 2004, 2005, 2008 Rocky Bernstein <rocky@gnu.org>
+  Copyright (C) 1998 Monty xiphmont@mit.edu
+  
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _ISORT_H_
+#define _ISORT_H_
+
+typedef struct sort_link{
+  struct sort_link *next;
+} sort_link_t;
+
+typedef struct sort_info {
+  int16_t *vector;               /* vector (storage doesn't belong to us) */
+
+  long  *abspos;                 /* pointer for side effects */
+  long  size;                    /* vector size */
+
+  long  maxsize;                 /* maximum vector size */
+
+  long sortbegin;                /* range of contiguous sorted area */
+  long lo,hi;                    /* current post, overlap range */
+  int  val;                      /* ...and val */
+
+  /* sort structs */
+  sort_link_t **head;           /* sort buckets (65536) */
+
+  long *bucketusage;          /*  of used buckets (65536) */
+  long lastbucket;
+  sort_link_t *revindex;
+
+} sort_info_t;
+
+/*! ========================================================================
+ * sort_alloc()
+ *
+ * Allocates and initializes a new, empty sort_info object, which can
+ * be used to index up to (size) samples from a vector.
+ */
+extern sort_info_t *sort_alloc(long int size);
+
+/*! ========================================================================
+ * sort_unsortall() (internal)
+ *
+ * This function resets the index for further use with a different
+ * vector or range, without the overhead of an unnecessary free/alloc.
+ */
+extern void sort_unsortall(sort_info_t *i);
+
+/*! ========================================================================
+ * sort_setup()
+ *
+ * This function initializes a previously allocated sort_info_t.  The
+ * sort_info_t is associated with a vector of samples of length
+ * (size), whose position begins at (*abspos) within the CD's stream
+ * of samples.  Only the range of samples between (sortlo, sorthi)
+ * will eventually be indexed for fast searching.  (sortlo, sorthi)
+ * are absolute sample positions.
+ *
+ * ???: Why is abspos a pointer?  Why not just store a copy?
+ *
+ * Note: size *must* be <= the size given to the preceding sort_alloc(),
+ * but no error checking is done here.
+ */
+extern void sort_setup(sort_info_t *i, int16_t *vector, long int *abspos,
+		       long int size, long int sortlo, long int sorthi);
+
+/* =========================================================================
+ * sort_free()
+ *
+ * Releases all memory consumed by a sort_info object.
+ */
+extern void sort_free(sort_info_t *i);
+
+/*! ========================================================================
+ * sort_getmatch()
+ *
+ * This function returns a sort_link_t pointer which refers to the
+ * first sample equal to (value) in the vector.  It only searches for
+ * hits within (overlap) samples of (post), where (post) is an offset
+ * within the vector.  The caller can determine the position of the
+ * matched sample using ipos(sort_info *, sort_link *).
+ *
+ * This function returns NULL if no matches were found.
+ */
+extern sort_link_t *sort_getmatch(sort_info_t *i, long post, long overlap,
+				  int value);
+
+/*! ========================================================================
+ * sort_nextmatch()
+ *
+ * This function returns a sort_link_t pointer which refers to the
+ * next sample matching the criteria previously passed to
+ * sort_getmatch().  See sort_getmatch() for details.
+ *
+ * This function returns NULL if no further matches were found.
+ */
+extern sort_link_t *sort_nextmatch(sort_info_t *i, sort_link_t *prev);
+
+/* ===========================================================================
+ * is()
+ *
+ * This macro returns the size of the vector indexed by the given sort_info_t.
+ */
+#define is(i) (i->size)
+
+/* ===========================================================================
+ * ib()
+ *
+ * This macro returns the absolute position of the first sample in the vector
+ * indexed by the given sort_info_t.
+ */
+#define ib(i) (*i->abspos)
+
+/* ===========================================================================
+ * ie()
+ *
+ * This macro returns the absolute position of the sample after the last
+ * sample in the vector indexed by the given sort_info_t.
+ */
+#define ie(i) (i->size+*i->abspos)
+
+/* ===========================================================================
+ * iv()
+ *
+ * This macro returns the vector indexed by the given sort_info_t.
+ */
+#define iv(i) (i->vector)
+
+/* ===========================================================================
+ * ipos()
+ *
+ * This macro returns the relative position (offset) within the indexed vector
+ * at which the given match was found.
+ *
+ * It uses a little-known and frightening aspect of C pointer arithmetic:
+ * subtracting a pointer is not an arithmetic subtraction, but rather the
+ * additive inverse.  In other words, since
+ *   q     = p + n returns a pointer to the nth object in p,
+ *   q - p = p + n - p, and
+ *   q - p = n, not the difference of the two addresses.
+ */
+#define ipos(i,l) (l-i->revindex)
+
+#endif /* _ISORT_H_ */
+
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/lib/paranoia/libcdio_paranoia.sym libcdio-c742eed/lib/paranoia/libcdio_paranoia.sym
--- libcdio-f9bd26c/lib/paranoia/libcdio_paranoia.sym	1970-01-01 09:00:00 +0900
+++ libcdio-c742eed/lib/paranoia/libcdio_paranoia.sym	2012-02-26 05:07:35 +0900
@@ -0,0 +1,9 @@
+cdio_paranoia_init
+cdio_paranoia_free
+cdio_paranoia_modeset
+cdio_paranoia_seek
+cdio_paranoia_read
+cdio_paranoia_read_limited
+cdio_paranoia_overlapset
+cdio_paranoia_set_range
+paranoia_cb_mode2str
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/lib/paranoia/overlap.c libcdio-c742eed/lib/paranoia/overlap.c
--- libcdio-f9bd26c/lib/paranoia/overlap.c	1970-01-01 09:00:00 +0900
+++ libcdio-c742eed/lib/paranoia/overlap.c	2012-02-26 05:07:35 +0900
@@ -0,0 +1,255 @@
+/*
+  Copyright (C) 2004, 2005, 2008, 2011 Rocky Bernstein <rocky@gnu.org>
+  Copyright (C) 1998 Monty xiphmont@mit.edu
+  
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/***
+ *
+ * Statistic code and cache management for overlap settings
+ *
+ ***/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+# define __CDIO_CONFIG_H__ 1
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <stdio.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <cdio/paranoia.h>
+#include "p_block.h"
+#include "overlap.h"
+#include "isort.h"
+
+/**** Internal cache management *****************************************/
+
+void 
+paranoia_resetcache(cdrom_paranoia_t *p)
+{
+  c_block_t *c=c_first(p);
+  v_fragment_t *v;
+
+  while(c){
+    free_c_block(c);
+    c=c_first(p);
+  }
+
+  v=v_first(p);
+  while(v){
+    free_v_fragment(v);
+    v=v_first(p);
+  }
+}
+
+void 
+paranoia_resetall(cdrom_paranoia_t *p)
+{
+  p->root.returnedlimit=0;
+  p->dyndrift=0;
+  p->root.lastsector=0;
+
+  if(p->root.vector){
+    i_cblock_destructor(p->root.vector);
+    p->root.vector=NULL;
+  }
+
+  paranoia_resetcache(p);
+}
+
+void 
+i_paranoia_trim(cdrom_paranoia_t *p, long int beginword, long int endword)
+{
+  root_block *root=&(p->root);
+  if(root->vector!=NULL){
+    long target=beginword-MAX_SECTOR_OVERLAP*CD_FRAMEWORDS;
+    long rbegin=cb(root->vector);
+    long rend=ce(root->vector);
+
+    if(rbegin>beginword)
+      goto rootfree;
+    
+    if(rbegin+MAX_SECTOR_OVERLAP*CD_FRAMEWORDS<beginword){
+      if(target+MIN_WORDS_OVERLAP>rend)
+	goto rootfree;
+
+      {
+	long int offset=target-rbegin;
+	c_removef(root->vector,offset);
+      }
+    }
+
+    {
+      c_block_t *c=c_first(p);
+      while(c){
+	c_block_t *next=c_next(c);
+	if(ce(c)<beginword-MAX_SECTOR_OVERLAP*CD_FRAMEWORDS)
+	  free_c_block(c);
+	c=next;
+      }
+    }
+
+  }
+  return;
+  
+rootfree:
+
+  i_cblock_destructor(root->vector);
+  root->vector=NULL;
+  root->returnedlimit=-1;
+  root->lastsector=0;
+  
+}
+
+/**** Statistical and heuristic[al? :-] management ************************/
+
+/* ===========================================================================
+ * offset_adjust_settings (internal)
+ *
+ * This function is called by offset_add_value() every time 10 samples have
+ * been accumulated.  This function updates the internal statistics for
+ * paranoia (dynoverlap, dyndrift) that compensate for jitter and drift.
+ *
+ * (dynoverlap) influences how far stage 1 and stage 2 search for matching
+ * runs.  In low-jitter conditions, it will be very small (or even 0),
+ * narrowing our search.  In high-jitter conditions, it will be much larger,
+ * widening our search at the cost of speed.
+ *
+ * ???: To be studied further.
+ */
+void 
+offset_adjust_settings(cdrom_paranoia_t *p, 
+		       void(*callback)(long int, paranoia_cb_mode_t))
+{
+  if(p->stage2.offpoints>=10){
+    /* drift: look at the average offset value.  If it's over one
+       sector, frob it.  We just want a little hysteresis [sp?]*/
+    long av=(p->stage2.offpoints?p->stage2.offaccum/p->stage2.offpoints:0);
+    
+    if(abs(av)>p->dynoverlap/4){
+      av=(av/MIN_SECTOR_EPSILON)*MIN_SECTOR_EPSILON;
+      
+      if(callback)(*callback)(ce(p->root.vector),PARANOIA_CB_DRIFT);
+      p->dyndrift+=av;
+      
+      /* Adjust all the values in the cache otherwise we get a
+	 (potentially unstable) feedback loop */
+      {
+	c_block_t *c=c_first(p);
+	v_fragment_t *v=v_first(p);
+
+	while(v && v->one){
+	  /* safeguard beginning bounds case with a hammer */
+	  if(fb(v)<av || cb(v->one)<av){
+	    v->one=NULL;
+	  }else{
+	    fb(v)-=av;
+	  }
+	  v=v_next(v);
+	}
+	while(c){
+	  long adj=min(av,cb(c));
+	  c_set(c,cb(c)-adj);
+	  c=c_next(c);
+	}
+      }
+
+      p->stage2.offaccum=0;
+      p->stage2.offmin=0;
+      p->stage2.offmax=0;
+      p->stage2.offpoints=0;
+      p->stage2.newpoints=0;
+      p->stage2.offdiff=0;
+    }
+  }
+
+  if(p->stage1.offpoints>=10){
+    /* dynoverlap: we arbitrarily set it to 4x the running difference
+       value, unless min/max are more */
+
+    p->dynoverlap=(p->stage1.offpoints?p->stage1.offdiff/
+		   p->stage1.offpoints*3:CD_FRAMEWORDS);
+
+    if(p->dynoverlap<-p->stage1.offmin*1.5)
+      p->dynoverlap=-p->stage1.offmin*1.5;
+						     
+    if(p->dynoverlap<p->stage1.offmax*1.5)
+      p->dynoverlap=p->stage1.offmax*1.5;
+
+    if(p->dynoverlap<MIN_SECTOR_EPSILON)p->dynoverlap=MIN_SECTOR_EPSILON;
+    if(p->dynoverlap>MAX_SECTOR_OVERLAP*CD_FRAMEWORDS)
+      p->dynoverlap=MAX_SECTOR_OVERLAP*CD_FRAMEWORDS;
+    			     
+    if(callback)(*callback)(p->dynoverlap,PARANOIA_CB_OVERLAP);
+
+    if(p->stage1.offpoints>600){ /* bit of a bug; this routine is
+				    called too often due to the overlap 
+				    mesh alg we use in stage 1 */
+      p->stage1.offpoints/=1.2;
+      p->stage1.offaccum/=1.2;
+      p->stage1.offdiff/=1.2;
+    }
+    p->stage1.offmin=0;
+    p->stage1.offmax=0;
+    p->stage1.newpoints=0;
+  }
+}
+
+
+/* ===========================================================================
+ * offset_add_value (internal)
+ *
+ * This function adds the given jitter detected (value) to the statistics
+ * for the given stage (o).  It is called whenever jitter has been identified
+ * by stage 1 or 2.  After every 10 samples, we update the overall jitter-
+ * compensation settings (e.g. dynoverlap).  This allows us to narrow our
+ * search for matching runs (in both stages) in low-jitter conditions
+ * and also widen our search appropriately when there is jitter.
+ *
+ * ???BUG???:
+ * Note that there is a bug in the way that this is called by try_sort_sync().
+ * Silence looks like zero jitter, and dynoverlap may be incorrectly reduced
+ * when there's lots of silence but also jitter.
+ *
+ * See the bug notes in try_sort_sync() for details.
+ */
+void 
+offset_add_value(cdrom_paranoia_t *p,offsets *o,long value,
+		 void(*callback)(long int, paranoia_cb_mode_t))
+{
+  if(o->offpoints!=-1){
+
+    /* Track the average magnitude of jitter (in either direction) */
+    o->offdiff+=abs(value);
+    o->offpoints++;
+    o->newpoints++;
+
+    /* Track the net value of the jitter (to track drift) */
+    o->offaccum+=value;
+
+    /* Track the largest jitter we've encountered in each direction */
+    if(value<o->offmin)o->offmin=value;
+    if(value>o->offmax)o->offmax=value;
+
+    /* After 10 samples, update dynoverlap, etc. */
+    if(o->newpoints>=10)offset_adjust_settings(p,callback);
+  }
+}
+
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/lib/paranoia/overlap.h libcdio-c742eed/lib/paranoia/overlap.h
--- libcdio-f9bd26c/lib/paranoia/overlap.h	1970-01-01 09:00:00 +0900
+++ libcdio-c742eed/lib/paranoia/overlap.h	2012-02-26 05:07:35 +0900
@@ -0,0 +1,33 @@
+/*
+  $Id: overlap.h,v 1.2 2008/04/17 17:39:48 karl Exp $
+
+  Copyright (C) 2004, 2008 Rocky Bernstein <rocky@gnu.org>
+  Copyright (C) 1998 Monty xiphmont@mit.edu
+  
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _OVERLAP_H_
+#define _OVERLAP_H_
+
+extern void offset_add_value(cdrom_paranoia_t *p,offsets *o,long value,
+			     void(*callback)(long int, paranoia_cb_mode_t));
+extern void offset_clear_settings(offsets *o);
+extern void offset_adjust_settings(cdrom_paranoia_t *p, 
+				   void(*callback)(long, paranoia_cb_mode_t));
+extern void i_paranoia_trim(cdrom_paranoia_t *p,long beginword,long endword);
+extern void paranoia_resetall(cdrom_paranoia_t *p);
+extern void paranoia_resetcache(cdrom_paranoia_t *p);
+
+#endif /*_OVERLAP_H_*/
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/lib/paranoia/p_block.c libcdio-c742eed/lib/paranoia/p_block.c
--- libcdio-f9bd26c/lib/paranoia/p_block.c	1970-01-01 09:00:00 +0900
+++ libcdio-c742eed/lib/paranoia/p_block.c	2012-02-26 05:07:35 +0900
@@ -0,0 +1,458 @@
+/*
+  Copyright (C) 2004, 2005, 2007, 2008 Rocky Bernstein <rocky@gnu.org>
+  Copyright (C) 1998 Monty xiphmont@mit.edu
+
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+# define __CDIO_CONFIG_H__ 1
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <stdio.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <limits.h>
+#include "p_block.h"
+#include <cdio/cdda.h>
+#include <cdio/paranoia.h>
+
+linked_list_t *new_list(void *(*newp)(void),void (*freep)(void *))
+{
+  linked_list_t *ret=calloc(1,sizeof(linked_list_t));
+  ret->new_poly=newp;
+  ret->free_poly=freep;
+  return(ret);
+}
+
+linked_element *add_elem(linked_list_t *l,void *elem)
+{
+
+  linked_element *ret=calloc(1,sizeof(linked_element));
+  ret->stamp=l->current++;
+  ret->ptr=elem;
+  ret->list=l;
+
+  if(l->head)
+    l->head->prev=ret;
+  else
+    l->tail=ret;    
+  ret->next=l->head;
+  ret->prev=NULL;
+  l->head=ret;
+  l->active++;
+
+  return(ret);
+}
+
+linked_element *
+new_elem(linked_list_t *p_list)
+{
+  void *p_new=p_list->new_poly();
+  return(add_elem(p_list,p_new));
+}
+
+void 
+free_elem(linked_element *e,int free_ptr)
+{
+  linked_list_t *l=e->list;
+  if(free_ptr)l->free_poly(e->ptr);
+
+  if(e==l->head)
+    l->head=e->next;
+  if(e==l->tail)
+    l->tail=e->prev;
+    
+  if(e->prev)
+    e->prev->next=e->next;
+  if(e->next)
+    e->next->prev=e->prev;
+
+  l->active--;
+  free(e);
+} 
+
+void 
+free_list(linked_list_t *list,int free_ptr)
+{
+  while(list->head)
+    free_elem(list->head,free_ptr);
+  free(list);
+}
+
+void *get_elem(linked_element *e)
+{
+  return(e->ptr);
+}
+
+linked_list_t *copy_list(linked_list_t *list)
+{
+  linked_list_t *new=new_list(list->new_poly,list->free_poly);
+  linked_element *i=list->tail;
+
+  while(i){
+    add_elem(new,i->ptr);
+    i=i->prev;
+  }
+  return(new);
+}
+
+/**** C_block stuff ******************************************************/
+
+static c_block_t *
+i_cblock_constructor(cdrom_paranoia_t *p)
+{
+  c_block_t *ret=calloc(1,sizeof(c_block_t));
+  return(ret);
+}
+
+void 
+i_cblock_destructor(c_block_t *c)
+{
+  if(c){
+    if(c->vector)free(c->vector);
+    if(c->flags)free(c->flags);
+    c->e=NULL;
+    free(c);
+  }
+}
+
+c_block_t *
+new_c_block(cdrom_paranoia_t *p)
+{
+  linked_element *e=new_elem(p->cache);
+  c_block_t *c=e->ptr;
+  c->e=e;
+  c->p=p;
+  return(c);
+}
+
+void free_c_block(c_block_t *c)
+{
+  /* also rid ourselves of v_fragments that reference this block */
+  v_fragment_t *v=v_first(c->p);
+  
+  while(v){
+    v_fragment_t *next=v_next(v);
+    if(v->one==c)free_v_fragment(v);
+    v=next;
+  }    
+
+  free_elem(c->e,1);
+}
+
+static v_fragment_t *
+i_vfragment_constructor(void)
+{
+  v_fragment_t *ret=calloc(1,sizeof(v_fragment_t));
+  return(ret);
+}
+
+static void 
+i_v_fragment_destructor(v_fragment_t *v)
+{
+  free(v);
+}
+
+v_fragment_t *
+new_v_fragment(cdrom_paranoia_t *p, c_block_t *one,
+	       long int begin, long int end, int last)
+{
+  linked_element *e=new_elem(p->fragments);
+  v_fragment_t *b=e->ptr;
+  
+  b->e=e;
+  b->p=p;
+
+  b->one=one;
+  b->begin=begin;
+  b->vector=one->vector+begin-one->begin;
+  b->size=end-begin;
+  b->lastsector=last;
+
+#if TRACE_PARANOIA
+  fprintf(stderr, "- Verified [%ld-%ld] (0x%04X...0x%04X)%s\n",
+	  begin, end,
+	  b->vector[0]&0xFFFF, b->vector[b->size-1]&0xFFFF,
+	  last ? " *" : "");
+#endif
+
+  return(b);
+}
+
+void free_v_fragment(v_fragment_t *v)
+{
+  free_elem(v->e,1);
+}
+
+c_block_t *
+c_first(cdrom_paranoia_t *p)
+{
+  if(p->cache->head)
+    return(p->cache->head->ptr);
+  return(NULL);
+}
+
+c_block_t *
+c_last(cdrom_paranoia_t *p)
+{
+  if(p->cache->tail)
+    return(p->cache->tail->ptr);
+  return(NULL);
+}
+
+c_block_t *
+c_next(c_block_t *c)
+{
+  if(c->e->next)
+    return(c->e->next->ptr);
+  return(NULL);
+}
+
+c_block_t *
+c_prev(c_block_t *c)
+{
+  if(c->e->prev)
+    return(c->e->prev->ptr);
+  return(NULL);
+}
+
+v_fragment_t *
+v_first(cdrom_paranoia_t *p)
+{
+  if(p->fragments->head){
+    return(p->fragments->head->ptr);
+  }
+  return(NULL);
+}
+
+v_fragment_t *
+v_last(cdrom_paranoia_t *p)
+{
+  if(p->fragments->tail)
+    return(p->fragments->tail->ptr);
+  return(NULL);
+}
+
+v_fragment_t *
+v_next(v_fragment_t *v)
+{
+  if(v->e->next)
+    return(v->e->next->ptr);
+  return(NULL);
+}
+
+v_fragment_t *
+v_prev(v_fragment_t *v)
+{
+  if(v->e->prev)
+    return(v->e->prev->ptr);
+  return(NULL);
+}
+
+void 
+recover_cache(cdrom_paranoia_t *p)
+{
+  linked_list_t *l=p->cache;
+
+  /* Are we at/over our allowed cache size? */
+  while(l->active>p->cache_limit)
+    /* cull from the tail of the list */
+    free_c_block(c_last(p));
+
+}
+
+int16_t *
+v_buffer(v_fragment_t *v)
+{
+  if(!v->one)return(NULL);
+  if(!cv(v->one))return(NULL);
+  return(v->vector);
+}
+
+/* alloc a c_block not on a cache list */
+c_block_t *
+c_alloc(int16_t *vector, long begin, long size)
+{
+  c_block_t *c=calloc(1,sizeof(c_block_t));
+  c->vector=vector;
+  c->begin=begin;
+  c->size=size;
+  return(c);
+}
+
+void c_set(c_block_t *v,long begin){
+  v->begin=begin;
+}
+
+/* pos here is vector position from zero */
+void 
+c_insert(c_block_t *v,long pos,int16_t *b,long size)
+{
+  int vs=cs(v);
+  if(pos<0 || pos>vs)return;
+
+  if(v->vector) {
+    v->vector = realloc(v->vector,sizeof(int16_t)*(size+vs));
+  } else {
+    v->vector = calloc(1, sizeof(int16_t)*size);
+  }
+  
+  if(pos<vs)memmove(v->vector+pos+size,v->vector+pos,
+		       (vs-pos)*sizeof(int16_t));
+  memcpy(v->vector+pos,b,size*sizeof(int16_t));
+
+  v->size+=size;
+}
+
+void 
+c_remove(c_block_t *v, long cutpos, long cutsize)
+{
+  int vs=cs(v);
+  if(cutpos<0 || cutpos>vs)return;
+  if(cutpos+cutsize>vs)cutsize=vs-cutpos;
+  if(cutsize<0)cutsize=vs-cutpos;
+  if(cutsize<1)return;
+
+  memmove(v->vector+cutpos,v->vector+cutpos+cutsize,
+            (vs-cutpos-cutsize)*sizeof(int16_t));
+  
+  v->size-=cutsize;
+}
+
+void 
+c_overwrite(c_block_t *v,long pos,int16_t *b,long size)
+{
+  int vs=cs(v);
+
+  if(pos<0)return;
+  if(pos+size>vs)size=vs-pos;
+
+  memcpy(v->vector+pos,b,size*sizeof(int16_t));
+}
+
+void 
+c_append(c_block_t *v, int16_t *vector, long size)
+{
+  int vs=cs(v);
+
+  /* update the vector */
+  if(v->vector)
+    v->vector=realloc(v->vector,sizeof(int16_t)*(size+vs));
+  else {
+    v->vector=calloc(1, sizeof(int16_t)*size);
+  }
+  memcpy(v->vector+vs,vector,sizeof(int16_t)*size);
+
+  v->size+=size;
+}
+
+void 
+c_removef(c_block_t *v, long cut)
+{
+  c_remove(v,0,cut);
+  v->begin+=cut;
+}
+
+
+
+/**** Initialization *************************************************/
+
+/*!  Get the beginning and ending sector bounds given cursor position.
+
+  There are a couple of subtle differences between this and the
+  cdda_firsttrack_sector and cdda_lasttrack_sector. If the cursor is
+  an a sector later than cdda_firsttrack_sector, that sectur will be
+  used. As for the difference between cdda_lasttrack_sector, if the CD
+  is mixed and there is a data track after the cursor but before the
+  last audio track, the end of the audio sector before that is used.
+*/
+void 
+i_paranoia_firstlast(cdrom_paranoia_t *p)
+{
+  track_t i, j;
+  cdrom_drive_t *d=p->d;
+  const track_t i_first_track = cdio_get_first_track_num(d->p_cdio);
+  const track_t i_last_track  = cdio_get_last_track_num(d->p_cdio);
+
+  p->current_lastsector = p->current_firstsector = -1;
+
+  i = cdda_sector_gettrack(d, p->cursor); 
+
+  if ( CDIO_INVALID_TRACK != i ) {
+    if ( 0 == i ) i++;
+    j = i;
+    /* In the below loops, We assume the cursor already is on an audio
+       sector. Not sure if this is correct if p->cursor is in the pregap
+       before the first track.
+    */
+    for ( ; i < i_last_track; i++)
+      if( !cdda_track_audiop(d,i) ) {
+	p->current_lastsector=cdda_track_lastsector(d,i-1);
+	break;
+      }
+
+    i = j;
+    for ( ; i >= i_first_track; i-- )
+      if( !cdda_track_audiop(d,i) ) {
+	p->current_firstsector = cdda_track_firstsector(d,i+1);
+	break;
+      }
+  }
+  
+  if (p->current_lastsector == -1)
+    p->current_lastsector = cdda_disc_lastsector(d);
+
+  if(p->current_firstsector == -1)
+    p->current_firstsector = cdda_disc_firstsector(d);
+
+}
+
+cdrom_paranoia_t *
+paranoia_init(cdrom_drive_t *d)
+{
+  cdrom_paranoia_t *p=calloc(1,sizeof(cdrom_paranoia_t));
+
+  p->cache=new_list((void *)&i_cblock_constructor,
+		    (void *)&i_cblock_destructor);
+
+  p->fragments=new_list((void *)&i_vfragment_constructor,
+			(void *)&i_v_fragment_destructor);
+
+  p->readahead=150;
+  p->sortcache=sort_alloc(p->readahead*CD_FRAMEWORDS);
+  p->d=d;
+  p->dynoverlap=MAX_SECTOR_OVERLAP*CD_FRAMEWORDS;
+  p->cache_limit=JIGGLE_MODULO;
+  p->enable=PARANOIA_MODE_FULL;
+  p->cursor=cdda_disc_firstsector(d);
+  p->lastread=LONG_MAX;
+
+  /* One last one... in case data and audio tracks are mixed... */
+  i_paranoia_firstlast(p);
+
+  return(p);
+}
+
+void paranoia_set_range(cdrom_paranoia_t *p, long start, long end)
+{
+  p->cursor = start;
+  p->current_firstsector = start;
+  p->current_lastsector = end;
+}
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/lib/paranoia/p_block.h libcdio-c742eed/lib/paranoia/p_block.h
--- libcdio-f9bd26c/lib/paranoia/p_block.h	1970-01-01 09:00:00 +0900
+++ libcdio-c742eed/lib/paranoia/p_block.h	2012-02-26 05:07:35 +0900
@@ -0,0 +1,213 @@
+/*
+  $Id: p_block.h,v 1.6 2008/04/17 17:39:48 karl Exp $
+
+  Copyright (C) 2004, 2005, 2008 Rocky Bernstein <rocky@gnu.org>
+  Copyright (C) by Monty (xiphmont@mit.edu)
+
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _P_BLOCK_H_
+#define _P_BLOCK_H_
+
+#include <cdio/paranoia.h>
+#include <cdio/cdda.h>
+
+#define MIN_WORDS_OVERLAP    64     /* 16 bit words */
+#define MIN_WORDS_SEARCH     64     /* 16 bit words */
+#define MIN_WORDS_RIFT       16     /* 16 bit words */
+#define MAX_SECTOR_OVERLAP   32     /* sectors */
+#define MIN_SECTOR_EPSILON  128     /* words */
+#define MIN_SECTOR_BACKUP    16     /* sectors */
+#define JIGGLE_MODULO        15     /* sectors */
+#define MIN_SILENCE_BOUNDARY 1024   /* 16 bit words */
+
+#define min(x,y) ((x)>(y)?(y):(x))
+#define max(x,y) ((x)<(y)?(y):(x))
+
+#include "isort.h"
+
+typedef struct {
+  /* linked list */
+  struct linked_element *head;
+  struct linked_element *tail;
+
+  void *(*new_poly)();
+  void (*free_poly)(void *poly);
+  long current;
+  long active;
+
+} linked_list_t;
+
+typedef struct linked_element{
+  void *ptr;
+  struct linked_element *prev;
+  struct linked_element *next;
+  
+  linked_list_t *list;
+  int stamp;
+} linked_element;
+
+extern linked_list_t *new_list(void *(*new_fn)(void),void (*free)(void *));
+extern linked_element *new_elem(linked_list_t *list);
+extern linked_element *add_elem(linked_list_t *list,void *elem);
+extern void free_list(linked_list_t *list,int free_ptr); /* unlink or free */
+extern void free_elem(linked_element *e,int free_ptr); /* unlink or free */
+extern void *get_elem(linked_element *e);
+
+/* This is a shallow copy; it doesn't copy contained structures */
+extern linked_list_t *copy_list(linked_list_t *p_list); 
+
+typedef struct c_block {
+  /* The buffer */
+  int16_t *vector;
+  long begin;
+  long size;
+
+  /* auxiliary support structures */
+  unsigned char *flags; /* 1    known boundaries in read data
+			   2    known blanked data
+			   4    matched sample
+			   8    reserved
+			   16   reserved
+			   32   reserved
+			   64   reserved
+			   128  reserved
+			 */
+
+  /* end of session cases */
+  long lastsector;
+  cdrom_paranoia_t *p;
+  struct linked_element *e;
+
+} c_block_t;
+
+extern void free_c_block(c_block_t *c);
+extern void i_cblock_destructor(c_block_t *c);
+extern c_block_t *new_c_block(cdrom_paranoia_t *p);
+
+typedef struct v_fragment_s {
+  c_block_t *one;
+
+  long begin;
+  long size;
+  int16_t *vector;
+
+  /* end of session cases */
+  long lastsector;
+
+  /* linked list */
+  cdrom_paranoia_t *p;
+  struct linked_element *e;
+
+} v_fragment_t;
+
+extern void free_v_fragment(v_fragment_t *c);
+extern v_fragment_t *new_v_fragment(cdrom_paranoia_t *p, c_block_t *one,
+				  long int begin, long int end, 
+				  int lastsector);
+extern int16_t *v_buffer(v_fragment_t *v);
+
+extern c_block_t *c_first(cdrom_paranoia_t *p);
+extern c_block_t *c_last(cdrom_paranoia_t *p);
+extern c_block_t *c_next(c_block_t *c);
+extern c_block_t *c_prev(c_block_t *c);
+
+extern v_fragment_t *v_first(cdrom_paranoia_t *p);
+extern v_fragment_t *v_last(cdrom_paranoia_t *p);
+extern v_fragment_t *v_next(v_fragment_t *v);
+extern v_fragment_t *v_prev(v_fragment_t *v);
+
+typedef struct root_block{
+  long returnedlimit;   
+  long lastsector;
+  cdrom_paranoia_t *p;
+
+  c_block_t *vector; /* doesn't use any sorting */
+  int silenceflag;
+  long silencebegin;
+} root_block;
+
+typedef struct offsets{
+  
+  long offpoints;
+  long newpoints;
+  long offaccum;
+  long offdiff;
+  long offmin;
+  long offmax;
+
+} offsets;
+
+struct cdrom_paranoia_s {
+  cdrom_drive_t *d;
+
+  root_block root;           /* verified/reconstructed cached data */
+  linked_list_t *cache;      /* our data as read from the cdrom */
+  long int cache_limit;
+  linked_list_t *fragments;  /* fragments of blocks that have been 'verified' */
+  sort_info_t *sortcache;
+
+  int readahead;             /* sectors of readahead in each readop */
+  int jitter;           
+  long lastread;
+
+  paranoia_cb_mode_t enable;
+  long int cursor;
+  long int current_lastsector;
+  long int current_firstsector;
+
+  /* statistics for drift/overlap */
+  struct offsets stage1;
+  struct offsets stage2;
+
+  long dynoverlap;
+  long dyndrift;
+
+  /* statistics for verification */
+
+};
+
+extern c_block_t *c_alloc(int16_t *vector,long begin,long size);
+extern void c_set(c_block_t *v,long begin);
+extern void c_insert(c_block_t *v,long pos,int16_t *b,long size);
+extern void c_remove(c_block_t *v,long cutpos,long cutsize);
+extern void c_overwrite(c_block_t *v,long pos,int16_t *b,long size);
+extern void c_append(c_block_t *v, int16_t *vector, long size);
+extern void c_removef(c_block_t *v, long cut);
+
+#define ce(v) (v->begin+v->size)
+#define cb(v) (v->begin)
+#define cs(v) (v->size)
+
+/* pos here is vector position from zero */
+
+extern void recover_cache(cdrom_paranoia_t *p);
+extern void i_paranoia_firstlast(cdrom_paranoia_t *p);
+
+#define cv(c) (c->vector)
+
+#define fe(f) (f->begin+f->size)
+#define fb(f) (f->begin)
+#define fs(f) (f->size)
+#define fv(f) (v_buffer(f))
+
+#ifndef DO_NOT_WANT_PARANOIA_COMPATIBILITY
+/** For compatibility with good ol' paranoia */
+#define linked_list linked_list_t
+#endif /*DO_NOT_WANT_PARANOIA_COMPATIBILITY*/
+
+#define CDP_COMPILE
+#endif /*_P_BLOCK_H_*/
+
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/lib/paranoia/paranoia.c libcdio-c742eed/lib/paranoia/paranoia.c
--- libcdio-f9bd26c/lib/paranoia/paranoia.c	1970-01-01 09:00:00 +0900
+++ libcdio-c742eed/lib/paranoia/paranoia.c	2012-02-26 05:07:35 +0900
@@ -0,0 +1,3024 @@
+/*
+  Copyright (C) 2004, 2005, 2006, 2008, 2011 Rocky Bernstein <rocky@gnu.org>
+  Copyright (C) 1998 Monty xiphmont@mit.edu
+  
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/***
+ * Toplevel file for the paranoia abstraction over the cdda lib 
+ *
+ ***/
+
+/* immediate todo:: */
+/* Allow disabling of root fixups? */ 
+/* Dupe bytes are creeping into cases that require greater overlap
+   than a single fragment can provide.  We need to check against a
+   larger area* (+/-32 sectors of root?) to better eliminate
+   dupes. Of course this leads to other problems... Is it actually a
+   practically solvable problem? */
+/* Bimodal overlap distributions break us. */
+/* scratch detection/tolerance not implemented yet */
+
+/***************************************************************
+
+  Da new shtick: verification now a two-step assymetric process.
+  
+  A single 'verified/reconstructed' data segment cache, and then the
+  multiple fragment cache 
+
+  verify a newly read block against previous blocks; do it only this
+  once. We maintain a list of 'verified sections' from these matches.
+
+  We then glom these verified areas into a new data buffer.
+  Defragmentation fixups are allowed here alone.
+
+  We also now track where read boundaries actually happened; do not
+  verify across matching boundaries.
+
+  **************************************************************/
+
+/***************************************************************
+
+  Silence.  "It's BAAAAAAaaack."
+
+  audio is now treated as great continents of values floating on a
+  mantle of molten silence.  Silence is not handled by basic
+  verification at all; we simply anchor sections of nonzero audio to a
+  position and fill in everything else as silence.  We also note the
+  audio that interfaces with silence; an edge must be 'wet'.
+
+  **************************************************************/
+
+/* ===========================================================================
+ * Let's translate the above vivid metaphor into something a mere mortal
+ * can understand:
+ *
+ * Non-silent audio is "solid."  Silent audio is "wet" and fluid.  The reason
+ * to treat silence as fluid is that if there's a long enough span of
+ * silence, we can't reliably detect jitter or dropped samples within that
+ * span (since all silence looks alike).  Non-silent audio, on the other
+ * hand, is distinctive and can be reliably reassembled.
+ *
+ * So we treat long spans of silence specially.  We only consider an edge
+ * of a non-silent region ("continent" or "island") to be "wet" if it borders
+ * a long span of silence.  Short spans of silence are merely damp and can
+ * be reliably placed within a continent.
+ *
+ * We position ("anchor") the non-silent regions somewhat arbitrarily (since
+ * they may be jittered and we have no way to verify their exact position),
+ * and fill the intervening space with silence.
+ *
+ * See i_silence_match() for the gory details.
+ * ===========================================================================
+ */
+
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+# define __CDIO_CONFIG_H__ 1
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <unistd.h>
+#include <stdio.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <math.h>
+#include <cdio/cdda.h>
+#include "../cdda_interface/smallft.h"
+#include "p_block.h"
+#include <cdio/paranoia.h>
+#include "overlap.h"
+#include "gap.h"
+#include "isort.h"
+
+const char *paranoia_cb_mode2str[] = {
+  "read",
+  "verify",
+  "fixup edge",
+  "fixup atom",
+  "scratch",
+  "repair",
+  "skip",
+  "drift",
+  "backoff",
+  "overlap",
+  "fixup dropped",
+  "fixup duplicated",
+  "read error"
+};
+
+/** The below variables are trickery to force the above enum symbol
+    values to be recorded in debug symbol tables. They are used to
+    allow one to refer to the enumeration value names in the typedefs
+    above in a debugger and debugger expressions
+*/
+
+paranoia_mode_t    debug_paranoia_mode;
+paranoia_cb_mode_t debug_paranoia_cb_mode;
+
+static inline long 
+re(root_block *root)
+{
+  if (!root)return(-1);
+  if (!root->vector)return(-1);
+  return(ce(root->vector));
+}
+
+static inline long 
+rb(root_block *root)
+{
+  if (!root)return(-1);
+  if (!root->vector)return(-1);
+  return(cb(root->vector));
+}
+
+static inline 
+long rs(root_block *root)
+{
+  if (!root)return(-1);
+  if (!root->vector)return(-1);
+  return(cs(root->vector));
+}
+
+static inline int16_t *
+rv(root_block *root){
+  if (!root)return(NULL);
+  if (!root->vector)return(NULL);
+  return(cv(root->vector));
+}
+
+#define rc(r) (r->vector)
+
+/** 
+    Flags indicating the status of a read samples.
+
+    Imagine the below enumeration values are #defines to be used in a
+    bitmask rather than distinct values of an enum.
+
+    The variable part of the declaration is trickery to force the enum
+    symbol values to be recorded in debug symbol tables. They are used
+    to allow one refer to the enumeration value names in a debugger
+    and in debugger expressions.
+*/
+enum  {
+  FLAGS_EDGE    =0x1, /**< first/last N words of frame */
+  FLAGS_UNREAD  =0x2, /**< unread, hence missing and unmatchable */
+  FLAGS_VERIFIED=0x4  /**< block read and verified */
+} paranoia_read_flags;
+
+
+/**** matching and analysis code *****************************************/
+
+/* ===========================================================================
+ * i_paranoia_overlap() (internal)
+ *
+ * This function is called when buffA[offsetA] == buffB[offsetB].  This
+ * function searches backward and forward to see how many consecutive
+ * samples also match.
+ *
+ * This function is called by do_const_sync() when we're not doing any
+ * verification.  Its more complicated sibling is i_paranoia_overlap2.
+ *
+ * This function returns the number of consecutive matching samples.
+ * If (ret_begin) or (ret_end) are not NULL, it fills them with the
+ * offsets of the first and last matching samples in A.
+ */
+static inline long 
+i_paranoia_overlap(int16_t *buffA,int16_t *buffB,
+		   long offsetA, long offsetB,
+		   long sizeA,long sizeB,
+		   long *ret_begin, long *ret_end)
+{
+  long beginA=offsetA,endA=offsetA;
+  long beginB=offsetB,endB=offsetB;
+
+  /* Scan backward to extend the matching run in that direction. */
+  for(; beginA>=0 && beginB>=0; beginA--,beginB--)
+    if (buffA[beginA] != buffB[beginB]) break;
+  beginA++;
+  beginB++;
+
+  /* Scan forward to extend the matching run in that direction. */
+  for(; endA<sizeA && endB<sizeB; endA++,endB++)
+    if (buffA[endA] != buffB[endB]) break;
+
+  /* Return the result of our search. */
+  if (ret_begin) *ret_begin = beginA;
+  if (ret_end) *ret_end = endA;
+  return (endA-beginA);
+}
+
+
+/* ===========================================================================
+ * i_paranoia_overlap2() (internal)
+ *
+ * This function is called when buffA[offsetA] == buffB[offsetB].  This
+ * function searches backward and forward to see how many consecutive
+ * samples also match.
+ *
+ * This function is called by do_const_sync() when we're verifying the
+ * data coming off the CD.  Its less complicated sibling is
+ * i_paranoia_overlap, which is a good place to look to see the simplest
+ * outline of how this function works.
+ *
+ * This function returns the number of consecutive matching samples.
+ * If (ret_begin) or (ret_end) are not NULL, it fills them with the
+ * offsets of the first and last matching samples in A.
+ */
+static inline long 
+i_paranoia_overlap2(int16_t *buffA,int16_t *buffB,
+		    unsigned char *flagsA, unsigned char *flagsB,
+		    long offsetA, long offsetB,
+		    long sizeA,long sizeB,
+		    long *ret_begin, long *ret_end)
+{
+  long beginA=offsetA, endA=offsetA;
+  long beginB=offsetB, endB=offsetB;
+  
+  /* Scan backward to extend the matching run in that direction. */
+  for (; beginA>=0 && beginB>=0; beginA--,beginB--) {
+    if (buffA[beginA] != buffB[beginB]) break;
+
+    /* don't allow matching across matching sector boundaries */
+    /* Stop if both samples were at the edges of a low-level read.
+     * ???: What implications does this have?
+     * ???: Why do we include the first sample for which this is true?
+     */
+    if ((flagsA[beginA]&flagsB[beginB]&FLAGS_EDGE)) {
+      beginA--;
+      beginB--;
+      break;
+    }
+
+    /* don't allow matching through known missing data */
+    if ((flagsA[beginA]&FLAGS_UNREAD) || (flagsB[beginB]&FLAGS_UNREAD))
+      break;
+  }
+  beginA++;
+  beginB++;
+  
+  /* Scan forward to extend the matching run in that direction. */
+  for (; endA<sizeA && endB<sizeB; endA++,endB++) {
+    if (buffA[endA] != buffB[endB]) break;
+
+    /* don't allow matching across matching sector boundaries */
+    /* Stop if both samples were at the edges of a low-level read.
+     * ???: What implications does this have?
+     * ???: Why do we not stop if endA == beginA?
+     */
+    if ((flagsA[endA]&flagsB[endB]&FLAGS_EDGE) && endA!=beginA){
+      break;
+    }
+
+    /* don't allow matching through known missing data */
+    if ((flagsA[endA]&FLAGS_UNREAD) || (flagsB[endB]&FLAGS_UNREAD))
+      break;
+  }
+
+  /* Return the result of our search. */
+  if (ret_begin) *ret_begin = beginA;
+  if (ret_end) *ret_end = endA;
+  return (endA-beginA);
+}
+
+
+/* ===========================================================================
+ * do_const_sync() (internal)
+ *
+ * This function is called when samples A[posA] == B[posB].  It tries to
+ * build a matching run from that point, looking forward and backward to
+ * see how many consecutive samples match.  Since the starting samples
+ * might only be coincidentally identical, we only consider the run to
+ * be a true match if it's longer than MIN_WORDS_SEARCH.
+ *
+ * This function returns the length of the run if a matching run was found,
+ * or 0 otherwise.  If a matching run was found, (begin) and (end) are set
+ * to the absolute positions of the beginning and ending samples of the
+ * run in A, and (offset) is set to the jitter between the c_blocks.
+ * (I.e., offset indicates the distance between what A considers sample N
+ * on the CD and what B considers sample N.)
+ */
+static inline long int 
+do_const_sync(c_block_t *A,
+	      sort_info_t *B, unsigned char *flagB,
+	      long posA, long posB,
+	      long *begin, long *end, long *offset)
+{
+  unsigned char *flagA=A->flags;
+  long ret=0;
+
+  /* If we're doing any verification whatsoever, we have flags in stage
+   * 1, and will take them into account.  Otherwise (e.g. in stage 2),
+   * we just do the simple equality test for samples on both sides of
+   * the initial match.
+   */
+  if (flagB==NULL)
+    ret=i_paranoia_overlap(cv(A), iv(B), posA, posB,
+			   cs(A), is(B), begin, end);
+  else
+    if ((flagB[posB]&FLAGS_UNREAD)==0)
+      ret=i_paranoia_overlap2(cv(A), iv(B), flagA, flagB, 
+			      posA, posB, cs(A), is(B),
+			      begin, end);
+	
+  /* Small matching runs could just be coincidental.  We only consider this
+   * a real match if it's long enough.
+   */
+  if (ret > MIN_WORDS_SEARCH) {
+    *offset=+(posA+cb(A))-(posB+ib(B));
+
+    /* Note that try_sort_sync()'s swaps A & B when it calls this function,
+     * so while we adjust begin & end to be relative to A here, that means
+     * it's relative to B in try_sort_sync().
+     */
+    *begin+=cb(A);
+    *end+=cb(A);
+    return(ret);
+  }
+  
+  return(0);
+}
+
+
+/* ===========================================================================
+ * try_sort_sync() (internal)
+ *
+ * Starting from the sample in B with the absolute position (post), look
+ * for a matching run in A.  This search will look in A for a first
+ * matching sample within (p->dynoverlap) samples around (post).  If it
+ * finds one, it will then determine how many consecutive samples match
+ * both A and B from that point, looking backwards and forwards.  If
+ * this search produces a matching run longer than MIN_WORDS_SEARCH, we
+ * consider it a match.
+ *
+ * When used by stage 1, the "post" is planted with respect to the old
+ * c_block being compare to the new c_block.  In stage 2, the "post" is
+ * planted with respect to the verified root.
+ *
+ * This function returns 1 if a match is found and 0 if not.  When a match
+ * is found, (begin) and (end) are set to the boundaries of the run, and
+ * (offset) is set to the difference in position of the run in A and B.
+ * (begin) and (end) are the absolute positions of the samples in
+ * B.  (offset) transforms A to B's frame of reference.  I.e., an offset of
+ * 2 would mean that A's absolute 3 is equivalent to B's 5.
+ */
+
+/* post is w.r.t. B.  in stage one, we post from old.  In stage 2 we
+   post from root. Begin, end, offset count from B's frame of
+   reference */
+
+static inline long int 
+try_sort_sync(cdrom_paranoia_t *p,
+	      sort_info_t *A, unsigned char *Aflags,
+	      c_block_t *B,
+	      long int post,
+	      long int *begin,
+	      long int *end,
+	      long *offset,
+	      void (*callback)(long int, paranoia_cb_mode_t))
+{
+  
+  long int dynoverlap=p->dynoverlap;
+  sort_link_t *ptr=NULL;
+  unsigned char *Bflags=B->flags;
+
+  /* block flag matches FLAGS_UNREAD (and hence unmatchable) */
+  if (Bflags==NULL || (Bflags[post-cb(B)]&FLAGS_UNREAD)==0){
+    /* always try absolute offset zero first! */
+    {
+      long zeropos=post-ib(A);
+      if (zeropos>=0 && zeropos<is(A)) {
+
+	/* Before we bother with the search for a matching samples,
+	 * we check the simple case.  If there's no jitter at all
+	 * (i.e. the absolute positions of A's and B's samples are
+	 * consistent), A's sample at (post) should be identical
+	 * to B's sample at the same position.
+	 */
+	if ( cv(B)[post-cb(B)] == iv(A)[zeropos] ) {
+
+	  /* The first sample matched, now try to grow the matching run
+	   * in both directions.  We only consider it a match if more
+	   * than MIN_WORDS_SEARCH consecutive samples match.
+	   */
+	  if (do_const_sync(B, A, Aflags,
+			    post-cb(B), zeropos,
+			    begin, end, offset) ) {
+
+	    /* ???BUG??? Jitter cannot be accurately detected when there are
+	     * large regions of silence.  Silence all looks alike, so if
+	     * there is actually jitter but lots of silence, jitter (offset)
+	     * will be incorrectly identified as 0.  When the incorrect zero
+	     * jitter is passed to offset_add_value, it eventually reduces
+	     * dynoverlap so much that it's impossible for stage 2 to merge
+	     * jittered fragments into the root (it doesn't search far enough).
+	     *
+	     * A potential solution (tested, but not committed) is to check
+	     * for silence in do_const_sync and simply not call
+	     * offset_add_value if the match is all silence.
+	     *
+	     * This bug is not fixed yet.
+	     */
+	    /* ???: To be studied. */
+	    offset_add_value(p,&(p->stage1),*offset,callback);
+	    
+	    return(1);
+	  }
+	}
+      }
+    }
+  } else
+    return(0);
+
+  /* If the samples with the same absolute position didn't match, it's
+   * either a bad sample, or the two c_blocks are jittered with respect
+   * to each other.  Now we search through A for samples that do have
+   * the same value as B's post.  The search looks from first to last
+   * occurrence witin (dynoverlap) samples of (post).
+   */
+  ptr=sort_getmatch(A,post-ib(A),dynoverlap,cv(B)[post-cb(B)]);
+  
+  while (ptr){
+
+    /* We've found a matching sample, so try to grow the matching run in
+     * both directions.  If we find a long enough run (longer than
+     * MIN_WORDS_SEARCH), we've found a match.
+     */
+    if (do_const_sync(B,A,Aflags,
+		     post-cb(B),ipos(A,ptr),
+		     begin,end,offset)){
+
+      /* ???BUG??? Jitter cannot be accurately detected when there are
+       * large regions of silence.  Silence all looks alike, so if
+       * there is actually jitter but lots of silence, jitter (offset)
+       * will be incorrectly identified as 0.  When the incorrect zero
+       * jitter is passed to offset_add_value, it eventually reduces
+       * dynoverlap so much that it's impossible for stage 2 to merge
+       * jittered fragments into the root (it doesn't search far enough).
+       *
+       * A potential solution (tested, but not committed) is to check
+       * for silence in do_const_sync and simply not call
+       * offset_add_value if the match is all silence.
+       *
+       * This bug is not fixed yet.
+       */
+      /* ???: To be studied. */
+      offset_add_value(p,&(p->stage1),*offset,callback);
+      return(1);
+    }
+
+    /* The matching sample was just a fluke -- there weren't enough adjacent
+     * samples that matched to consider a matching run.  So now we check
+     * for the next occurrence of that value in A.
+     */
+    ptr=sort_nextmatch(A,ptr);
+  }
+
+  /* We didn't find any matches. */
+  *begin=-1;
+  *end=-1;
+  *offset=-1;
+  return(0);
+}
+
+
+/* ===========================================================================
+ * STAGE 1 MATCHING
+ *
+ * ???: Insert high-level explanation here.
+ * ===========================================================================
+ */
+
+/* Top level of the first stage matcher */
+
+/* We match each analysis point of new to the preexisting blocks
+recursively.  We can also optionally maintain a list of fragments of
+the preexisting block that didn't match anything, and match them back
+afterward. */
+
+#define OVERLAP_ADJ (MIN_WORDS_OVERLAP/2-1)
+
+
+/* ===========================================================================
+ * stage1_matched() (internal)
+ *
+ * This function is called whenever stage 1 verification finds two identical
+ * runs of samples from different reads.  The runs must be more than
+ * MIN_WORDS_SEARCH samples long.  They may be jittered (i.e. their absolute
+ * positions on the CD may not match due to inaccurate seeking) with respect
+ * to each other, but they have been verified to have no dropped samples
+ * within them.
+ *
+ * This function provides feedback via the callback mechanism and marks the
+ * runs as verified.  The details of the marking are somehwat subtle and
+ * are described near the relevant code.
+ *
+ * Subsequent portions of the stage 1 code will build a verified fragment
+ * from this run.  The verified fragment will eventually be merged
+ * into the verified root (and its absolute position determined) in
+ * stage 2.
+ */
+static inline void 
+stage1_matched(c_block_t *old, c_block_t *new,
+	       long matchbegin,long matchend,
+	       long matchoffset,
+	       void (*callback)(long int, paranoia_cb_mode_t))
+{
+  long i;
+  long oldadjbegin=matchbegin-cb(old);
+  long oldadjend=matchend-cb(old);
+  long newadjbegin=matchbegin-matchoffset-cb(new);
+  long newadjend=matchend-matchoffset-cb(new);
+
+
+  /* Provide feedback via the callback about the samples we've just
+   * verified.
+   *
+   * ???: How can matchbegin ever be < cb(old)?
+   *
+   * ???: Why do edge samples get logged only when there's jitter
+   * between the matched runs (matchoffset != 0)?
+   */
+  if ( matchbegin-matchoffset<=cb(new)
+       || matchbegin<=cb(old)
+       || (new->flags[newadjbegin]&FLAGS_EDGE) 
+       || (old->flags[oldadjbegin]&FLAGS_EDGE) ) {
+    if ( matchoffset && callback )
+	(*callback)(matchbegin,PARANOIA_CB_FIXUP_EDGE);
+  } else
+    if (callback)
+      (*callback)(matchbegin,PARANOIA_CB_FIXUP_ATOM);
+  
+  if ( matchend-matchoffset>=ce(new) ||
+       (new->flags[newadjend]&FLAGS_EDGE) ||
+       matchend>=ce(old) ||
+       (old->flags[oldadjend]&FLAGS_EDGE) ) {
+    if ( matchoffset && callback )
+      (*callback)(matchend,PARANOIA_CB_FIXUP_EDGE);
+  } else
+    if (callback) 
+      (*callback)(matchend, PARANOIA_CB_FIXUP_ATOM);
+
+
+#if TRACE_PARANOIA & 1
+  fprintf(stderr, "-   Matched [%ld-%ld] against [%ld-%ld]\n",
+	  newadjbegin+cb(new), newadjend+cb(new),
+	  oldadjbegin+cb(old), oldadjend+cb(old));
+#endif
+
+  /* Mark verified samples as "verified," but trim the verified region
+   * by OVERLAP_ADJ samples on each side.  There are several significant
+   * implications of this trimming:
+   *
+   * 1) Why we trim at all:  We have to trim to distinguish between two
+   * adjacent verified runs and one long verified run.  We encounter this
+   * situation when samples have been dropped:
+   *
+   *   matched portion of read 1 ....)(.... matched portion of read 1
+   *       read 2 adjacent run  .....)(..... read 2 adjacent run
+   *                                 ||
+   *                      dropped samples in read 2
+   *
+   * So at this point, the fact that we have two adjacent runs means
+   * that we have not yet verified that the two runs really are adjacent.
+   * (In fact, just the opposite:  there are two runs because they were
+   * matched by separate runs, indicating that some samples didn't match
+   * across the length of read 2.)
+   *
+   * If we verify that they are actually adjacent (e.g. if the two runs
+   * are simply a result of matching runs from different reads, not from
+   * dropped samples), we will indeed mark them as one long merged run.
+   *
+   * 2) Why we trim by this amount: We want to ensure that when we
+   * verify the relationship between these two runs, we do so with
+   * an overlapping fragment at least OVERLAP samples long.  Following
+   * from the above example:
+   *
+   *                (..... matched portion of read 3 .....)
+   *       read 2 adjacent run  .....)(..... read 2 adjacent run
+   *
+   * Assuming there were no dropped samples between the adjacent runs,
+   * the matching portion of read 3 will need to be at least OVERLAP
+   * samples long to mark the two runs as one long verified run.
+   * If there were dropped samples, read 3 wouldn't match across the
+   * two runs, proving our caution worthwhile.
+   *
+   * 3) Why we partially discard the work we've done:  We don't.
+   * When subsequently creating verified fragments from this run,
+   * we compensate for this trimming.  Thus the verified fragment will
+   * contain the full length of verified samples.  Only the c_blocks
+   * will reflect this trimming.
+   *
+   * ???: The comment below indicates that the sort cache is updated in
+   * some way, but this does not appear to be the case.
+   */
+
+  /* Mark the verification flags.  Don't mark the first or
+     last OVERLAP/2 elements so that overlapping fragments
+     have to overlap by OVERLAP to actually merge. We also
+     remove elements from the sort such that later sorts do
+     not have to sift through already matched data */
+
+  newadjbegin+=OVERLAP_ADJ;
+  newadjend-=OVERLAP_ADJ;
+  for(i=newadjbegin;i<newadjend;i++)
+    new->flags[i]|=FLAGS_VERIFIED; /* mark verified */
+
+  oldadjbegin+=OVERLAP_ADJ;
+  oldadjend-=OVERLAP_ADJ;
+  for(i=oldadjbegin;i<oldadjend;i++)
+    old->flags[i]|=FLAGS_VERIFIED; /* mark verified */
+}
+
+
+/* ===========================================================================
+ * i_iterate_stage1 (internal)
+ *
+ * This function is called by i_stage1() to compare newly read samples with
+ * previously read samples, searching for contiguous runs of identical
+ * samples.  Matching runs indicate that at least two reads of the CD
+ * returned identical data, with no dropped samples in that run.
+ * The runs may be jittered (i.e. their absolute positions on the CD may
+ * not be accurate due to inaccurate seeking) at this point.  Their
+ * positions will be determined in stage 2.
+ *
+ * This function compares the new c_block (which has been indexed in
+ * p->sortcache) to a previous c_block.  It is called for each previous
+ * c_block.  It searches for runs of identical samples longer than
+ * MIN_WORDS_SEARCH.  Samples in matched runs are marked as verified.
+ *
+ * Subsequent stage 1 code builds verified fragments from the runs of
+ * verified samples.  These fragments are merged into the verified root
+ * in stage 2.
+ *
+ * This function returns the number of distinct runs verified in the new
+ * c_block when compared against this old c_block.
+ */
+static long int 
+i_iterate_stage1(cdrom_paranoia_t *p, c_block_t *old, c_block_t *new,
+		 void(*callback)(long int, paranoia_cb_mode_t)) 
+{
+  long matchbegin = -1;
+  long matchend   = -1;
+  long matchoffset;
+
+  /* ???: Why do we limit our search only to the samples with overlapping
+   * absolute positions?  It could be because it eliminates some further
+   * bounds checking.
+   *
+   * Why do we "no longer try to spread the ... search" as mentioned below?
+   */
+  /* we no longer try to spread the stage one search area by dynoverlap */
+  long searchend   = min(ce(old), ce(new));
+  long searchbegin = max(cb(old), cb(new));
+  long searchsize  = searchend-searchbegin;
+  sort_info_t *i = p->sortcache;
+  long ret = 0;
+  long int j;
+
+  long tried = 0;
+  long matched = 0;
+
+  if (searchsize<=0)
+    return(0);
+
+  /* match return values are in terms of the new vector, not old */
+
+  /* ???: Why 23?  */
+
+  for (j=searchbegin; j<searchend; j+=23) {
+
+    /* Skip past any samples verified in previous comparisons to
+     * other old c_blocks.  Also, obviously, don't bother verifying
+     * unread/unmatchable samples.
+     */
+    if ((new->flags[j-cb(new)] & (FLAGS_VERIFIED|FLAGS_UNREAD)) == 0) {
+      tried++;
+
+      /* Starting from the sample in the old c_block with the absolute
+       * position j, look for a matching run in the new c_block.  This
+       * search will look a certain distance around j, and if successful
+       * will extend the matching run as far backward and forward as
+       * it can.
+       *
+       * The search will only return 1 if it finds a matching run long
+       * enough to be deemed significant.
+       */
+      if (try_sort_sync(p, i, new->flags, old, j,
+			&matchbegin, &matchend, &matchoffset,
+			callback) == 1) {
+
+	matched+=matchend-matchbegin;
+
+	/* purely cosmetic: if we're matching zeros, don't use the
+           callback because they will appear to be all skewed */
+	{
+	  long j = matchbegin-cb(old);
+	  long end = matchend-cb(old);
+	  for (; j<end; j++) if (cv(old)[j]!=0) break;
+
+	  /* Mark the matched samples in both c_blocks as verified.
+	   * In reality, not all the samples are marked.  See
+	   * stage1_matched() for details.
+	   */
+	  if (j<end) {
+	    stage1_matched(old,new,matchbegin,matchend,matchoffset,callback);
+	  } else {
+	    stage1_matched(old,new,matchbegin,matchend,matchoffset,NULL);
+	  }
+	}
+	ret++;
+
+	/* Skip past this verified run to look for more matches. */
+	if (matchend-1 > j)
+	  j = matchend-1;
+      }
+    }
+  } /* end for */
+
+#ifdef NOISY 
+  fprintf(stderr,"iterate_stage1: search area=%ld[%ld-%ld] tried=%ld matched=%ld spans=%ld\n",
+	  searchsize,searchbegin,searchend,tried,matched,ret);
+#endif
+
+  return(ret);
+}
+
+
+/* ===========================================================================
+ * i_stage1() (internal)
+ *
+ * Compare newly read samples against previously read samples, searching
+ * for contiguous runs of identical samples.  Matching runs indicate that
+ * at least two reads of the CD returned identical data, with no dropped
+ * samples in that run.  The runs may be jittered (i.e. their absolute
+ * positions on the CD may not be accurate due to inaccurate seeking) at
+ * this point.  Their positions will be determined in stage 2.
+ *
+ * This function compares a new c_block against all other c_blocks in memory,
+ * searching for sufficiently long runs of identical samples.  Since each
+ * c_block represents a separate call to read_c_block, this ensures that
+ * multiple reads have returned identical data.  (Additionally, read_c_block
+ * varies the reads so that multiple reads are unlikely to produce identical
+ * errors, so any matches between reads are considered verified.  See
+ * i_read_c_block for more details.)
+ *
+ * Each time we find such a  run (longer than MIN_WORDS_SEARCH), we mark
+ * the samples as "verified" in both c_blocks.  Runs of verified samples in
+ * the new c_block are promoted into verified fragments, which will later
+ * be merged into the verified root in stage 2.
+ *
+ * In reality, not all the verified samples are marked as "verified."
+ * See stage1_matched() for an explanation.
+ *
+ * This function returns the number of verified fragments created by the
+ * stage 1 matching.
+ */
+static long int
+i_stage1(cdrom_paranoia_t *p, c_block_t *p_new, 
+	 void (*callback)(long int, paranoia_cb_mode_t))
+{
+  long size=cs(p_new);
+  c_block_t *ptr=c_last(p);
+  int ret=0;
+  long int begin=0;
+  long int end;
+
+#if TRACE_PARANOIA & 1
+  long int block_count = 0;
+  fprintf(stderr,
+	  "Verifying block %ld:[%ld-%ld] against previously read blocks...\n",
+	  p->cache->active,
+	  cb(p_new), ce(p_new));
+#endif
+  
+  /* We're going to be comparing the new c_block against the other
+   * c_blocks in memory.  Initialize the "sort cache" index to allow
+   * for fast searching through the new c_block.  (The index will
+   * actually be built the first time we search.)
+   */
+  if (ptr) 
+    sort_setup( p->sortcache, cv(p_new), &cb(p_new), cs(p_new), cb(p_new), 
+		ce(p_new) );
+
+  /* Iterate from oldest to newest c_block, comparing the new c_block
+   * to each, looking for a sufficiently long run of identical samples
+   * (longer than MIN_WORDS_SEARCH), which will be marked as "verified"
+   * in both c_blocks.
+   *
+   * Since the new c_block is already in the list (at the head), don't
+   * compare it against itself.
+   */
+  while ( ptr && ptr != p_new ) {
+#if TRACE_PARANOIA & 1
+    block_count++;
+    fprintf(stderr,
+	    "- Verifying against block %ld:[%ld-%ld] dynoverlap=%ld\n",
+	    block_count, cb(ptr), ce(ptr), p->dynoverlap);
+#endif
+
+    if (callback)
+      (*callback)(cb(p_new), PARANOIA_CB_VERIFY);
+    i_iterate_stage1(p,ptr,p_new,callback);
+
+    ptr=c_prev(ptr);
+  }
+
+  /* parse the verified areas of p_new into v_fragments */
+
+  /* Find each run of contiguous verified samples in the new c_block
+   * and create a verified fragment from each run.
+   */
+  begin=0;
+  while (begin<size) {
+    for ( ; begin < size; begin++)
+      if (p_new->flags[begin]&FLAGS_VERIFIED) break;
+    for (end=begin; end < size; end++)
+      if ((p_new->flags[end]&FLAGS_VERIFIED)==0) break;
+    if (begin>=size) break;
+    
+    ret++;
+
+    /* We create a new verified fragment from the contiguous run
+     * of verified samples.
+     *
+     * We expand the "verified" range by OVERLAP_ADJ on each side
+     * to compensate for trimming done to the verified range by
+     * stage1_matched().  The samples were actually verified, and
+     * hence belong in the verified fragment.  See stage1_matched()
+     * for an explanation of the trimming.
+     */
+    new_v_fragment(p,p_new,cb(p_new)+max(0,begin-OVERLAP_ADJ),
+		   cb(p_new)+min(size,end+OVERLAP_ADJ),
+		   (end+OVERLAP_ADJ>=size && p_new->lastsector));
+
+    begin=end;
+  }
+
+  /* Return the number of distinct verified fragments we found with
+   * stage 1 matching.
+   */
+  return(ret);
+}
+
+
+/* ===========================================================================
+ * STAGE 2 MATCHING
+ *
+ * ???: Insert high-level explanation here.
+ * ===========================================================================
+ */
+
+typedef struct sync_result {
+  long offset;
+  long begin;
+  long end;
+} sync_result_t;
+
+/* Reconcile v_fragments to root buffer.  Free if matched, fragment/fixup root
+   if necessary.
+
+   Do *not* match using zero posts
+*/
+
+/* ===========================================================================
+ * i_iterate_stage2 (internal)
+ *
+ * This function searches for a sufficiently long run of identical samples
+ * between the passed verified fragment and the verified root.  The search
+ * is similar to that performed by i_iterate_stage1.  Of course, what we do
+ * as a result of a match is different.
+ *
+ * Our search is slightly different in that we refuse to match silence to
+ * silence.  All silence looks alike, and it would result in too many false
+ * positives here, so we handle silence separately.
+ *
+ * Also, because we're trying to determine whether this fragment as a whole
+ * overlaps with the root at all, we narrow our search (since it should match
+ * immediately or not at all).  This is in contrast to stage 1, where we
+ * search the entire vector looking for all possible matches.
+ *
+ * This function returns 0 if no match was found (including failure to find
+ * one due to silence), or 1 if we found a match.
+ *
+ * When a match is found, the sync_result_t is set to the boundaries of
+ * matching run (begin/end, in terms of the root) and how far out of sync
+ * the fragment is from the canonical root (offset).  Note that this offset
+ * is opposite in sign from the notion of offset used by try_sort_sync()
+ * and stage 1 generally.
+ */
+static long int 
+i_iterate_stage2(cdrom_paranoia_t *p,
+		 v_fragment_t *v,
+		 sync_result_t *r,
+		 void(*callback)(long int, paranoia_cb_mode_t))
+{
+  root_block *root=&(p->root);
+  long matchbegin=-1,matchend=-1,offset;
+  long fbv,fev;
+  
+#if TRACE_PARANOIA & 2
+  fprintf(stderr, "- Comparing fragment [%ld-%ld] to root [%ld-%ld]...",
+	  fb(v), fe(v), rb(root), re(root));
+#endif
+
+#ifdef NOISY
+      fprintf(stderr,"Stage 2 search: fbv=%ld fev=%ld\n",fb(v),fe(v));
+#endif
+
+  /* Quickly check whether there could possibly be any overlap between
+   * the verified fragment and the root.  Our search will allow up to
+   * (p->dynoverlap) jitter between the two, so we expand the fragment
+   * search area by p->dynoverlap on both sides and see if that expanded
+   * area overlaps with the root.
+   *
+   * We could just as easily expand root's boundaries by p->dynoverlap
+   * instead and achieve the same result.
+   */
+  if (min(fe(v) + p->dynoverlap,re(root)) -
+    max(fb(v) - p->dynoverlap,rb(root)) <= 0) 
+    return(0);
+
+  if (callback)
+    (*callback)(fb(v), PARANOIA_CB_VERIFY);
+
+  /* We're going to try to match the fragment to the root while allowing
+   * for p->dynoverlap jitter, so we'll actually be looking at samples
+   * in the fragment whose position claims to be up to p->dynoverlap
+   * outside the boundaries of the root.  But, of course, don't extend
+   * past the edges of the fragment.
+   */
+  fbv = max(fb(v), rb(root)-p->dynoverlap);
+
+  /* Skip past leading zeroes in the fragment, and bail if there's nothing
+   * but silence.  We handle silence later separately.
+   */
+  while (fbv<fe(v) && fv(v)[fbv-fb(v)]==0)
+    fbv++;
+  if (fbv == fe(v))
+    return(0);
+
+  /* This is basically the same idea as the initial calculation for fbv
+   * above.  Look at samples up to p->dynoverlap outside the boundaries
+   * of the root, but don't extend past the edges of the fragment.
+   *
+   * However, we also limit the search to no more than 256 samples.
+   * Unlike stage 1, we're not trying to find all possible matches within
+   * two runs -- rather, we're trying to see if the fragment as a whole
+   * overlaps with the root.  If we can't find a match within 256 samples,
+   * there's probably no match to be found (because this fragment doesn't
+   * overlap with the root).
+   *
+   * ??? Is this why?  Why 256?
+   */
+  fev = min(min(fbv+256, re(root)+p->dynoverlap), fe(v));
+  
+  {
+    /* Because we'll allow for up to (p->dynoverlap) jitter between the
+     * fragment and the root, we expand the search area (fbv to fev) by
+     * p->dynoverlap on both sides.  But, because we're iterating through
+     * root, we need to constrain the search area not to extend beyond
+     * the root's boundaries.
+     */
+    long searchend=min(fev+p->dynoverlap,re(root));
+    long searchbegin=max(fbv-p->dynoverlap,rb(root));
+    sort_info_t *i=p->sortcache;
+    long j;
+
+    /* Initialize the "sort cache" index to allow for fast searching
+     * through the verified fragment between (fbv,fev).  (The index will
+     * actually be built the first time we search.)
+     */
+    sort_setup(i, fv(v), &fb(v), fs(v), fbv, fev);
+
+    /* ??? Why 23? */
+    for(j=searchbegin; j<searchend; j+=23){
+
+      /* Skip past silence in the root.  If there are just a few silent
+       * samples, the effect is minimal.  The real reason we need this is
+       * for large regions of silence.  All silence looks alike, so you
+       * could false-positive "match" two runs of silence that are either
+       * unrelated or ought to be jittered, and try_sort_sync can't
+       * accurately determine jitter (offset) from silence.
+       *
+       * Therefore, we want to post on a non-zero sample.  If there's
+       * nothing but silence left in the root, bail.  We don't want
+       * to match it here.
+       */
+      while (j<searchend && rv(root)[j-rb(root)]==0)j++;
+      if (j==searchend) break;
+
+      /* Starting from the (non-zero) sample in the root with the absolute
+       * position j, look for a matching run in the verified fragment.  This
+       * search will look a certain distance around j, and if successful
+       * will extend the matching run as far backward and forward as
+       * it can.
+       *
+       * The search will only return 1 if it finds a matching run long
+       * enough to be deemed significant.  Note that the search is limited
+       * by the boundaries given to sort_setup() above.
+       *
+       * Note also that flags aren't used in stage 2 (since neither verified
+       * fragments nor the root have them).
+       */
+      if (try_sort_sync(p, i, NULL, rc(root), j,
+			&matchbegin,&matchend,&offset,callback)){
+
+	/* If we found a matching run, we return the results of our match.
+	 *
+	 * Note that we flip the sign of (offset) because try_sort_sync()
+	 * returns it in terms of the fragment (i.e. what we add
+	 * to the fragment's position to yield the corresponding position
+	 * in the root), but here we consider the root to be canonical,
+	 * and so our returned "offset" reflects how the fragment is offset
+	 * from the root.
+	 *
+	 * E.g.: If the fragment's sample 10 corresponds to root's 12,
+	 * try_sort_sync() would return 2.  But since root is canonical,
+	 * we say that the fragment is off by -2.
+	 */
+	r->begin=matchbegin;
+	r->end=matchend;
+	r->offset=-offset;
+	if (offset)if (callback)(*callback)(r->begin,PARANOIA_CB_FIXUP_EDGE);
+	return(1);
+      }
+    }
+  }
+  
+  return(0);
+}
+
+
+/* ===========================================================================
+ * i_silence_test() (internal)
+ *
+ * If the entire root is silent, or there's enough trailing silence
+ * to be significant (MIN_SILENCE_BOUNDARY samples), mark the beginning
+ * of the silence and "light" the silence flag.  This flag will remain lit
+ * until i_silence_match() appends some non-silent samples to the root.
+ *
+ * We do this because if there's a long enough span of silence, we can't
+ * reliably detect jitter or dropped samples within that span.  See
+ * i_silence_match() for details on how we recover from this situation.
+ */
+static void 
+i_silence_test(root_block *root)
+{
+  int16_t *vec=rv(root);
+  long end=re(root)-rb(root)-1;
+  long j;
+
+  /* Look backward from the end of the root to find the first non-silent
+   * sample.
+   */
+  for(j=end-1;j>=0;j--)
+    if (vec[j]!=0) break;
+
+  /* If the entire root is silent, or there's enough trailing silence
+   * to be significant, mark the beginning of the silence and "light"
+   * the silence flag.
+   */
+  if (j<0 || end-j>MIN_SILENCE_BOUNDARY) {
+    /* ???BUG???:
+     *
+     * The original code appears to have a bug, as it points to the
+     * last non-zero sample, and silence matching appears to treat
+     * silencebegin as the first silent sample.  As a result, in certain
+     * situations, the last non-zero sample can get clobbered.
+     *
+     * This bug has been tentatively fixed, since it allows more regression
+     * tests to pass.  The original code was:
+     *   if (j<0)j=0;
+     */
+    j++;
+
+    root->silenceflag=1;
+    root->silencebegin=rb(root)+j;
+
+    /* ???: To be studied. */
+    if (root->silencebegin<root->returnedlimit)
+      root->silencebegin=root->returnedlimit;
+  }
+}
+
+
+/* ===========================================================================
+ * i_silence_match() (internal)
+ *
+ * This function is merges verified fragments into the verified root in cases
+ * where there is a problematic amount of silence (MIN_SILENCE_BOUNDARY
+ * samples) at the end of the root.
+ *
+ * We need a special approach because if there's a long enough span of
+ * silence, we can't reliably detect jitter or dropped samples within that
+ * span (since all silence looks alike).
+ *
+ * Only fragments that begin with MIN_SILENCE_BOUNDARY samples are eligible
+ * to be merged in this case.  Fragments that are too far beyond the edge
+ * of the root to possibly overlap are also disregarded.
+ *
+ * Our first approach is to assume that such fragments have no jitter (since
+ * we can't establish otherwise) and merge them.  However, if it's clear
+ * that there must be jitter (i.e. because non-silent samples overlap when
+ * we assume no jitter), we assume the fragment has the minimum possible
+ * jitter and then merge it.
+ *
+ * This function extends silence fairly aggressively, so it must be called
+ * with fragments in ascending order (beginning position) in case there are
+ * small non-silent regions within the silence.
+ */
+static long int 
+i_silence_match(root_block *root, v_fragment_t *v, 
+		void(*callback)(long int, paranoia_cb_mode_t))
+{
+
+  cdrom_paranoia_t *p=v->p;
+  int16_t *vec=fv(v);
+  long end=fs(v),begin;
+  long j;
+
+#if TRACE_PARANOIA & 2
+  fprintf(stderr, "- Silence matching fragment [%ld-%ld] to root [%ld-%ld]"
+	  " silencebegin=%ld\n",
+	  fb(v), fe(v), rb(root), re(root), root->silencebegin);
+#endif
+
+  /* See how much leading silence this fragment has.  If there are fewer than
+   * MIN_SILENCE_BOUNDARY leading silent samples, we don't do this special
+   * silence matching.
+   *
+   * This fragment could actually belong here, but we can't be sure unless
+   * it has enough silence on its leading edge.  This fragment will likely
+   * stick around until we do successfully extend the root, at which point
+   * it will be merged using the usual method.
+   */
+  if (end<MIN_SILENCE_BOUNDARY) return(0);
+  for(j=0;j<end;j++)
+    if (vec[j]!=0) break;
+  if (j<MIN_SILENCE_BOUNDARY) return(0);
+
+  /* Convert the offset of the first non-silent sample to an absolute
+   * position.  For the time being, we will assume that this position
+   * is accurate, with no jitter.
+   */
+  j+=fb(v);
+
+#if TRACE_PARANOIA & 2
+  fprintf(stderr, "- Fragment begins with silence [%ld-%ld]\n", fb(v), j);
+#endif
+
+  /* If this fragment is ahead of the root, see if that could just be due
+   * to jitter (if it's within p->dynoverlap samples of the end of root).
+   */
+  if (fb(v)>=re(root) && fb(v)-p->dynoverlap<re(root)){
+
+    /* This fragment is within jitter range of the root, so we extend the
+     * root's silence so that it overlaps with this fragment.  At this point
+     * we know that the fragment has at least MIN_SILENCE_BOUNDARY silent
+     * samples at the beginning, so we overlap by that amount.
+     */
+    long addto   = fb(v) + MIN_SILENCE_BOUNDARY - re(root);
+    int16_t *vec = calloc(addto, sizeof(int16_t));
+    c_append(rc(root), vec, addto);
+    free(vec);
+
+#if TRACE_PARANOIA & 2
+    fprintf(stderr, "* Adding silence [%ld-%ld] to root\n",
+	    re(root)-addto, re(root));
+#endif
+  }
+
+  /* Calculate the overlap of the root's trailing silence and the fragment's
+   * leading silence.  (begin,end) are the boundaries of that overlap.
+   */
+  begin = max(fb(v),root->silencebegin);
+  end = min(j,re(root));
+
+  /* If there is an overlap, we assume that both the root and the fragment
+   * are jitter-free (since there's no way for us to tell otherwise).
+   */
+  if (begin<end){
+
+    /* If the fragment will extend the root, then we append it to the root.
+     * Otherwise, no merging is necessary, as the fragment should already
+     * be contained within the root.
+     */
+    if (fe(v)>re(root)){
+      long int voff = begin-fb(v);
+
+      /* Truncate the overlapping silence from the end of the root.
+       */
+      c_remove(rc(root),begin-rb(root),-1);
+
+      /* Append the fragment to the root, starting from the point of overlap.
+       */
+      c_append(rc(root),vec+voff,fs(v)-voff);
+
+#if TRACE_PARANOIA & 2
+      fprintf(stderr, "* Adding [%ld-%ld] to root (no jitter)\n",
+	      begin, re(root));
+#endif
+    }
+
+    /* Record the fact that we merged this fragment assuming zero jitter.
+     */
+    offset_add_value(p,&p->stage2,0,callback);
+
+  } else {
+
+    /* We weren't able to merge the fragment assuming zero jitter.
+     *
+     * Check whether the fragment's leading silence ends before the root's
+     * trailing silence begins.  If it does, we assume that the root is
+     * jittered forward.
+     */
+    if (j<begin){
+
+      /* We're going to append the non-silent samples of the fragment
+       * to the root where its silence begins.
+       *
+       * ??? This seems to be a very strange approach.  At this point
+       * the root has a lot of trailing silence, and the fragment has
+       * the lot of leading silence.  This merge will drop the silence
+       * and just splice the non-silence together.
+       *
+       * In theory, rift analysis will either confirm or fix this result.
+       * What circumstances motivated this approach?
+       */
+
+      /* Compute the amount of silence at the beginning of the fragment.
+       */
+      long voff = j - fb(v);
+
+      /* If attaching the non-silent tail of the fragment to the end
+       * of the non-silent portion of the root will extend the root,
+       * then we'll append the samples to the root.  Otherwise, no
+       * merging is necessary, as the fragment should already be contained
+       * within the root.
+       */
+      if (begin+fs(v)-voff>re(root)) {
+
+	/* Truncate the trailing silence from the root.
+	 */
+	c_remove(rc(root),root->silencebegin-rb(root),-1);
+
+	/* Append the non-silent tail of the fragment to the root.
+	 */
+	c_append(rc(root),vec+voff,fs(v)-voff);
+
+#if TRACE_PARANOIA & 2
+	fprintf(stderr, "* Adding [%ld-%ld] to root (jitter=%ld)\n",
+		root->silencebegin, re(root), end-begin);
+#endif
+      }
+
+      /* Record the fact that we merged this fragment assuming (end-begin)
+       * jitter.
+       */
+      offset_add_value(p,&p->stage2,end-begin,callback);
+
+    } else
+
+      /* We only get here if the fragment is past the end of the root,
+       * which means it must be farther than (dynoverlap) away, due to our
+       * root extension above.
+       */
+
+      /* We weren't able to merge this fragment into the root after all.
+       */
+      return(0);
+  }
+
+
+  /* We only get here if we merged the fragment into the root.  Update
+   * the root's silence flag.
+   *
+   * Note that this is the only place silenceflag is reset.  In other words,
+   * once i_silence_test() lights the silence flag, it can only be reset
+   * by i_silence_match().
+   */
+  root->silenceflag = 0;
+
+  /* Now see if the new, extended root ends in silence.
+   */
+  i_silence_test(root);
+
+
+  /* Since we merged the fragment, we can free it now.  But first we propagate
+   * its lastsector flag.
+   */
+  if (v->lastsector) root->lastsector=1;
+  free_v_fragment(v);
+  return(1);
+}
+
+
+/* ===========================================================================
+ * i_stage2_each (internal)
+ *
+ * This function (which is entirely too long) attempts to merge the passed
+ * verified fragment into the verified root.
+ *
+ * First this function looks for a run of identical samples between
+ * the root and the fragment.  If it finds a long enough run, it then
+ * checks for "rifts" (see below) and fixes the root and/or fragment as
+ * necessary.  Finally, if the fragment will extend the tail of the root,
+ * we merge the fragment and extend the root.
+ *
+ * Most of the ugliness in this function has to do with handling "rifts",
+ * which are points of disagreement between the root and the verified
+ * fragment.  This can happen when a drive consistently drops a few samples
+ * or stutters and repeats a few samples.  It has to be consistent enough
+ * to result in a verified fragment (i.e. it happens twice), but inconsistent
+ * enough (e.g. due to the jiggled reads) not to happen every time.
+ *
+ * This function returns 1 if the fragment was successfully merged into the
+ * root, and 0 if not.
+ */
+static long int 
+i_stage2_each(root_block *root, v_fragment_t *v,
+	      void(*callback)(long int, paranoia_cb_mode_t))
+{
+
+  /* If this fragment has already been merged & freed, abort. */
+  if (!v || !v->one) return(0);
+
+  cdrom_paranoia_t *p=v->p;
+
+  /* ??? Why do we round down to an even dynoverlap? */
+  long dynoverlap=p->dynoverlap/2*2;
+  
+  /* If there's no verified root yet, abort. */
+  if (!rv(root)){
+    return(0);
+  } else {
+    sync_result_t r;
+
+    /* Search for a sufficiently long run of identical samples between
+     * the verified fragment and the verified root.  There's a little
+     * bit of subtlety in the search when silence is involved.
+     */
+    if (i_iterate_stage2(p,v,&r,callback)){
+
+      /* Convert the results of the search to be relative to the root. */
+      long int begin=r.begin-rb(root);
+      long int end=r.end-rb(root);
+
+      /* Convert offset into a value that will transform a relative
+       * position in the root to the corresponding relative position in
+       * the fragment.  I.e., if offset = -2, then the sample at relative
+       * position 2 in the root is at relative position 0 in the fragment.
+       *
+       * While a bit opaque, this does reduce the number of calculations
+       * below.
+       */
+      long int offset=r.begin+r.offset-fb(v)-begin;
+      long int temp;
+      c_block_t *l=NULL;
+
+      /* we have a match! We don't rematch off rift, we chase the
+	 match all the way to both extremes doing rift analysis. */
+
+#if TRACE_PARANOIA & 2
+      fprintf(stderr, "matched [%ld-%ld], offset=%ld\n",
+	      r.begin, r.end, r.offset);
+      int traced = 0;
+#endif
+#ifdef NOISY
+      fprintf(stderr,"Stage 2 match\n");
+#endif
+
+      /* Now that we've found a sufficiently long run of identical samples
+       * between the fragment and the root, we need to check for rifts.
+       *
+       * A "rift", as mentioned above, is a disagreement between the
+       * fragment and the root.  When there's a rift, the matching run
+       * found by i_iterate_stage2() will obviously stop where the root
+       * and the fragment disagree.
+       *
+       * So we detect rifts by checking whether the matching run extends
+       * to the ends of the fragment and root.  If the run does extend to
+       * the ends of the fragment and root, then all overlapping samples
+       * agreed, and there's no rift.  If, however, the matching run
+       * stops with samples left over in both the root and the fragment,
+       * that means the root and fragment disagreed at that point.
+       * Leftover samples at the beginning of the match indicate a
+       * leading rift, and leftover samples at the end of the match indicate
+       * a trailing rift.
+       *
+       * Once we detect a rift, we attempt to fix it, depending on the
+       * nature of the disagreement.  See i_analyze_rift_[rf] for details
+       * on how we determine what kind of rift it is.  See below for
+       * how we attempt to fix the rifts.
+       */
+
+      /* First, check for a leading rift, fix it if possible, and then
+       * extend the match forward until either we hit the limit of the
+       * overlapping samples, or until we encounter another leading rift.
+       * Keep doing this until we hit the beginning of the overlap.
+       *
+       * Note that while we do fix up leading rifts, we don't extend
+       * the root backward (earlier samples) -- only forward (later
+       * samples).
+       */
+
+      /* If the beginning of the match didn't reach the beginning of
+       * either the fragment or the root, we have a leading rift to be
+       * examined.
+       *
+       * Remember that (begin) is the offset into the root, and (begin+offset)
+       * is the equivalent offset into the fragment.  If neither one is at
+       * zero, then they both have samples before the match, and hence a
+       * rift.
+       */
+      while ((begin+offset>0 && begin>0)){
+	long matchA=0,matchB=0,matchC=0;
+
+	/* (begin) is the offset into the root of the first matching sample,
+	 * (beginL) is the offset into the fragment of the first matching
+	 * sample.  These samples are at the edge of the rift.
+	 */
+	long beginL=begin+offset;
+
+#if TRACE_PARANOIA & 2
+	if ((traced & 1) == 0) {
+	  fprintf(stderr, "- Analyzing leading rift...\n");
+	  traced |= 1;
+	}
+#endif
+
+	/* The first time we encounter a leading rift, allocate a
+	 * scratch copy of the verified fragment which we'll use if
+	 * we need to fix up the fragment before merging it into
+	 * the root.
+	 */
+	if (l==NULL){
+	  int16_t *buff=malloc(fs(v)*sizeof(int16_t));
+	  l=c_alloc(buff,fb(v),fs(v));
+	  memcpy(buff,fv(v),fs(v)*sizeof(int16_t));
+	}
+
+	/* Starting at the first mismatching sample, see how far back the
+	 * rift goes, and determine what kind of rift it is.  Note that
+	 * we're searching through the fixed up copy of the fragment.
+	 *
+	 * matchA  > 0 if there are samples missing from the root
+	 * matchA  < 0 if there are duplicate samples (stuttering) in the root
+	 * matchB  > 0 if there are samples missing from the fragment
+	 * matchB  < 0 if there are duplicate samples in the fragment
+	 * matchC != 0 if there's a section of garbage, after which
+	 *             the fragment and root agree and are in sync
+	 */
+	i_analyze_rift_r(rv(root),cv(l),
+			 rs(root),cs(l),
+			 begin-1,beginL-1,
+			 &matchA,&matchB,&matchC);
+	
+#ifdef NOISY
+	fprintf(stderr,"matching rootR: matchA:%ld matchB:%ld matchC:%ld\n",
+		matchA,matchB,matchC);
+#endif		
+	
+	/* ??? The root.returnedlimit checks below are presently a mystery. */
+
+	if (matchA){
+	  /* There's a problem with the root */
+
+	  if (matchA>0){
+	    /* There were (matchA) samples dropped from the root.  We'll add
+	     * them back from the fixed up fragment.
+	     */
+	    if (callback)
+	      (*callback)(begin+rb(root)-1,PARANOIA_CB_FIXUP_DROPPED);
+	    if (rb(root)+begin<p->root.returnedlimit)
+	      break;
+	    else{
+
+	      /* At the edge of the rift in the root, insert the missing
+	       * samples from the fixed up fragment.  They're the (matchA)
+	       * samples immediately preceding the edge of the rift in the
+	       * fragment.
+	       */
+	      c_insert(rc(root),begin,cv(l)+beginL-matchA,
+		       matchA);
+
+	      /* We just inserted (matchA) samples into the root, so update
+	       * our begin/end offsets accordingly.  Also adjust the
+	       * (offset) to compensate (since we use it to find samples in
+	       * the fragment, and the fragment hasn't changed).
+	       */
+	      offset-=matchA;
+	      begin+=matchA;
+	      end+=matchA;
+	    }
+
+	  } else {
+	    /* There were (-matchA) duplicate samples (stuttering) in the
+	     * root.  We'll drop them.
+	     */
+	    if (callback)
+	      (*callback)(begin+rb(root)-1,PARANOIA_CB_FIXUP_DUPED);
+	    if (rb(root)+begin+matchA<p->root.returnedlimit) 
+	      break;
+	    else{
+
+	      /* Remove the (-matchA) samples immediately preceding the
+	       * edge of the rift in the root.
+	       */
+	      c_remove(rc(root),begin+matchA,-matchA);
+
+	      /* We just removed (-matchA) samples from the root, so update
+	       * our begin/end offsets accordingly.  Also adjust the offset
+	       * to compensate.  Remember that matchA < 0, so we're actually
+	       * subtracting from begin/end.
+	       */
+	      offset-=matchA;
+	      begin+=matchA;
+	      end+=matchA;
+	    }
+	  }
+	} else if (matchB){
+	  /* There's a problem with the fragment */
+
+	  if (matchB>0){
+	    /* There were (matchB) samples dropped from the fragment.  We'll
+	     * add them back from the root.
+	     */
+	    if (callback)
+	      (*callback)(begin+rb(root)-1,PARANOIA_CB_FIXUP_DROPPED);
+
+	    /* At the edge of the rift in the fragment, insert the missing
+	     * samples from the root.  They're the (matchB) samples
+	     * immediately preceding the edge of the rift in the root.
+	     * Note that we're fixing up the scratch copy of the fragment.
+	     */
+	    c_insert(l,beginL,rv(root)+begin-matchB,
+			 matchB);
+
+	    /* We just inserted (matchB) samples into the fixed up fragment,
+	     * so update (offset), since we use it to find samples in the
+	     * fragment based on the root's unchanged offsets.
+	     */
+	    offset+=matchB;
+
+	  } else {
+	    /* There were (-matchB) duplicate samples (stuttering) in the
+	     * fixed up fragment.  We'll drop them.
+	     */
+	    if (callback)
+	      (*callback)(begin+rb(root)-1,PARANOIA_CB_FIXUP_DUPED);
+
+	    /* Remove the (-matchB) samples immediately preceding the edge
+	     * of the rift in the fixed up fragment.
+	     */
+	    c_remove(l,beginL+matchB,-matchB);
+
+	    /* We just removed (-matchB) samples from the fixed up fragment,
+	     * so update (offset), since we use it to find samples in the
+	     * fragment based on the root's unchanged offsets.
+	     */
+	    offset+=matchB;
+	  }
+
+	} else if (matchC){
+
+	  /* There are (matchC) samples that simply disagree between the
+	   * fragment and the root.  On the other side of the mismatch, the
+	   * fragment and root agree again.  We can't classify the mismatch
+	   * as either a stutter or dropped samples, and we have no way of
+	   * telling whether the fragment or the root is right.
+	   *
+	   * The original comment indicated that we set "disagree" flags
+	   * in the root, but it seems to be historical.
+	   */
+
+	  if (rb(root)+begin-matchC<p->root.returnedlimit)
+	    break;
+
+	  /* Overwrite the mismatching (matchC) samples in root with the
+	   * samples from the fixed up fragment.
+	   *
+	   * ??? Do we think the fragment is more likely correct, is this
+	   * just arbitrary, or is there some other reason for overwriting
+	   * the root?
+	   */
+	  c_overwrite(rc(root),begin-matchC,
+			cv(l)+beginL-matchC,matchC);
+	  
+	} else {
+
+	  /* We may have had a mismatch because we ran into leading silence.
+	   *
+	   * ??? To be studied: why would this cause a mismatch?  Neither
+	   * i_analyze_rift_r nor i_iterate_stage2() nor i_paranoia_overlap()
+	   * appear to take silence into consideration in this regard.
+	   * It could be due to our skipping of silence when searching for
+	   * a match.
+	   *
+	   * Since we don't extend the root in that direction, we don't
+	   * do anything, just move on to trailing rifts.
+	   */
+
+	  /* If the rift was too complex to fix (see i_analyze_rift_r),
+	   * we just stop and leave the leading edge where it is.
+	   */
+	    
+	  /*RRR(*callback)(post,PARANOIA_CB_XXX);*/
+	  break;
+	}
+
+	/* Recalculate the offset of the edge of the rift in the fixed
+	 * up fragment, in case it changed.
+	 *
+	 * ??? Why is this done here rather than in the (matchB) case above,
+	 * which should be the only time beginL will change.
+	 */
+	beginL=begin+offset;
+
+	/* Now that we've fixed up the root or fragment as necessary, see
+	 * how far we can extend the matching run.  This function is
+	 * overkill, as it tries to extend the matching run in both
+	 * directions (and rematches what we already matched), but it works.
+	 */
+	i_paranoia_overlap(rv(root),cv(l),
+			   begin,beginL,
+			   rs(root),cs(l),
+			   &begin,&end);	
+
+      } /* end while (leading rift) */
+
+
+      /* Second, check for a trailing rift, fix it if possible, and then
+       * extend the match forward until either we hit the limit of the
+       * overlapping samples, or until we encounter another trailing rift.
+       * Keep doing this until we hit the end of the overlap.
+       */
+
+      /* If the end of the match didn't reach the end of either the fragment
+       * or the root, we have a trailing rift to be examined.
+       *
+       * Remember that (end) is the offset into the root, and (end+offset)
+       * is the equivalent offset into the fragment.  If neither one is
+       * at the end of the vector, then they both have samples after the
+       * match, and hence a rift.
+       *
+       * (temp) is the size of the (potentially fixed-up) fragment.  If
+       * there was a leading rift, (l) is the fixed up fragment, and
+       * (offset) is now relative to it.
+       */
+      temp=l ? cs(l) : fs(v);
+      while (end+offset<temp && end<rs(root)){
+	long matchA=0,matchB=0,matchC=0;
+
+	/* (begin) is the offset into the root of the first matching sample,
+	 * (beginL) is the offset into the fragment of the first matching
+	 * sample.  We know these samples match and will use these offsets
+	 * later when we try to extend the matching run.
+	 */
+	long beginL=begin+offset;
+
+	/* (end) is the offset into the root of the first mismatching sample
+	 * after the matching run, (endL) is the offset into the fragment of
+	 * the equivalent sample.  These samples are at the edge of the rift.
+	 */
+	long endL=end+offset;
+	
+#if TRACE_PARANOIA & 2
+	if ((traced & 2) == 0) {
+	  fprintf(stderr, "- Analyzing trailing rift...\n");
+	  traced |= 2;
+	}
+#endif
+
+	/* The first time we encounter a rift, allocate a scratch copy of
+	 * the verified fragment which we'll use if we need to fix up the
+	 * fragment before merging it into the root.
+	 *
+	 * Note that if there was a leading rift, we'll already have
+	 * this (potentially fixed-up) scratch copy allocated.
+	 */
+	if (l==NULL){
+	  int16_t *buff=malloc(fs(v)*sizeof(int16_t));
+	  l=c_alloc(buff,fb(v),fs(v));
+	  memcpy(buff,fv(v),fs(v)*sizeof(int16_t));
+	}
+
+	/* Starting at the first mismatching sample, see how far forward the
+	 * rift goes, and determine what kind of rift it is.  Note that we're
+	 * searching through the fixed up copy of the fragment.
+	 *
+	 * matchA  > 0 if there are samples missing from the root
+	 * matchA  < 0 if there are duplicate samples (stuttering) in the root
+	 * matchB  > 0 if there are samples missing from the fragment
+	 * matchB  < 0 if there are duplicate samples in the fragment
+	 * matchC != 0 if there's a section of garbage, after which
+	 *             the fragment and root agree and are in sync
+	 */
+	i_analyze_rift_f(rv(root),cv(l),
+			 rs(root),cs(l),
+			 end,endL,
+			 &matchA,&matchB,&matchC);
+	
+#ifdef NOISY	
+	fprintf(stderr,"matching rootF: matchA:%ld matchB:%ld matchC:%ld\n",
+		matchA,matchB,matchC);
+#endif
+
+	/* ??? The root.returnedlimit checks below are presently a mystery. */
+	
+	if (matchA){
+	  /* There's a problem with the root */
+
+	  if (matchA>0){
+	    /* There were (matchA) samples dropped from the root.  We'll add
+	     * them back from the fixed up fragment.
+	     */
+	    if (callback)(*callback)(end+rb(root),PARANOIA_CB_FIXUP_DROPPED);
+	    if (end+rb(root)<p->root.returnedlimit)
+	      break;
+
+	    /* At the edge of the rift in the root, insert the missing
+	     * samples from the fixed up fragment.  They're the (matchA)
+	     * samples immediately preceding the edge of the rift in the
+	     * fragment.
+	     */
+	    c_insert(rc(root),end,cv(l)+endL,matchA);
+
+	    /* Although we just inserted samples into the root, we did so
+	     * after (begin) and (end), so we needn't update those offsets.
+	     */
+
+	  } else {
+	    /* There were (-matchA) duplicate samples (stuttering) in the
+	     * root.  We'll drop them.
+	     */
+	    if (callback)(*callback)(end+rb(root),PARANOIA_CB_FIXUP_DUPED);
+	    if (end+rb(root)<p->root.returnedlimit)
+	      break;
+
+	    /* Remove the (-matchA) samples immediately following the edge
+	     * of the rift in the root.
+	     */
+	    c_remove(rc(root),end,-matchA);
+
+	    /* Although we just removed samples from the root, we did so
+	     * after (begin) and (end), so we needn't update those offsets.
+	     */
+
+	  }
+	} else if (matchB){
+	  /* There's a problem with the fragment */
+
+	  if (matchB>0){
+	    /* There were (matchB) samples dropped from the fragment.  We'll
+	     * add them back from the root.
+	     */
+	    if (callback)(*callback)(end+rb(root),PARANOIA_CB_FIXUP_DROPPED);
+
+	    /* At the edge of the rift in the fragment, insert the missing
+	     * samples from the root.  They're the (matchB) samples
+	     * immediately following the dge of the rift in the root.
+	     * Note that we're fixing up the scratch copy of the fragment.
+	     */
+	    c_insert(l,endL,rv(root)+end,matchB);
+
+	    /* Although we just inserted samples into the fragment, we did so
+	     * after (begin) and (end), so (offset) hasn't changed either.
+	     */
+
+	  } else {
+	    /* There were (-matchB) duplicate samples (stuttering) in the
+	     * fixed up fragment.  We'll drop them.
+	     */
+	    if (callback)(*callback)(end+rb(root),PARANOIA_CB_FIXUP_DUPED);
+
+	    /* Remove the (-matchB) samples immediately following the edge
+	     * of the rift in the fixed up fragment.
+	     */
+	    c_remove(l,endL,-matchB);
+
+	    /* Although we just removed samples from the fragment, we did so
+	     * after (begin) and (end), so (offset) hasn't changed either.
+	     */
+	  }
+	} else if (matchC){
+
+          /* There are (matchC) samples that simply disagree between the
+           * fragment and the root.  On the other side of the mismatch, the
+           * fragment and root agree again.  We can't classify the mismatch
+           * as either a stutter or dropped samples, and we have no way of
+           * telling whether the fragment or the root is right.
+           *
+           * The original comment indicated that we set "disagree" flags
+           * in the root, but it seems to be historical.
+           */
+
+	  if (end+rb(root)<p->root.returnedlimit)
+	    break;
+
+          /* Overwrite the mismatching (matchC) samples in root with the
+           * samples from the fixed up fragment.
+           *
+           * ??? Do we think the fragment is more likely correct, is this
+           * just arbitrary, or is there some other reason for overwriting
+           * the root?
+           */
+	  c_overwrite(rc(root),end,cv(l)+endL,matchC);
+
+	} else {
+
+	  /* We may have had a mismatch because we ran into trailing silence.
+	   *
+	   * ??? To be studied: why would this cause a mismatch?  Neither
+	   * i_analyze_rift_f nor i_iterate_stage2() nor i_paranoia_overlap()
+	   * appear to take silence into consideration in this regard.
+           * It could be due to our skipping of silence when searching for
+           * a match.
+	   */
+
+	  /* At this point we have a trailing rift.  We check whether
+	   * one of the vectors (fragment or root) has trailing silence.
+	   */
+	  analyze_rift_silence_f(rv(root),cv(l),
+				 rs(root),cs(l),
+				 end,endL,
+				 &matchA,&matchB);
+	  if (matchA){
+
+	    /* The contents of the root's trailing rift are silence.  The
+	     * fragment's are not (otherwise there wouldn't be a rift).
+	     * We therefore assume that the root has garbage from this
+	     * point forward and truncate it.
+	     *
+	     * This will have the effect of eliminating the trailing
+	     * rift, causing the fragment's samples to be appended to
+	     * the root.
+	     *
+	     * ??? Does this have any negative side effects?  Why is this
+	     * a good idea?
+	     */
+	    /* ??? TODO: returnedlimit */
+	    /* Can only do this if we haven't already returned data */
+	    if (end+rb(root)>=p->root.returnedlimit){
+	      c_remove(rc(root),end,-1);
+	    }
+
+	  } else if (matchB){
+
+	    /* The contents of the fragment's trailing rift are silence.
+	     * The root's are not (otherwise there wouldn't be a rift).
+	     * We therefore assume that the fragment has garbage from this
+	     * point forward.
+	     *
+	     * We needn't actually truncate the fragment, because the root
+	     * has already been fixed up from this fragment as much as
+	     * possible, and the truncated fragment wouldn't extend the
+	     * root.  Therefore, we can consider this (truncated) fragment
+	     * to be already merged into the root.  So we dispose of it and
+	     * return a success.
+	     */
+	    if (l)i_cblock_destructor(l);
+	    free_v_fragment(v);
+	    return(1);
+
+	  } else {
+
+	    /* If the rift was too complex to fix (see i_analyze_rift_f),
+	     * we just stop and leave the trailing edge where it is.
+	     */
+	    
+	    /*RRR(*callback)(post,PARANOIA_CB_XXX);*/
+	  }
+	  break;
+	}
+
+        /* Now that we've fixed up the root or fragment as necessary, see
+         * how far we can extend the matching run.  This function is
+         * overkill, as it tries to extend the matching run in both
+         * directions (and rematches what we already matched), but it works.
+         */
+	i_paranoia_overlap(rv(root),cv(l),
+			   begin,beginL,
+			   rs(root),cs(l),
+			   NULL,&end);
+
+	/* ???BUG??? (temp) never gets updated within the loop, even if the
+	 * fragment gets fixed up.  In contrast, rs(root) is inherently
+	 * updated when the verified root gets fixed up.
+	 *
+	 * This bug is not fixed yet.
+	 */
+
+      } /* end while (trailing rift) */
+
+
+      /* Third and finally, if the overlapping verified fragment extends
+       * our range forward (later samples), we append ("glom") the new
+       * samples to the end of the root.
+       *
+       * Note that while we did fix up leading rifts, we don't extend
+       * the root backward (earlier samples) -- only forward (later
+       * samples).
+       *
+       * This is generally fine, since the verified root is supposed to
+       * slide from earlier samples to later samples across multiple calls
+       * to paranoia_read().
+       *
+       * ??? But, is this actually right?  Because of this, we don't
+       * extend the root to hold the earliest read sample, if we happened
+       * to initialize the root with a later sample due to jitter.
+       * There are probably some ugly side effects from extending the root
+       * backward, in the general case, but it may not be so dire if we're
+       * near sample 0.  To be investigated.
+       */
+      {
+	long sizeA=rs(root);
+	long sizeB;
+	long vecbegin;
+	int16_t *vector;
+
+	/* If there were any rifts, we'll use the fixed up fragment (l),
+	 * otherwise, we use the original fragment (v).
+	 */
+	if (l){
+	  sizeB=cs(l);
+	  vector=cv(l);
+	  vecbegin=cb(l);
+	} else {
+	  sizeB=fs(v);
+	  vector=fv(v);
+	  vecbegin=fb(v);
+	}
+
+	/* Convert the fragment-relative offset (sizeB) into an offset
+	 * relative to the root (A), and see if the offset is past the
+	 * end of the root (> sizeA).  If it is, this fragment will extend
+	 * our root.
+	 *
+	 * ??? Why do we check for v->lastsector separately?
+	 */
+	if (sizeB-offset>sizeA || v->lastsector){	  
+	  if (v->lastsector){
+	    root->lastsector=1;
+	  }
+
+	  /* ??? Why would end be < sizeA? Why do we truncate root? */
+	  if (end<sizeA)c_remove(rc(root),end,-1);
+
+	  /* Extend the root with the samples from the end of the
+	   * (potentially fixed up) fragment.
+	   *
+	   * ??? When would this condition not be true?
+	   */
+	  if (sizeB-offset-end)c_append(rc(root),vector+end+offset,
+					 sizeB-offset-end);
+	  
+#if TRACE_PARANOIA & 2
+	  fprintf(stderr, "* Adding [%ld-%ld] to root\n",
+		  rb(root)+end, re(root));
+#endif
+
+	  /* Any time we update the root we need to check whether it ends
+	   * with a large span of silence.
+	   */
+	  i_silence_test(root);
+
+	  /* Add the offset into our stage 2 statistics.
+	   *
+	   * Note that we convert our peculiar offset (which is in terms of
+	   * the relative positions of samples within each vector) back into
+	   * the actual offset between what A considers sample N and what B
+	   * considers sample N.
+	   *
+	   * We do this at the end of rift handling because any original
+	   * offset returned by i_iterate_stage2() might have been due to
+	   * dropped or duplicated samples.  Once we've fixed up the root
+	   * and the fragment, we have an offset which more reliably
+	   * indicates jitter.
+	   */
+	  offset_add_value(p,&p->stage2,offset+vecbegin-rb(root),callback);
+	}
+      }
+      if (l)i_cblock_destructor(l);
+      free_v_fragment(v);
+      return(1);
+      
+    } else { /* !i_iterate_stage2(...) */
+#if TRACE_PARANOIA & 2
+      fprintf(stderr, "no match");
+#endif
+
+      /* We were unable to merge this fragment into the root.
+       *
+       * Check whether the fragment should have overlapped with the root,
+       * even taking possible jitter into account.  (I.e., If the fragment
+       * ends so far before the end of the root that even (dynoverlap)
+       * samples of jitter couldn't push it beyond the end of the root,
+       * it should have overlapped.)
+       *
+       * It is, however, possible that we failed to match using the normal
+       * tests because we're dealing with silence, which we handle
+       * separately.
+       *
+       * If the fragment should have overlapped, and we're not dealing
+       * with the special silence case, we don't know what to make of
+       * this fragment, and we just discard it.
+       */
+      if (fe(v)+dynoverlap<re(root) && !root->silenceflag){
+	/* It *should* have matched.  No good; free it. */
+	free_v_fragment(v);
+#if TRACE_PARANOIA & 2
+	fprintf(stderr, ", discarding fragment.");
+#endif
+      }
+
+#if TRACE_PARANOIA & 2
+      fprintf(stderr, "\n");
+#endif
+
+      /* otherwise, we likely want this for an upcoming match */
+      /* we don't free the sort info (if it was collected) */
+      return(0);
+      
+    }
+  } /* endif rv(root) */
+}
+
+static int 
+i_init_root(root_block *root, v_fragment_t *v,long int begin,
+		       void(*callback)(long int, paranoia_cb_mode_t))
+{
+  if (fb(v)<=begin && fe(v)>begin){
+    
+    root->lastsector=v->lastsector;
+    root->returnedlimit=begin;
+
+    if (rv(root)){
+      i_cblock_destructor(rc(root));
+      rc(root)=NULL;
+    }
+
+    {
+      int16_t *buff=malloc(fs(v)*sizeof(int16_t));
+      memcpy(buff,fv(v),fs(v)*sizeof(int16_t));
+      root->vector=c_alloc(buff,fb(v),fs(v));
+    }    
+
+    /* Check whether the new root has a long span of trailing silence.
+     */
+    i_silence_test(root);
+
+#if TRACE_PARANOIA & 2
+    fprintf(stderr,
+	    "* Assigning fragment [%ld-%ld] to root, silencebegin=%ld\n",
+	    rb(root), re(root), root->silencebegin);
+#endif
+
+    return(1);
+  } else
+    return(0);
+}
+
+static int 
+vsort(const void *a,const void *b)
+{
+  return((*(v_fragment_t **)a)->begin-(*(v_fragment_t **)b)->begin);
+}
+
+
+/* ===========================================================================
+ * i_stage2 (internal)
+ *
+ * This function attempts to extend the verified root by merging verified
+ * fragments into it.  It keeps extending the tail end of the root until
+ * it runs out of matching fragments.  See i_stage2_each (and
+ * i_iterate_stage2) for details of fragment matching and merging.
+ *
+ * This function is called by paranoia_read_limited when the verified root
+ * doesn't contain sufficient data to satisfy the request for samples.
+ * If this function fails to extend the verified root far enough (having
+ * exhausted the currently available verified fragments), the caller
+ * will then read the device again to try and establish more verified
+ * fragments.
+ *
+ * We first try to merge all the fragments in ascending order using the
+ * standard method (i_stage2_each()), and then we try to merge the
+ * remaining fragments using silence matching (i_silence_match())
+ * if the root has a long span of trailing silence.  See the initial
+ * comments on silence and  i_silence_match() for an explanation of this
+ * distinction.
+ *
+ * This function returns the number of verified fragments successfully
+ * merged into the verified root.
+ */
+static int 
+i_stage2(cdrom_paranoia_t *p, long int beginword, long int endword,
+	 void (*callback)(long int, paranoia_cb_mode_t))
+{
+
+  int flag=1,ret=0;
+  root_block *root=&(p->root);
+
+#ifdef NOISY
+  fprintf(stderr,"Fragments:%ld\n",p->fragments->active);
+  fflush(stderr);
+#endif
+
+  /* even when the 'silence flag' is lit, we try to do non-silence
+     matching in the event that there are still audio vectors with
+     content to be sunk before the silence */
+
+  /* This flag is not the silence flag.  Rather, it indicates whether
+   * we succeeded in adding a verified fragment to the verified root.
+   * In short, we keep adding fragments until we no longer find a
+   * match.
+   */
+  while (flag) {
+
+    /* Convert the linked list of verified fragments into an array,
+     * to be sorted in order of beginning sample position
+     */
+    v_fragment_t *first=v_first(p);
+    long active=p->fragments->active,count=0;
+    v_fragment_t **list = calloc(active, sizeof(v_fragment_t *));
+
+    while (first){
+      v_fragment_t *next=v_next(first);
+      list[count++]=first;
+      first=next;
+    }
+
+    /* Reset the flag so that if we don't match any fragments, we
+     * stop looping.  Then, proceed only if there are any fragments
+     * to match.
+     */
+    flag=0;
+    if (count){
+
+      /* Sort the array of verified fragments in order of beginning
+       * sample position.
+       */
+      qsort(list,active,sizeof(v_fragment_t *),&vsort);
+
+      /* We don't check for the silence flag yet, because even if the
+       * verified root ends in silence (and thus the silence flag is set),
+       * there may be a non-silent region at the beginning of the verified
+       * root, into which we can merge the verified fragments.
+       */
+
+      /* Iterate through the verified fragments, starting at the fragment
+       * with the lowest beginning sample position.
+       */
+      for(count=0;count<active;count++){
+	first=list[count];
+
+	/* Make sure this fragment hasn't already been merged (and
+	 * thus freed). */
+	if (first->one){
+
+	  /* If we don't have a verified root yet, just promote the first
+	   * fragment (with lowest beginning sample) to be the verified
+	   * root.
+	   *
+	   * ??? It seems that this could be fairly arbitrary if jitter
+	   * is an issue.  If we've verified two fragments allegedly
+	   * beginning at "0" (which are actually slightly offset due to
+	   * jitter), the root might not begin at the earliest read
+	   * sample.  Additionally, because subsequent fragments are
+	   * only merged at the tail end of the root, this situation
+	   * won't be fixed by merging the earlier samples.
+	   *
+	   * Practically, this ends up not being critical since most
+	   * drives insert some extra silent samples at the beginning
+	   * of the stream.  Missing a few of them doesn't cause any
+	   * real lost data.  But it is non-deterministic.
+	   */
+	  if (rv(root)==NULL){
+	    if (i_init_root(&(p->root),first,beginword,callback)){
+	      free_v_fragment(first);
+
+	      /* Consider this a merged fragment, so set the flag
+	       * to keep looping.
+	       */
+	      flag=1;
+	      ret++;
+	    }
+	  } else {
+
+	    /* Try to merge this fragment with the verified root,
+	     * extending the tail of the root.
+	     */
+	    if (i_stage2_each(root,first,callback)){
+
+	      /* If we successfully merged the fragment, set the flag
+	       * to keep looping.
+	       */
+	      ret++;
+	      flag=1;
+	    }
+	  }
+	}
+      }
+
+      /* If the verified root ends in a long span of silence, iterate
+       * through the remaining unmerged fragments to see if they can be
+       * merged using our special silence matching.
+       */
+      if (!flag && p->root.silenceflag){
+	for(count=0;count<active;count++){
+	  first=list[count];
+
+	  /* Make sure this fragment hasn't already been merged (and
+	   * thus freed). */
+	  if (first->one){
+	    if (rv(root)!=NULL){
+
+	      /* Try to merge the fragment into the root.  This will only
+	       * succeed if the fragment overlaps and begins with sufficient
+	       * silence to be a presumed match.
+	       *
+	       * Note that the fragments must be passed to i_silence_match()
+	       * in ascending order, as they are here.
+	       */
+	      if (i_silence_match(root,first,callback)){
+
+		/* If we successfully merged the fragment, set the flag
+		 * to keep looping.
+		 */
+		ret++;
+		flag=1;
+	      }
+	    }
+	  }
+	} /* end for */
+      }
+    } /* end if(count) */
+    free(list);
+
+    /* If we were able to extend the verified root at all during this pass
+     * through the loop, loop again to see if we can merge any remaining
+     * fragments with the extended root.
+     */
+
+#if TRACE_PARANOIA & 2
+    if (flag)
+      fprintf(stderr,
+	      "- Root updated, comparing remaining fragments again.\n");
+#endif
+
+  } /* end while */
+
+  /* Return the number of fragments we successfully merged into the
+   * verified root.
+   */
+  return(ret);
+}
+
+
+static void 
+i_end_case(cdrom_paranoia_t *p,long endword, 
+	   void(*callback)(long int, paranoia_cb_mode_t))
+{
+
+  root_block *root=&p->root;
+
+  /* have an 'end' flag; if we've just read in the last sector in a
+     session, set the flag.  If we verify to the end of a fragment
+     which has the end flag set, we're done (set a done flag).  Pad
+     zeroes to the end of the read */
+  
+  if (root->lastsector==0)return;
+  if (endword<re(root))return;
+  
+  {
+    long addto=endword-re(root);
+    char *temp=calloc(addto,sizeof(char)*2);
+
+    c_append(rc(root),(void *)temp,addto);
+    free(temp);
+
+    /* trash da cache */
+    paranoia_resetcache(p);
+
+  }
+}
+
+/* We want to add a sector. Look through the caches for something that
+   spans.  Also look at the flags on the c_block... if this is an
+   obliterated sector, get a bit of a chunk past the obliteration. */
+
+/* Not terribly smart right now, actually.  We can probably find
+   *some* match with a cache block somewhere.  Take it and continue it
+   through the skip */
+
+static void 
+verify_skip_case(cdrom_paranoia_t *p,
+		 void(*callback)(long int, paranoia_cb_mode_t))
+{
+
+  root_block *root=&(p->root);
+  c_block_t *graft=NULL;
+  int vflag=0;
+  int gend=0;
+  long post;
+  
+#ifdef NOISY
+	fprintf(stderr,"\nskipping\n");
+#endif
+
+  if (rv(root)==NULL){
+    post=0;
+  } else {
+    post=re(root);
+  }
+  if (post==-1)post=0;
+
+  if (callback)(*callback)(post,PARANOIA_CB_SKIP);
+  
+#if TRACE_PARANOIA
+  fprintf(stderr, "Skipping [%ld-", post);
+#endif
+
+  /* We want to add a sector.  Look for a c_block that spans,
+     preferrably a verified area */
+
+  {
+    c_block_t *c=c_first(p);
+    while (c){
+      long cbegin=cb(c);
+      long cend=ce(c);
+      if (cbegin<=post && cend>post){
+	long vend=post;
+
+	if (c->flags[post-cbegin]&FLAGS_VERIFIED){
+	  /* verified area! */
+	  while (vend<cend && (c->flags[vend-cbegin]&FLAGS_VERIFIED))vend++;
+	  if (!vflag || vend>vflag){
+	    graft=c;
+	    gend=vend;
+	  }
+	  vflag=1;
+	} else {
+	  /* not a verified area */
+	  if (!vflag){
+	    while (vend<cend && (c->flags[vend-cbegin]&FLAGS_VERIFIED)==0)vend++;
+	    if (graft==NULL || gend>vend){
+	      /* smallest unverified area */
+	      graft=c;
+	      gend=vend;
+	    }
+	  }
+	}
+      }
+      c=c_next(c);
+    }
+
+    if (graft){
+      long cbegin=cb(graft);
+      long cend=ce(graft);
+
+      while (gend<cend && (graft->flags[gend-cbegin]&FLAGS_VERIFIED))gend++;
+      gend=min(gend+OVERLAP_ADJ,cend);
+
+      if (rv(root)==NULL){
+	int16_t *buff=malloc(cs(graft));
+	memcpy(buff,cv(graft),cs(graft));
+	rc(root)=c_alloc(buff,cb(graft),cs(graft));
+      } else {
+	c_append(rc(root),cv(graft)+post-cbegin,
+		 gend-post);
+      }
+
+#if TRACE_PARANOIA
+      fprintf(stderr, "%d], filled with %s data from block [%ld-%ld]\n",
+	      gend, (graft->flags[post-cbegin]&FLAGS_VERIFIED)
+	      ? "verified" : "unverified", cbegin, cend);
+#endif
+
+      root->returnedlimit=re(root);
+      return;
+    }
+  }
+
+  /* No?  Fine.  Great.  Write in some zeroes :-P */
+  {
+    void *temp=calloc(CDIO_CD_FRAMESIZE_RAW,sizeof(int16_t));
+
+    if (rv(root)==NULL){
+      rc(root)=c_alloc(temp,post,CDIO_CD_FRAMESIZE_RAW);
+    } else {
+      c_append(rc(root),temp,CDIO_CD_FRAMESIZE_RAW);
+      free(temp);
+    }
+
+#if TRACE_PARANOIA
+    fprintf(stderr, "%ld], filled with zero\n", re(root));
+#endif
+
+    root->returnedlimit=re(root);
+  }
+}    
+
+/**** toplevel ****************************************/
+
+void 
+paranoia_free(cdrom_paranoia_t *p)
+{
+  paranoia_resetall(p);
+  sort_free(p->sortcache);
+  free_list(p->cache, 1);
+  free_list(p->fragments, 1);
+  free(p);
+}
+
+/*! 
+  Set the kind of repair you want to on for reading. 
+  The modes are listed above
+  
+  @param p       paranoia type
+  @mode  mode    paranoia mode flags built from values in 
+  paranoia_mode_t, e.g. 
+  PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP
+*/
+void 
+paranoia_modeset(cdrom_paranoia_t *p, int mode_flags)
+{
+  p->enable=mode_flags;
+}
+
+/*!
+  reposition reading offset. 
+  
+  @param p       paranoia type
+  @param seek    byte offset to seek to
+  @param whence  like corresponding parameter in libc's lseek, e.g. 
+  SEEK_SET or SEEK_END.
+*/
+lsn_t
+paranoia_seek(cdrom_paranoia_t *p, int32_t seek, int whence)
+{
+  long sector;
+  long ret;
+  switch(whence){
+  case SEEK_SET:
+    sector=seek;
+    break;
+  case SEEK_END:
+    sector=cdda_disc_lastsector(p->d)+seek;
+    break;
+  default:
+    sector=p->cursor+seek;
+    break;
+  }
+  
+  if (cdda_sector_gettrack(p->d,sector)==-1)return(-1);
+
+  i_cblock_destructor(p->root.vector);
+  p->root.vector=NULL;
+  p->root.lastsector=0;
+  p->root.returnedlimit=0;
+
+  ret=p->cursor;
+  p->cursor=sector;
+
+  i_paranoia_firstlast(p);
+  
+  /* Evil hack to fix pregap patch for NEC drives! To be rooted out in a10 */
+  p->current_firstsector=sector;
+
+  return(ret);
+}
+
+
+
+/* ===========================================================================
+ * read_c_block() (internal)
+ *
+ * This funtion reads many (p->readahead) sectors, encompassing at least
+ * the requested words.
+ *
+ * It returns a c_block which encapsulates these sectors' data and sector
+ * number.  The sectors come come from multiple low-level read requests.
+ *
+ * This function reads many sectors in order to exhaust any caching on the
+ * drive itself, as caching would simply return the same incorrect data
+ * over and over.  Paranoia depends on truly re-reading portions of the
+ * disc to make sure the reads are accurate and correct any inaccuracies.
+ *
+ * Which precise sectors are read varies ("jiggles") between calls to
+ * read_c_block, to prevent consistent errors across multiple reads
+ * from being misinterpreted as correct data.
+ *
+ * The size of each low-level read is determined by the underlying driver
+ * (p->d->nsectors), which allows the driver to specify how many sectors
+ * can be read in a single request.  Historically, the Linux kernel could
+ * only read 8 sectors at a time, with likely dropped samples between each
+ * read request.  Other operating systems may have different limitations.
+ *
+ * This function is called by paranoia_read_limited(), which breaks the
+ * c_block of read data into runs of samples that are likely to be
+ * contiguous, verifies them and stores them in verified fragments, and
+ * eventually merges the fragments into the verified root.
+ *
+ * This function returns the last c_block read or NULL on error.
+ */
+
+static c_block_t *
+i_read_c_block(cdrom_paranoia_t *p,long beginword,long endword,
+	       void(*callback)(long, paranoia_cb_mode_t))
+{
+
+/* why do it this way?  We need to read lots of sectors to kludge
+   around stupid read ahead buffers on cheap drives, as well as avoid
+   expensive back-seeking. We also want to 'jiggle' the start address
+   to try to break borderline drives more noticeably (and make broken
+   drives with unaddressable sectors behave more often). */
+      
+  long readat,firstread;
+  long totaltoread=p->readahead;
+  long sectatonce=p->d->nsectors;
+  long driftcomp=(float)p->dyndrift/CD_FRAMEWORDS+.5;
+  c_block_t *new=NULL;
+  root_block *root=&p->root;
+  int16_t *buffer=NULL;
+  unsigned char *flags=NULL;
+  long sofar;
+  long dynoverlap=(p->dynoverlap+CD_FRAMEWORDS-1)/CD_FRAMEWORDS; 
+  long anyflag=0;
+
+
+  /* Calculate the first sector to read.  This calculation takes
+   * into account the need to jitter the starting point of the read
+   * to reveal consistent errors as well as the low reliability of
+   * the edge words of a read.
+   *
+   * ???: Document more clearly how dynoverlap and MIN_SECTOR_BACKUP
+   * are calculated and used.
+   */
+
+  /* What is the first sector to read?  want some pre-buffer if
+     we're not at the extreme beginning of the disc */
+  
+  if (p->enable&(PARANOIA_MODE_VERIFY|PARANOIA_MODE_OVERLAP)){
+    
+    /* we want to jitter the read alignment boundary */
+    long target;
+    if (rv(root)==NULL || rb(root)>beginword)
+      target=p->cursor-dynoverlap; 
+    else
+      target=re(root)/(CD_FRAMEWORDS)-dynoverlap;
+	
+    if (target+MIN_SECTOR_BACKUP>p->lastread && target<=p->lastread)
+      target=p->lastread-MIN_SECTOR_BACKUP;
+
+    /* we want to jitter the read alignment boundary, as some
+       drives, beginning from a specific point, will tend to
+       lose bytes between sectors in the same place.  Also, as
+       our vectors are being made up of multiple reads, we want
+       the overlap boundaries to move.... */
+    
+    readat=(target&(~((long)JIGGLE_MODULO-1)))+p->jitter;
+    if (readat>target)readat-=JIGGLE_MODULO;
+    p->jitter++;
+    if (p->jitter>=JIGGLE_MODULO)
+      p->jitter=0;
+     
+  } else {
+    readat=p->cursor; 
+  }
+  
+  readat+=driftcomp;
+
+  /* Create a new, empty c_block and add it to the head of the
+   * list of c_blocks in memory.  It will be empty until the end of
+   * this subroutine.
+   */
+  if (p->enable&(PARANOIA_MODE_OVERLAP|PARANOIA_MODE_VERIFY)) {
+    flags=calloc(totaltoread*CD_FRAMEWORDS, 1);
+    new=new_c_block(p);
+    recover_cache(p);
+  } else {
+    /* in the case of root it's just the buffer */
+    paranoia_resetall(p);	
+    new=new_c_block(p);
+  }
+
+  buffer=calloc(totaltoread*CDIO_CD_FRAMESIZE_RAW, 1);
+  sofar=0;
+  firstread=-1;
+
+#if TRACE_PARANOIA
+  fprintf(stderr, "Reading [%ld-%ld] from media\n",
+	  readat*CD_FRAMEWORDS, (readat+totaltoread)*CD_FRAMEWORDS);
+#endif
+
+  /* Issue each of the low-level reads until we've read enough sectors
+   * to exhaust the drive's cache.
+   *
+   * p->readahead   = total number of sectors to read
+   * p->d->nsectors = number of sectors to read per request
+   *
+   * The driver determines this latter number, which is the maximum
+   * number of sectors the kernel can reliably read per request.  In
+   * old Linux kernels, there was a hard limit of 8 sectors per read.
+   * While this limit has since been removed, certain motherboards
+   * can't handle DMA requests larger than 64K.  And other operating
+   * systems may have similar limitations.  So the method of splitting
+   * up reads is still useful.
+   */
+
+  /* actual read loop */
+
+  while (sofar<totaltoread){
+    long secread=sectatonce;  /* number of sectors to read this request */
+    long adjread=readat;      /* first sector to read for this request */
+    long thisread;            /* how many sectors were read this request */
+
+    /* don't under/overflow the audio session */
+    if (adjread<p->current_firstsector){
+      secread-=p->current_firstsector-adjread;
+      adjread=p->current_firstsector;
+    }
+    if (adjread+secread-1>p->current_lastsector)
+      secread=p->current_lastsector-adjread+1;
+    
+    if (sofar+secread>totaltoread)secread=totaltoread-sofar;
+    
+    if (secread>0){
+      
+      if (firstread<0) firstread = adjread;
+
+      /* Issue the low-level read to the driver.
+       */
+
+      thisread = cdda_read(p->d, buffer+sofar*CD_FRAMEWORDS, adjread, secread);
+
+#if TRACE_PARANOIA & 1
+      fprintf(stderr, "- Read [%ld-%ld] (0x%04X...0x%04X)%s",
+	      adjread*CD_FRAMEWORDS, (adjread+thisread)*CD_FRAMEWORDS,
+	      buffer[sofar*CD_FRAMEWORDS] & 0xFFFF,
+	      buffer[(sofar+thisread)*CD_FRAMEWORDS - 1] & 0xFFFF,
+	      thisread < secread ? "" : "\n");
+#endif
+
+      /* If the low-level read returned too few sectors, pad the result
+       * with null data and mark it as invalid (FLAGS_UNREAD).  We pad
+       * because we're going to be appending further reads to the current
+       * c_block.
+       *
+       * ???: Why not re-read?  It might be to keep you from getting
+       * hung up on a bad sector.  Or it might be to avoid interrupting
+       * the streaming as much as possible.
+       */
+      if ( thisread < secread) {
+
+	if (thisread<0) thisread=0;
+
+#if TRACE_PARANOIA & 1
+	fprintf(stderr, " -- couldn't read [%ld-%ld]\n",
+		(adjread+thisread)*CD_FRAMEWORDS,
+		(adjread+secread)*CD_FRAMEWORDS);
+#endif
+
+	/* Uhhh... right.  Make something up. But don't make us seek
+           backward! */
+
+	if (callback)
+	  (*callback)((adjread+thisread)*CD_FRAMEWORDS, PARANOIA_CB_READERR);  
+	memset(buffer+(sofar+thisread)*CD_FRAMEWORDS,0,
+	       CDIO_CD_FRAMESIZE_RAW*(secread-thisread));
+	if (flags)
+          memset(flags+(sofar+thisread)*CD_FRAMEWORDS, FLAGS_UNREAD,
+	         CD_FRAMEWORDS*(secread-thisread));
+      }
+      if (thisread!=0)anyflag=1;
+
+
+      /* Because samples are likely to be dropped between read requests,
+       * mark the samples near the the boundaries of the read requests
+       * as suspicious (FLAGS_EDGE).  This means that any span of samples
+       * against which these adjacent read requests are compared must
+       * overlap beyond the edges and into the more trustworthy data.
+       * Such overlapping spans are accordingly at least MIN_WORDS_OVERLAP
+       * words long (and naturally longer if any samples were dropped
+       * between the read requests).
+       *
+       *          (EEEEE...overlapping span...EEEEE)
+       * (read 1 ...........EEEEE)   (EEEEE...... read 2 ......EEEEE) ...
+       *         dropped samples --^
+       */
+      if (flags && sofar!=0){
+	/* Don't verify across overlaps that are too close to one
+           another */
+	int i=0;
+	for(i=-MIN_WORDS_OVERLAP/2;i<MIN_WORDS_OVERLAP/2;i++)
+	  flags[sofar*CD_FRAMEWORDS+i]|=FLAGS_EDGE;
+      }
+
+
+      /* Move the read cursor ahead by the number of sectors we attempted
+       * to read.
+       *
+       * ???: Again, why not move it ahead by the number actually read?
+       */
+      p->lastread=adjread+secread;
+      
+      if (adjread+secread-1==p->current_lastsector)
+	new->lastsector=-1;
+      
+      if (callback)(*callback)((adjread+secread-1)*CD_FRAMEWORDS,PARANOIA_CB_READ);
+      
+      sofar+=secread;
+      readat=adjread+secread; 
+    } else /* secread <= 0 */
+      if (readat<p->current_firstsector)
+	readat+=sectatonce; /* due to being before the readable area */
+      else
+	break; /* due to being past the readable area */
+
+
+    /* Keep issuing read requests until we've read enough sectors to
+     * exhaust the drive's cache.
+     */
+
+  } /* end while */
+
+
+  /* If we managed to read any sectors at all (anyflag), fill in the
+   * previously allocated c_block with the read data.  Otherwise, free
+   * our buffers, dispose of the c_block, and return NULL.
+   */
+  if (anyflag) {
+    new->vector=buffer;
+    new->begin=firstread*CD_FRAMEWORDS-p->dyndrift;
+    new->size=sofar*CD_FRAMEWORDS;
+    new->flags=flags;
+
+#if TRACE_PARANOIA
+    fprintf(stderr, "- Read block %ld:[%ld-%ld] from media\n",
+	    p->cache->active, cb(new), ce(new));
+#endif
+  } else {
+    if (new)free_c_block(new);
+    free(buffer);
+    free(flags);
+    new=NULL;
+  }
+  return(new);
+}
+
+
+/** ==========================================================================
+ * cdio_paranoia_read(), cdio_paranoia_read_limited()
+ *
+ * These functions "read" the next sector of audio data and returns
+ * a pointer to a full sector of verified samples (2352 bytes).
+ *
+ * The returned buffer is *not* to be freed by the caller.  It will
+ *   persist only until the next call to paranoia_read() for this p 
+*/
+
+int16_t *
+cdio_paranoia_read(cdrom_paranoia_t *p, 
+		   void(*callback)(long, paranoia_cb_mode_t))
+{
+  return paranoia_read_limited(p, callback, 20);
+}
+
+/* I added max_retry functionality this way in order to avoid
+   breaking any old apps using the nerw libs.  cdparanoia 9.8 will
+   need the updated libs, but nothing else will require it. */
+int16_t *
+cdio_paranoia_read_limited(cdrom_paranoia_t *p, 
+			   void(*callback)(long int, paranoia_cb_mode_t),
+			   int max_retries)
+{
+  long int beginword  =  p->cursor*(CD_FRAMEWORDS);
+  long int endword    =  beginword+CD_FRAMEWORDS;
+  long int retry_count=  0;
+  long int lastend    = -2;
+  root_block *root    = &p->root;
+
+  if (beginword > p->root.returnedlimit)
+    p->root.returnedlimit=beginword;
+  lastend=re(root);
+
+
+  /* Since paranoia reads and verifies chunks of data at a time
+   * (which it needs to counteract dropped samples and inaccurate
+   * seeking), the requested samples may already be in memory,
+   * in the verified "root".
+   *
+   * The root is where paranoia stores samples that have been
+   * verified and whose position has been accurately determined.
+   */
+  
+  /* First, is the sector we want already in the root? */
+  while (rv(root)==NULL ||
+	rb(root)>beginword || 
+	(re(root)<endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS) &&
+	 p->enable&(PARANOIA_MODE_VERIFY|PARANOIA_MODE_OVERLAP)) ||
+	re(root)<endword){
+    
+    /* Nope; we need to build or extend the root verified range */
+
+#if TRACE_PARANOIA
+    fprintf(stderr, "Trying to expand root [%ld-%ld]...\n",
+	    rb(root), re(root));
+#endif
+
+    /* We may have already read the necessary samples and placed
+     * them into verified fragments, but not yet merged them into
+     * the verified root.  We'll check that before we actually
+     * try to read data from the drive.
+     */
+
+    if (p->enable&(PARANOIA_MODE_VERIFY|PARANOIA_MODE_OVERLAP)){
+
+      /* We need to make sure our memory consumption doesn't grow
+       * to the size of the whole CD.  But at the same time, we
+       * need to hang onto some of the verified data (even perhaps
+       * data that's already been returned by paranoia_read()) in
+       * order to verify and accurately position future samples.
+       *
+       * Therefore, we free some of the verified data that we
+       * no longer need.
+       */
+      i_paranoia_trim(p,beginword,endword);
+      recover_cache(p);
+
+      if (rb(root)!=-1 && p->root.lastsector)
+	i_end_case(p, endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS),
+			callback);
+      else
+
+	/* Merge as many verified fragments into the verified root
+	 * as we need to satisfy the pending request.  We may
+	 * not have all the fragments we need, in which case we'll
+	 * read data from the CD further below.
+	 */
+	i_stage2(p, beginword,
+		      endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS),
+		      callback);
+    } else
+      i_end_case(p,endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS),
+		 callback); /* only trips if we're already done */
+
+#if TRACE_PARANOIA
+    fprintf(stderr, "- Root is now [%ld-%ld] silencebegin=%ld\n",
+	    rb(root), re(root), root->silencebegin);
+#endif
+
+    /* If we were able to fill the verified root with data already
+     * in memory, we don't need to read any more data from the drive.
+     */
+    if (!(rb(root)==-1 || rb(root)>beginword || 
+	 re(root)<endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS))) 
+      break;
+    
+    /* Hmm, need more.  Read another block */
+
+    {
+      /* Read many sectors, encompassing at least the requested words.
+       *
+       * The returned c_block encapsulates these sectors' data and
+       * sector number.  The sectors come come from multiple low-level
+       * read requests, and words which were near the boundaries of
+       * those read requests are marked with FLAGS_EDGE.
+       */
+      c_block_t *new=i_read_c_block(p,beginword,endword,callback);
+      
+      if (new){
+	if (p->enable&(PARANOIA_MODE_OVERLAP|PARANOIA_MODE_VERIFY)){
+      
+	  /* If we need to verify these samples, send them to
+	   * stage 1 verification, which will add verified samples
+	   * to the set of verified fragments.  Verified fragments
+	   * will be merged into the verified root during stage 2
+	   * overlap analysis.
+	   */
+	  if (p->enable&PARANOIA_MODE_VERIFY)
+	    i_stage1(p,new,callback);
+
+	  /* If we're only doing overlapping reads (no stage 1
+	   * verification), consider each low-level read in the
+	   * c_block to be a verified fragment.  We exclude the
+	   * edges from these fragments to enforce the requirement
+	   * that we overlap the reads by the minimum amount.
+	   * These fragments will be merged into the verified
+	   * root during stage 2 overlap analysis.
+	   */
+	  else{
+	    /* just make v_fragments from the boundary information. */
+	    long begin=0,end=0;
+	    
+	    while (begin<cs(new)){
+	      /* ???BUG??? This while() should probably read begin<cs(new).
+	       *
+	       * This bug is not fixed yet.
+	       */
+	      while (end<cs(new) && (new->flags[begin]&FLAGS_EDGE))begin++;
+	      end=begin+1;
+	      while (end<cs(new) && (new->flags[end]&FLAGS_EDGE)==0)end++;
+	      {
+		new_v_fragment(p,new,begin+cb(new),
+			       end+cb(new),
+			       (new->lastsector && cb(new)+end==ce(new)));
+	      }
+	      begin=end;
+	    }
+	  }
+	  
+	} else {
+
+	  /* If we're not doing any overlapping reads or verification
+	   * of data, skip over the stage 1 and stage 2 verification and
+	   * promote this c_block directly to the current "verified" root.
+	   */
+
+	  if (p->root.vector)i_cblock_destructor(p->root.vector);
+	  free_elem(new->e,0);
+	  p->root.vector=new;
+
+	  i_end_case(p,endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS),
+			  callback);
+      
+	}
+      }
+    }
+
+    /* Are we doing lots of retries?  **************************************/
+
+    /* ???: To be studied
+     */
+
+    /* Check unaddressable sectors first.  There's no backoff here; 
+       jiggle and minimum backseek handle that for us */
+    
+    if (rb(root)!=-1 && lastend+588<re(root)){ /* If we've not grown
+						 half a sector */
+      lastend=re(root);
+      retry_count=0;
+    } else {
+      /* increase overlap or bail */
+      retry_count++;
+      
+      /* The better way to do this is to look at how many actual
+	 matches we're getting and what kind of gap */
+
+      if (retry_count%5==0){
+	if (p->dynoverlap==MAX_SECTOR_OVERLAP*CD_FRAMEWORDS ||
+	   retry_count==max_retries){
+	  if (!(p->enable&PARANOIA_MODE_NEVERSKIP))
+	    verify_skip_case(p,callback);
+	  retry_count=0;
+	} else {
+	  if (p->stage1.offpoints!=-1){ /* hack */
+	    p->dynoverlap*=1.5;
+	    if (p->dynoverlap>MAX_SECTOR_OVERLAP*CD_FRAMEWORDS)
+	      p->dynoverlap=MAX_SECTOR_OVERLAP*CD_FRAMEWORDS;
+	    if (callback)
+	      (*callback)(p->dynoverlap,PARANOIA_CB_OVERLAP);
+	  }
+	}
+      }
+    }
+
+    /* Having read data from the drive and placed it into verified
+     * fragments, we now loop back to try to extend the root with
+     * the newly loaded data.  Alternatively, if the root already
+     * contains the needed data, we'll just fall through.
+     */
+
+  } /* end while */
+  p->cursor++;
+
+  /* Return a pointer into the verified root.  Thus, the caller
+   * must NOT free the returned pointer!
+   */
+  return(rv(root)+(beginword-rb(root)));
+}
+
+/* a temporary hack */
+void 
+cdio_paranoia_overlapset(cdrom_paranoia_t *p, long int overlap)
+{
+  p->dynoverlap=overlap*CD_FRAMEWORDS;
+  p->stage1.offpoints=-1; 
+}
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/src/Makefile.am libcdio-c742eed/src/Makefile.am
--- libcdio-f9bd26c/src/Makefile.am	2012-02-26 05:06:04 +0900
+++ libcdio-c742eed/src/Makefile.am	2012-02-26 05:07:35 +0900
@@ -21,6 +23,10 @@
 # Things to make the utility/diagnostic programs
 ####################################################
 
+if BUILD_CD_PARANOIA
+SUBDIRS =  cd-paranoia
+endif
+
 CDDB_LIBS=@CDDB_LIBS@
 CDDA_PLAYER_LIBS=@CDDA_PLAYER_LIBS@
 
diff -urN '-x.git*' '-x.cvs*' -xrealpath.c libcdio-f9bd26c/test/Makefile.am libcdio-c742eed/test/Makefile.am
--- libcdio-f9bd26c/test/Makefile.am	2012-02-26 05:07:53 +0900
+++ libcdio-c742eed/test/Makefile.am	2012-02-26 05:07:35 +0900
@@ -23,6 +23,11 @@
 
 SUBDIRS = data driver
 
+if BUILD_CD_PARANOIA
+testparanoia=testparanoia
+testparanoia_LDADD = $(LIBCDIO_PARANOIA_LIBS) $(LIBCDIO_CDDA_LIBS) $(LIBCDIO_LIBS) $(LTLIBICONV)
+endif
+
 hack = check_sizeof testassert testgetdevices testischar \
        testisocd testisocd2 testiso9660 test_lib_driver_util \
        $(testparanoia) testpregap testunconfig
