changeset 24047:de28f9e8cb00

Sync libdvdread with version 0.9.5 (functional changes).
author diego
date Wed, 15 Aug 2007 11:47:22 +0000
parents 7e2808fb1807
children fe3043a8552c
files Changelog Copyright configure dvdread/Makefile dvdread/bswap.h dvdread/dvd_input.c dvdread/dvd_input.h dvdread/dvd_reader.c dvdread/dvd_reader.h dvdread/dvd_udf.c dvdread/dvd_udf.h dvdread/dvdread_internal.h dvdread/ifo_print.c dvdread/ifo_read.c dvdread/ifo_types.h dvdread/nav_print.c dvdread/nav_read.c dvdread/nav_types.h stream/stream_dvd_common.c
diffstat 19 files changed, 1089 insertions(+), 236 deletions(-) [+]
line wrap: on
line diff
--- a/Changelog	Wed Aug 15 10:34:53 2007 +0000
+++ b/Changelog	Wed Aug 15 11:47:22 2007 +0000
@@ -112,6 +112,7 @@
     * ability to change subtitle size during playback
     * ability to turn loop on/off during playback
     * Apple Remote support
+    * libdvdread updated to 0.9.5
 
 
   rc1: "Codename intentionally left blank" October 22, 2006
--- a/Copyright	Wed Aug 15 10:34:53 2007 +0000
+++ b/Copyright	Wed Aug 15 11:47:22 2007 +0000
@@ -49,7 +49,7 @@
 License:    GNU General Public License
 
 Name:       libdvdread
-Version:    0.9.4 + patches
+Version:    0.9.5 + patches
 Homepage:   http://www.dtek.chalmers.se/groups/dvd/development.shtml
 Directory:  dvdread
 Copyright:  1998, 1999 Eric Smith <eric@brouhaha.com>
--- a/configure	Wed Aug 15 10:34:53 2007 +0000
+++ b/configure	Wed Aug 15 11:47:22 2007 +0000
@@ -7744,6 +7744,9 @@
 #define HAVE_MEMCPY 1
 #define HAVE_STRCHR 1
 
+/* libdvdread */
+#define HAVE_UINTPTR_T 1
+
 /* name of messages charset */
 $_def_charset
 
--- a/dvdread/Makefile	Wed Aug 15 10:34:53 2007 +0000
+++ b/dvdread/Makefile	Wed Aug 15 11:47:22 2007 +0000
@@ -10,6 +10,7 @@
               nav_print.c \
               nav_read.c \
               md5.c \
+              cmd_print.c \
 
 CFLAGS = -D__USE_UNIX98 -D_GNU_SOURCE
 
--- a/dvdread/bswap.h	Wed Aug 15 10:34:53 2007 +0000
+++ b/dvdread/bswap.h	Wed Aug 15 11:47:22 2007 +0000
@@ -61,7 +61,19 @@
 #include <sys/endian.h>
 #define B2N_16(x) x = be16toh(x)
 #define B2N_32(x) x = be32toh(x)
+#if __FreeBSD_version >= 500000
 #define B2N_64(x) x = be64toh(x)
+#else
+#define B2N_64(x)                               \
+  x = ((((x) & 0xff00000000000000) >> 56) |     \
+       (((x) & 0x00ff000000000000) >> 40) |     \
+       (((x) & 0x0000ff0000000000) >> 24) |     \
+       (((x) & 0x000000ff00000000) >>  8) |     \
+       (((x) & 0x00000000ff000000) <<  8) |     \
+       (((x) & 0x0000000000ff0000) << 24) |     \
+       (((x) & 0x000000000000ff00) << 40) |     \
+       (((x) & 0x00000000000000ff) << 56))
+#endif /* _FreeBSD_version >= 500000 */
 
 #elif defined(__DragonFly__)
 #include <sys/endian.h>
@@ -113,7 +125,7 @@
  * functionality! 
  */
 
-#elif defined(__FreeBSD__) || defined(__sun) || defined(__bsdi__) || defined(__CYGWIN__)
+#elif defined(__FreeBSD__) || defined(__sun) || defined(__bsdi__) || defined(WIN32) || defined(__BEOS__) || defined(__INTERIX) || defined(__CYGWIN__)
 #define B2N_16(x) \
  x = ((((x) & 0xff00) >> 8) | \
       (((x) & 0x00ff) << 8))
--- a/dvdread/dvd_input.c	Wed Aug 15 10:34:53 2007 +0000
+++ b/dvdread/dvd_input.c	Wed Aug 15 11:47:22 2007 +0000
@@ -25,18 +25,26 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#define __USE_GNU /* to get O_DIRECT in linux */
 #include <fcntl.h>
 #include <unistd.h>
 
 #include "dvd_reader.h"
 #include "dvd_input.h"
 
+#include "dvdread_internal.h"
+
 /* The function pointers that is the exported interface of this file. */
 dvd_input_t (*dvdinput_open)  (const char *);
 int         (*dvdinput_close) (dvd_input_t);
 int         (*dvdinput_seek)  (dvd_input_t, int);
 int         (*dvdinput_title) (dvd_input_t, int); 
+/**
+ *  pointer must be aligned to 2048 bytes
+ *  if reading from a raw/O_DIRECT file
+ */
 int         (*dvdinput_read)  (dvd_input_t, void *, int, int);
+
 char *      (*dvdinput_error) (dvd_input_t);
 
 #ifdef HAVE_DVDCSS_DVDCSS_H
@@ -80,16 +88,15 @@
   /* Allocate the handle structure */
   dev = (dvd_input_t) malloc(sizeof(struct dvd_input_s));
   if(dev == NULL) {
-    fprintf(stderr, "libdvdread: Could not allocate memory.\n");
+    /* malloc has set errno to ENOMEM */
     return NULL;
   }
   
   /* Really open it with libdvdcss */
   dev->dvdcss = DVDcss_open(target);
   if(dev->dvdcss == 0) {
-    fprintf(stderr, "libdvdread: Could not open %s with libdvdcss.\n", target);
     free(dev);
-    return NULL;
+    dev = NULL;
   }
   
   return dev;
@@ -145,10 +152,14 @@
   return 0;
 }
 
-
-
-
-
+/* Need to use O_BINARY for WIN32 */
+#ifndef O_BINARY
+#ifdef _O_BINARY
+#define O_BINARY _O_BINARY
+#else
+#define O_BINARY 0
+#endif
+#endif
 
 /**
  * initialize and open a DVD device or file.
@@ -156,18 +167,26 @@
 static dvd_input_t file_open(const char *target)
 {
   dvd_input_t dev;
+  char *use_odirect;
+  int oflags;
   
+  oflags = O_RDONLY | O_BINARY;
+  use_odirect = getenv("DVDREAD_USE_DIRECT");
+  if(use_odirect) {
+#ifndef O_DIRECT
+#define O_DIRECT 0
+#endif
+    oflags |= O_DIRECT;
+  }
   /* Allocate the library structure */
   dev = (dvd_input_t) malloc(sizeof(struct dvd_input_s));
   if(dev == NULL) {
-    fprintf(stderr, "libdvdread: Could not allocate memory.\n");
     return NULL;
   }
   
   /* Open the device */
-  dev->fd = open(target, O_RDONLY);
+  dev->fd = open(target, oflags);
   if(dev->fd < 0) {
-    perror("libdvdread: Could not open input");
     free(dev);
     return NULL;
   }
@@ -189,9 +208,9 @@
  */
 static int file_seek(dvd_input_t dev, int blocks)
 {
-  off_t pos;
+  off_t pos = (off_t)blocks * (off_t)DVD_VIDEO_LB_LEN;
 
-  pos = lseek(dev->fd, (off_t)blocks * (off_t)DVD_VIDEO_LB_LEN, SEEK_SET);
+  pos = lseek(dev->fd, pos, SEEK_SET);
   if(pos < 0) {
       return pos;
   }
@@ -214,12 +233,13 @@
 {
   size_t len;
   ssize_t ret;
+  unsigned char *buf = buffer;
   
   len = (size_t)blocks * DVD_VIDEO_LB_LEN;
   
   while(len > 0) {
     
-    ret = read(dev->fd, buffer, len);
+    ret = read(dev->fd, buf, len);
     
     if(ret < 0) {
       /* One of the reads failed, too bad.  We won't even bother
@@ -238,6 +258,7 @@
       return (int) (bytes / DVD_VIDEO_LB_LEN);
     }
     
+    buf+=ret;
     len -= ret;
   }
 
@@ -262,13 +283,49 @@
 }
 
 
+static void *dvdcss_library = NULL;
+static int dvdcss_library_init = 0;
+
+/**
+ * Free any objects allocated by dvdinput_setup.
+ * Should only be called when libdvdread is not to be used any more.
+ * Closes dlopened libraries.
+ */
+void dvdinput_free(void)
+{
+#ifdef HAVE_DVDCSS_DVDCSS_H
+  /* linked statically, nothing to free */
+  return;
+#else
+  if(dvdcss_library) {
+    dlclose(dvdcss_library);
+    dvdcss_library = NULL;
+  }
+  dvdcss_library_init = 0;
+  return;
+#endif
+}
+
+
 /**
  * Setup read functions with either libdvdcss or minimal DVD access.
  */
 int dvdinput_setup(void)
 {
-  void *dvdcss_library = NULL;
   char **dvdcss_version = NULL;
+  int verbose;
+
+  /* dlopening libdvdcss */
+  if(dvdcss_library_init) {
+    /* libdvdcss is already dlopened, function ptrs set */
+    if(dvdcss_library) {
+      return 1; /* css available */
+    } else {
+      return 0; /* css not available */
+    }
+  }
+
+  verbose = get_verbose();
 
 #ifdef HAVE_DVDCSS_DVDCSS_H
   /* linking to libdvdcss */
@@ -277,7 +334,7 @@
   dvdcss_version = &dvdcss_interface_2;
 
 #else
-  /* dlopening libdvdcss */
+
   dvdcss_library = dlopen("libdvdcss.so.2", RTLD_LAZY);
   
   if(dvdcss_library != NULL) {
@@ -302,33 +359,39 @@
     dvdcss_version = (char **)dlsym(dvdcss_library, U_S "dvdcss_interface_2");
 
     if(dlsym(dvdcss_library, U_S "dvdcss_crack")) {
+      if(verbose >= 0) {
       fprintf(stderr, 
 	      "libdvdread: Old (pre-0.0.2) version of libdvdcss found.\n"
 	      "libdvdread: You should get the latest version from "
 	      "http://www.videolan.org/\n" );
+      }
       dlclose(dvdcss_library);
       dvdcss_library = NULL;
     } else if(!DVDcss_open  || !DVDcss_close || !DVDcss_title || !DVDcss_seek
 	      || !DVDcss_read || !DVDcss_error || !dvdcss_version) {
+      if(verbose >= 0) {
       fprintf(stderr,  "libdvdread: Missing symbols in libdvdcss.so.2, "
 	      "this shouldn't happen !\n");
+      }
       dlclose(dvdcss_library);
+      dvdcss_library = NULL;
     }
   }
 #endif /* HAVE_DVDCSS_DVDCSS_H */
   
-  if(dvdcss_library != NULL) {
+  dvdcss_library_init = 1;
+  
+  if(dvdcss_library) {
     /*
     char *psz_method = getenv( "DVDCSS_METHOD" );
     char *psz_verbose = getenv( "DVDCSS_VERBOSE" );
     fprintf(stderr, "DVDCSS_METHOD %s\n", psz_method);
     fprintf(stderr, "DVDCSS_VERBOSE %s\n", psz_verbose);
     */
-    /*
+    if(verbose >= 1) {
     fprintf(stderr, "libdvdread: Using libdvdcss version %s for DVD access\n",
 	    *dvdcss_version);
-    */
-    
+    }
     /* libdvdcss wrapper functions */
     dvdinput_open  = css_open;
     dvdinput_close = css_close;
@@ -339,8 +402,9 @@
     return 1;
     
   } else {
+    if(verbose >= 1) {
     fprintf(stderr, "libdvdread: Encrypted DVD support unavailable.\n");
-
+    }
     /* libdvdcss replacement functions */
     dvdinput_open  = file_open;
     dvdinput_close = file_close;
--- a/dvdread/dvd_input.h	Wed Aug 15 10:34:53 2007 +0000
+++ b/dvdread/dvd_input.h	Wed Aug 15 11:47:22 2007 +0000
@@ -40,6 +40,13 @@
 extern char *      (*dvdinput_error) (dvd_input_t);
 
 /**
+ * Free any objects allocated by dvdinput_setup.
+ * Should only be called when libdvdread is not to be used any more.
+ * Closes dlopened libraries.
+ */
+void dvdinput_free(void);
+
+/**
  * Setup function accessed by dvd_reader.c.  Returns 1 if there is CSS support.
  */
 int dvdinput_setup(void);
--- a/dvdread/dvd_reader.c	Wed Aug 15 10:34:53 2007 +0000
+++ b/dvdread/dvd_reader.c	Wed Aug 15 11:47:22 2007 +0000
@@ -60,11 +60,13 @@
 }
 #endif
 
-#include "dvd_udf.h"
+#include "dvd_reader.h"
 #include "dvd_input.h"
-#include "dvd_reader.h"
+#include "dvd_udf.h"
 #include "md5.h"
 
+#include "dvdread_internal.h"
+
 #define DEFAULT_UDF_CACHE_LEVEL 0
 
 struct dvd_reader_s {
@@ -85,6 +87,12 @@
     /* Filesystem cache */
     int udfcache_level; /* 0 - turned off, 1 - on */
     void *udfcache;
+
+  /* block aligned malloc */
+  void *align;
+  
+  /* error message verbosity level */
+  int verbose;
 };
 
 struct dvd_file_s {
@@ -106,6 +114,42 @@
     ssize_t filesize;
 };
 
+
+#define DVDREAD_VERBOSE_DEFAULT 0
+
+int get_verbose(void)
+{
+  char *dvdread_verbose;
+  int verbose;
+  
+  dvdread_verbose = getenv("DVDREAD_VERBOSE");
+  if(dvdread_verbose) {
+    verbose = (int)strtol(dvdread_verbose, NULL, 0);
+  } else {
+    verbose = DVDREAD_VERBOSE_DEFAULT;
+  }
+  return verbose;
+}
+
+int dvdread_verbose(dvd_reader_t *dvd)
+{
+  return dvd->verbose;
+}
+
+dvd_reader_t *device_of_file(dvd_file_t *file)
+{
+  return file->dvd;
+}
+
+/**
+ * Returns the compiled version. (DVDREAD_VERSION as an int)
+ */
+int DVDVersion(void)
+{
+  return DVDREAD_VERSION;
+}
+
+
 /**
  * Set the level of caching on udf
  * level = 0 (no caching)
@@ -140,6 +184,31 @@
   dev->udfcache = cache;
 }
 
+void *GetAlignHandle(dvd_reader_t *device)
+{
+  struct dvd_reader_s *dev = (struct dvd_reader_s *)device;
+  
+  return dev->align;
+}
+
+void SetAlignHandle(dvd_reader_t *device, void *align)
+{
+  struct dvd_reader_s *dev = (struct dvd_reader_s *)device;
+
+  dev->align = align;
+}
+
+#ifdef WIN32 /* replacement gettimeofday implementation */
+#include <sys/timeb.h>
+static int gettimeofday( struct timeval *tv, void *tz )
+{
+  struct timeb t;
+  ftime( &t );
+  tv->tv_sec = t.time;
+  tv->tv_usec = t.millitm * 1000;
+  return 0;
+}
+#endif
 
 
 /* Loop over all titles and call dvdcss_title to crack the keys. */
@@ -155,11 +224,12 @@
     if(nokeys_str != NULL)
       return 0;
     
+  if(dvd->verbose >= 1) {
     fprintf( stderr, "\n" );
     fprintf( stderr, "libdvdread: Attempting to retrieve all CSS keys\n" );
     fprintf( stderr, "libdvdread: This can take a _long_ time, "
 	     "please be patient\n\n" );
-	
+  }
     gettimeofday(&all_s, NULL);
 	
     for( title = 0; title < 100; title++ ) {
@@ -172,15 +242,21 @@
 	start = UDFFindFile( dvd, filename, &len );
 	if( start != 0 && len != 0 ) {
 	    /* Perform CSS key cracking for this title. */
+      if(dvd->verbose >= 1) {
 	    fprintf( stderr, "libdvdread: Get key for %s at 0x%08x\n", 
 		     filename, start );
+      }
 	    if( dvdinput_title( dvd->dev, (int)start ) < 0 ) {
+        if(dvd->verbose >= 0) {
 		fprintf( stderr, "libdvdread: Error cracking CSS key for %s (0x%08x)\n", filename, start);
 	    }
+      }
 	    gettimeofday( &t_e, NULL );
+      if(dvd->verbose >= 1) {
 	    fprintf( stderr, "libdvdread: Elapsed time %ld\n",  
 		     (long int) t_e.tv_sec - t_s.tv_sec );
 	}
+    }
 	    
 	if( title == 0 ) continue;
 	    
@@ -190,22 +266,31 @@
 	if( start == 0 || len == 0 ) break;
 	    
 	/* Perform CSS key cracking for this title. */
+    if(dvd->verbose >= 1) {
 	fprintf( stderr, "libdvdread: Get key for %s at 0x%08x\n", 
 		 filename, start );
+    }
 	if( dvdinput_title( dvd->dev, (int)start ) < 0 ) {
+      if(dvd->verbose >= 0) {
 	    fprintf( stderr, "libdvdread: Error cracking CSS key for %s (0x%08x)!!\n", filename, start);
 	}
+    }
 	gettimeofday( &t_e, NULL );
+    if(dvd->verbose >= 1) {
 	fprintf( stderr, "libdvdread: Elapsed time %ld\n",  
 		 (long int) t_e.tv_sec - t_s.tv_sec );
     }
+  }
     title--;
     
+  if(dvd->verbose >= 1) {
     fprintf( stderr, "libdvdread: Found %d VTS's\n", title );
+  }
     gettimeofday(&all_e, NULL);
+  if(dvd->verbose >= 1) {
     fprintf( stderr, "libdvdread: Elapsed time %ld\n",  
 	     (long int) all_e.tv_sec - all_s.tv_sec );
-    
+  }
     return 0;
 }
 
@@ -213,27 +298,43 @@
 
 /**
  * Open a DVD image or block device file.
+ * Checks if the root directory in the udf image file can be found.
+ * If not it assumes this isn't a valid udf image and returns NULL
  */
 static dvd_reader_t *DVDOpenImageFile( const char *location, int have_css )
 {
     dvd_reader_t *dvd;
     dvd_input_t dev;
+  int verbose;
+
+  verbose = get_verbose();
     
     dev = dvdinput_open( location );
     if( !dev ) {
-	fprintf( stderr, "libdvdread: Can't open %s for reading\n", location );
-	return 0;
+    if(verbose >= 1) {
+      fprintf( stderr, "libdvdread: Can't open '%s' for reading: %s\n",
+               location, strerror(errno));
+    }
+    return NULL;
     }
 
     dvd = (dvd_reader_t *) malloc( sizeof( dvd_reader_t ) );
-    if( !dvd ) return 0;
+  if( !dvd ) {
+    int tmp_errno = errno;
+    dvdinput_close(dev);
+    errno = tmp_errno;
+    return NULL;
+  }
+  dvd->verbose = verbose;
     dvd->isImageFile = 1;
     dvd->dev = dev;
-    dvd->path_root = 0;
+  dvd->path_root = NULL;
     
     dvd->udfcache_level = DEFAULT_UDF_CACHE_LEVEL;
     dvd->udfcache = NULL;
 
+  dvd->align = NULL;
+
     if( have_css ) {
       /* Only if DVDCSS_METHOD = title, a bit if it's disc or if
        * DVDCSS_METHOD = key but region missmatch. Unfortunaly we
@@ -243,6 +344,20 @@
     }
     dvd->css_title = 0;
     
+  /* sanity check, is it a valid UDF image, can we find the root dir */
+  if(!UDFFindFile(dvd, "/", NULL)) {
+    dvdinput_close(dvd->dev);
+    if(dvd->udfcache) {
+      FreeUDFCache(dvd, dvd->udfcache);
+    }
+    if(dvd->align) {
+      if(dvd->verbose >= 0) {
+        fprintf(stderr, "libdvdread: DVDOpenImageFile(): Memory leak in align functions 1\n");
+      }
+    }
+    free(dvd);
+    return NULL;
+  }
     return dvd;
 }
 
@@ -251,14 +366,22 @@
     dvd_reader_t *dvd;
 
     dvd = (dvd_reader_t *) malloc( sizeof( dvd_reader_t ) );
-    if( !dvd ) return 0;
+  if( !dvd ) {
+    return NULL;
+  }
+  dvd->verbose = get_verbose();
     dvd->isImageFile = 0;
     dvd->dev = 0;
     dvd->path_root = strdup( path_root );
-
+  if(!dvd->path_root) {
+    free(dvd);
+    return 0;
+  }
     dvd->udfcache_level = DEFAULT_UDF_CACHE_LEVEL;
     dvd->udfcache = NULL;
     
+  dvd->align = NULL;
+
     dvd->css_state = 0; /* Only used in the UDF path */
     dvd->css_title = 0; /* Only matters in the UDF path */
 
@@ -320,10 +443,16 @@
 {
     struct stat fileinfo;
     int ret, have_css;
-    char *dev_name = 0;
+  char *dev_name = NULL;
+  int internal_errno = 0;
+  int verbose;
 
-    if( path == NULL )
-      return 0;
+  if( path == NULL ) {
+    errno = EINVAL;
+    return NULL;
+  }
+  
+  verbose = get_verbose();
 
 #ifdef WIN32
     /* Stat doesn't work on devices under mingwin/cygwin. */
@@ -337,10 +466,14 @@
     {
     ret = stat( path, &fileinfo );
     if( ret < 0 ) {
+        int tmp_errno = errno;
 	/* If we can't stat the file, give up */
-	fprintf( stderr, "libdvdread: Can't stat %s\n", path );
-	perror("");
-	return 0;
+        if(verbose >= 1) {
+          fprintf( stderr, "libdvdread: Can't stat '%s': %s\n",
+                   path, strerror(errno));
+        }
+        errno = tmp_errno;
+        return NULL;
     }
     }
 
@@ -375,24 +508,38 @@
 	/* XXX: We should scream real loud here. */
 	if( !(path_copy = strdup( path ) ) ) return 0;
 
+#ifndef WIN32 /* don't have fchdir, and getcwd( NULL, ... ) is strange */
 	/* Resolve any symlinks and get the absolut dir name. */
 	{
 	    char *new_path;
-	    int cdir = open( ".", O_RDONLY );
+      char *current_path;
 	    
-	    if( cdir >= 0 ) {
+      current_path = malloc(PATH_MAX);
+      if(current_path) {
+        if(!getcwd(current_path, PATH_MAX)) {
+          free(current_path);
+          current_path = NULL;
+        }
+      }
+      if(current_path) {
 		chdir( path_copy );
-		new_path = getcwd( NULL, PATH_MAX );
-#ifndef __MINGW32__       
-		fchdir( cdir );
-#endif       
-		close( cdir );
+        new_path = malloc(PATH_MAX);
+        if(new_path) {
+          if(!getcwd(new_path, PATH_MAX )) {
+            free(new_path);
+            new_path = NULL;
+          }
+        }
+
+        chdir(current_path);
+        free(current_path);
 		if( new_path ) {
 		    free( path_copy );
 		    path_copy = new_path;
 		}
 	    }
 	}
+#endif
 	
 	/**
 	 * If we're being asked to open a directory, check if that directory
@@ -400,26 +547,37 @@
 	 */
 
 	if( strlen( path_copy ) > 1 ) {
-	    if( path_copy[ strlen( path_copy ) - 1 ] == '/' ) 
+      if( path_copy[ strlen( path_copy ) - 1 ] == '/' ) {
 		path_copy[ strlen( path_copy ) - 1 ] = '\0';
 	}
+    }
 
-	if( strlen( path_copy ) > 9 ) {
+    if( strlen( path_copy ) >= 9 ) {
 	    if( !strcasecmp( &(path_copy[ strlen( path_copy ) - 9 ]), 
 			     "/video_ts" ) ) {
 	      path_copy[ strlen( path_copy ) - 9 ] = '\0';
+        if(path_copy[0] == '\0') {
+          path_copy[0] = '/';
+          path_copy[1] = '\0';
+        }
 	    }
 	}
 
 #if defined(SYS_BSD)
 	if( ( fe = getfsfile( path_copy ) ) ) {
 	    dev_name = bsd_block2char( fe->fs_spec );
+      if(verbose >= 1) {
 	    fprintf( stderr,
 		     "libdvdread: Attempting to use device %s"
-		     " mounted on %s for CSS authentication\n",
+                 " mounted on %s%s\n",
 		     dev_name,
-		     fe->fs_file );
+                 fe->fs_file,
+                 have_css ? " for CSS authentication" : "");
+      }
 	    auth_drive = DVDOpenImageFile( dev_name, have_css );
+      if(!auth_drive) {
+        internal_errno = errno;
+      }
 	}
 #elif defined(__sun)
 	mntfile = fopen( MNTTAB, "r" );
@@ -430,12 +588,18 @@
 	    while( ( res = getmntent( mntfile, &mp ) ) != -1 ) {
 		if( res == 0 && !strcmp( mp.mnt_mountp, path_copy ) ) {
 		    dev_name = sun_block2char( mp.mnt_special );
+          if(verbose >= 1) {
 		    fprintf( stderr, 
 			     "libdvdread: Attempting to use device %s"
-			     " mounted on %s for CSS authentication\n",
+                     " mounted on %s%s\n",
 			     dev_name,
-			     mp.mnt_mountp );
+                     mp.mnt_mountp,
+                     have_css ? " for CSS authentication" : "");
+          }
 		    auth_drive = DVDOpenImageFile( dev_name, have_css );
+          if(!auth_drive) {
+            internal_errno = errno;
+          }
 		    break;
 		}
 	    }
@@ -448,12 +612,18 @@
  
             while( ( me = getmntent( mntfile ) ) ) {
                 if( !strcmp( me->mnt_dir, path_copy ) ) {
+          if(verbose >= 1) {
 		    fprintf( stderr, 
 			     "libdvdread: Attempting to use device %s"
-			     " mounted on %s for CSS authentication\n",
+                     " mounted on %s%s\n",
 			     me->mnt_fsname,
-			     me->mnt_dir );
+                     me->mnt_dir,
+                     have_css ? " for CSS authentication" : "");
+          }
                     auth_drive = DVDOpenImageFile( me->mnt_fsname, have_css );
+          if(!auth_drive) {
+            internal_errno = errno;
+          }
 		    dev_name = strdup(me->mnt_fsname);
                     break;
                 }
@@ -465,10 +635,16 @@
 	auth_drive = DVDOpenImageFile( path, have_css );
 #endif
 	if( !dev_name ) {
+      if(verbose >= 1) {
 	  fprintf( stderr, "libdvdread: Couldn't find device name.\n" );
+      }
 	} else if( !auth_drive ) {
-	    fprintf( stderr, "libdvdread: Device %s inaccessible, "
-		     "CSS authentication not available.\n", dev_name );
+      if(verbose >= 1) {
+        fprintf( stderr, "libdvdread: Device %s inaccessible%s: %s\n",
+                 dev_name,
+                 have_css ? ", CSS authentication not available" : "",
+                 strerror(internal_errno));
+      }
 	}
 
 	free( dev_name );
@@ -477,8 +653,9 @@
         /**
          * If we've opened a drive, just use that.
          */
-        if( auth_drive ) return auth_drive;
-
+    if( auth_drive ) {
+      return auth_drive;
+    }
         /**
          * Otherwise, we now try to open the directory tree instead.
          */
@@ -486,7 +663,9 @@
     }
 
     /* If it's none of the above, screw it. */
+  if(verbose >= 1) {
     fprintf( stderr, "libdvdread: Could not open %s\n", path );
+  }
     return 0;
 }
 
@@ -495,11 +674,27 @@
     if( dvd ) {
         if( dvd->dev ) dvdinput_close( dvd->dev );
         if( dvd->path_root ) free( dvd->path_root );
-	if( dvd->udfcache ) FreeUDFCache( dvd->udfcache );
+    if( dvd->udfcache ) FreeUDFCache( dvd, dvd->udfcache );
+    if(dvd->align) {
+      if(dvd->verbose >= 0) {
+        fprintf(stderr, "libdvdread: DVDClose(): Memory leak in align functions\n");
+      }
+    }
+    dvdinput_free();
         free( dvd );
     }
 }
 
+void DVDInit(void)
+{
+  dvdinput_setup();
+}
+
+void DVDFinish(void)
+{
+  dvdinput_free();
+}
+
 /**
  * Open an unencrypted file on a DVD image file.
  */
@@ -542,10 +737,11 @@
             sprintf( filename, "%s%s%s", path,
                      ( ( path[ strlen( path ) - 1 ] == '/' ) ? "" : "/" ),
                      ent->d_name );
+      closedir(dir);
             return 0;
         }
     }
-
+  closedir(dir);
     return -1;
 }
 
@@ -606,7 +802,9 @@
     dvd_file->filesize = 0;
 
     if( stat( full_path, &fileinfo ) < 0 ) {
+    if(dvd->verbose >= 1) {
         fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename );
+    }
         free( dvd_file );
         return 0;
     }
@@ -704,7 +902,9 @@
         }
 
         if( stat( full_path, &fileinfo ) < 0 ) {
+      if(dvd->verbose >= 1) {
             fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename );
+      }
             free( dvd_file );
             return 0;
         }
@@ -722,7 +922,9 @@
             }
 
             if( stat( full_path, &fileinfo ) < 0 ) {
+        if(dvd->verbose >= 1) {
                 fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename );
+        }
                 break;
             }
 
@@ -746,8 +948,10 @@
     char filename[ MAX_UDF_FILE_NAME_LEN ];
     
     /* Check arguments. */
-    if( dvd == NULL || titlenum < 0 )
+  if( dvd == NULL || titlenum < 0 ) {
+    errno = EINVAL;
       return NULL;
+  }
 
     switch( domain ) {
     case DVD_READ_INFO_FILE:
@@ -780,7 +984,10 @@
         }
         break;
     default:
+    if(dvd->verbose >= 1) {
         fprintf( stderr, "libdvdread: Invalid domain for file open.\n" );
+    }
+    errno = EINVAL;
         return NULL;
     }
     
@@ -811,7 +1018,20 @@
     }
 }
 
-/* Internal, but used from dvd_udf.c */
+/**
+ * Internal, but used from dvd_udf.c 
+ *
+ * @param device A read handle.
+ * @param lb_number Logical block number to start read from.
+ * @param block_count Number of logical blocks to read.
+ * @param data Pointer to buffer where read data should be stored.
+ *             This buffer must be large enough to hold lb_number*2048 bytes.
+ *             The pointer must be aligned to the logical block size when
+ *             reading from a raw/O_DIRECT device.
+ * @param encrypted 0 if no decryption shall be performed,
+ *                  1 if decryption shall be performed
+ * @param return Returns number of blocks read on success, negative on error
+ */
 int UDFReadBlocksRaw( dvd_reader_t *device, uint32_t lb_number,
 			 size_t block_count, unsigned char *data, 
 			 int encrypted )
@@ -819,13 +1039,19 @@
    int ret;
 
    if( !device->dev ) {
+    if(device->verbose >= 1) {
      	fprintf( stderr, "libdvdread: Fatal error in block read.\n" );
+    }
 	return 0;
    }
 
    ret = dvdinput_seek( device->dev, (int) lb_number );
    if( ret != (int) lb_number ) {
-     	fprintf( stderr, "libdvdread: Can't seek to block %u\n", lb_number );
+    if(device->verbose >= 1) {
+      fprintf( stderr,
+               "libdvdread: UDFReadBlocksRaw: Can't seek to block %u\n",
+               lb_number );
+    }
 	return 0;
    }
 
@@ -833,12 +1059,20 @@
 			 (int) block_count, encrypted );
 }
 
-/* This is using a single input and starting from 'dvd_file->lb_start' offset.
+/**
+ * This is using a single input and starting from 'dvd_file->lb_start' offset.
  *
  * Reads 'block_count' blocks from 'dvd_file' at block offset 'offset'
  * into the buffer located at 'data' and if 'encrypted' is set
  * descramble the data if it's encrypted.  Returning either an
- * negative error or the number of blocks read. */
+ * negative error or the number of blocks read.
+ *
+ * @param data Pointer to buffer where read data should be placed.
+ *             This buffer must be large enough to hold block_count*2048 bytes.
+ *             The pointer must be aligned to 2048 bytes when reading from
+ *             a raw/O_DIRECT device.
+ * @return Returns the number of blocks read on success or a negative error.
+ */
 static int DVDReadBlocksUDF( dvd_file_t *dvd_file, uint32_t offset,
 			     size_t block_count, unsigned char *data,
 			     int encrypted )
@@ -847,12 +1081,19 @@
 			     block_count, data, encrypted );
 }
 
-/* This is using possibly several inputs and starting from an offset of '0'.
- *
+/**
+ * This is using possibly several inputs and starting from an offset of '0'.
+ * data must be aligned to logical block size (2048 bytes) of the device
+ * for raw/O_DIRECT devices to work
  * Reads 'block_count' blocks from 'dvd_file' at block offset 'offset'
  * into the buffer located at 'data' and if 'encrypted' is set
  * descramble the data if it's encrypted.  Returning either an
- * negative error or the number of blocks read. */
+ * negative error or the number of blocks read.
+ *
+ * @param dvd_file A file read handle.
+ * @param offset Block offset from start of file.
+ * @return Returns number of blocks read on success, negative on error.
+ */
 static int DVDReadBlocksPath( dvd_file_t *dvd_file, unsigned int offset,
 			      size_t block_count, unsigned char *data,
 			      int encrypted )
@@ -869,8 +1110,10 @@
             if( ( offset + block_count ) <= dvd_file->title_sizes[ i ] ) {
 		off = dvdinput_seek( dvd_file->title_devs[ i ], (int)offset );
                 if( off < 0 || off != (int)offset ) {
-		    fprintf( stderr, "libdvdread: Can't seek to block %d\n", 
+          if(dvd_file->dvd->verbose >= 1) {
+            fprintf( stderr, "libdvdread: DVDReadBlocksPath1: Can't seek to block %d\n", 
 			     offset );
+          }
 		    return off < 0 ? off : 0;
 		}
                 ret = dvdinput_read( dvd_file->title_devs[ i ], data,
@@ -884,8 +1127,10 @@
                 /* Read part 1 */
                 off = dvdinput_seek( dvd_file->title_devs[ i ], (int)offset );
                 if( off < 0 || off != (int)offset ) {
-		    fprintf( stderr, "libdvdread: Can't seek to block %d\n", 
+          if(dvd_file->dvd->verbose >= 1) {
+            fprintf( stderr, "libdvdread: DVDReadBlocksPath2: Can't seek to block %d\n", 
 			     offset );
+          }
 		    return off < 0 ? off : 0;
 		}
                 ret = dvdinput_read( dvd_file->title_devs[ i ], data,
@@ -900,8 +1145,9 @@
                 /* Read part 2 */
                 off = dvdinput_seek( dvd_file->title_devs[ i + 1 ], 0 );
                 if( off < 0 || off != 0 ) {
-		    fprintf( stderr, "libdvdread: Can't seek to block %d\n", 
-			     0 );
+          if(dvd_file->dvd->verbose >= 1) {
+            fprintf( stderr, "libdvdread: DVDReadBlocksPath3: Can't seek to block %d\n", 0 );
+          }
 		    return off < 0 ? off : 0;
 		}
                 ret2 = dvdinput_read( dvd_file->title_devs[ i + 1 ], 
@@ -920,7 +1166,9 @@
     return ret + ret2;
 }
 
-/* This is broken reading more than 2Gb at a time is ssize_t is 32-bit. */
+/**
+ * This is broken reading more than 2Gb at a time if ssize_t is 32-bit.
+ */
 ssize_t DVDReadBlocks( dvd_file_t *dvd_file, int offset, 
 		       size_t block_count, unsigned char *data )
 {
@@ -966,29 +1214,41 @@
     return offset;
 }
 
+#ifndef HAVE_UINTPTR_T
+#warning "Assuming that (unsigned long) can hold (void *)"
+typedef unsigned long uintptr_t;
+#endif
+
+#define DVD_ALIGN(ptr) (void *)((((uintptr_t)(ptr)) + (DVD_VIDEO_LB_LEN-1)) \
+                                / DVD_VIDEO_LB_LEN * DVD_VIDEO_LB_LEN)
+
 ssize_t DVDReadBytes( dvd_file_t *dvd_file, void *data, size_t byte_size )
 {
-    unsigned char *secbuf;
+  unsigned char *secbuf_start;
+  unsigned char *secbuf; //must be aligned to 2048-bytes for raw/O_DIRECT
     unsigned int numsec, seek_sector, seek_byte;
     int ret;
     
     /* Check arguments. */
-    if( dvd_file == NULL || data == NULL )
+  if( dvd_file == NULL || data == NULL ) {
+    errno = EINVAL;
       return -1;
-
+  }
     seek_sector = dvd_file->seek_pos / DVD_VIDEO_LB_LEN;
     seek_byte   = dvd_file->seek_pos % DVD_VIDEO_LB_LEN;
 
     numsec = ( ( seek_byte + byte_size ) / DVD_VIDEO_LB_LEN ) +
       ( ( ( seek_byte + byte_size ) % DVD_VIDEO_LB_LEN ) ? 1 : 0 );
     
-    secbuf = (unsigned char *) malloc( numsec * DVD_VIDEO_LB_LEN );
-    if( !secbuf ) {
-	fprintf( stderr, "libdvdread: Can't allocate memory " 
-		 "for file read!\n" );
-        return 0;
+  /* must align to 2048 bytes if we are reading from raw/O_DIRECT */
+  secbuf_start = (unsigned char *) malloc( (numsec+1) * DVD_VIDEO_LB_LEN );
+  if( !secbuf_start ) {
+    /* errno will be set to ENOMEM by malloc */
+    return -1;
     }
     
+  secbuf = DVD_ALIGN(secbuf_start);
+
     if( dvd_file->dvd->isImageFile ) {
 	ret = DVDReadBlocksUDF( dvd_file, (uint32_t) seek_sector, 
 				(size_t) numsec, secbuf, DVDINPUT_NOFLAGS );
@@ -998,12 +1258,12 @@
     }
 
     if( ret != (int) numsec ) {
-        free( secbuf );
+    free( secbuf_start );
         return ret < 0 ? ret : 0;
     }
 
     memcpy( data, &(secbuf[ seek_byte ]), byte_size );
-    free( secbuf );
+  free( secbuf_start );
 
     dvd_file->seek_pos += byte_size;
     return byte_size;
@@ -1022,11 +1282,14 @@
 {
     struct md5_ctx ctx;
     int title;
-
+  int nr_of_files = 0;
+  int tmp_errno;
+  int nofiles_errno = ENOENT;
     /* Check arguments. */
-    if( dvd == NULL || discid == NULL )
-      return 0;
-    
+  if( dvd == NULL || discid == NULL ) {
+    errno = EINVAL;
+    return -1;
+  }
     /* Go through the first 10 IFO:s, in order, 
      * and md5sum them, i.e  VIDEO_TS.IFO and VTS_0?_0.IFO */
     md5_init_ctx( &ctx );
@@ -1037,16 +1300,23 @@
 	    size_t file_size = dvd_file->filesize * DVD_VIDEO_LB_LEN;
 	    char *buffer = malloc( file_size );
 	    
+      nr_of_files++;
+
 	    if( buffer == NULL ) {
-		fprintf( stderr, "libdvdread: DVDDiscId, failed to "
-			 "allocate memory for file read!\n" );
+        /* errno will be set to ENOMEM by malloc */
 		return -1;
 	    }
+
 	    bytes_read = DVDReadBytes( dvd_file, buffer, file_size );
 	    if( bytes_read != file_size ) {
+        tmp_errno = errno;
+        if(dvd->verbose >= 1) {
 		fprintf( stderr, "libdvdread: DVDDiscId read returned %d bytes"
-			 ", wanted %d\n", bytes_read, file_size );
+                   ", wanted %d\n", (int)bytes_read, (int)file_size );
+        }
+        free(buffer);
 		DVDCloseFile( dvd_file );
+        errno = tmp_errno;
 		return -1;
 	    }
 	    
@@ -1054,10 +1324,17 @@
 	    
 	    DVDCloseFile( dvd_file );
 	    free( buffer );
+    } else {
+      if(errno != ENOENT) {
+        nofiles_errno = errno;
+      }
 	}
     }
     md5_finish_ctx( &ctx, discid );
-    
+  if(nr_of_files == 0) {
+    errno = nofiles_errno;
+    return -1;
+  }
     return 0;
 }
 
@@ -1066,29 +1343,36 @@
 		      char *volid, unsigned int volid_size,
 		      unsigned char *volsetid, unsigned int volsetid_size )
 {
-  unsigned char *buffer;
+  unsigned char *buffer; /* must be aligned to 2048 for raw/O_DIRECT */
+  unsigned char *buffer_start; 
   int ret;
 
   /* Check arguments. */
-  if( dvd == NULL )
-    return 0;
-  
-  if( dvd->dev == NULL ) {
-    /* No block access, so no ISO... */
+  if( dvd == NULL ) {
+    errno = EINVAL;
     return -1;
   }
   
-  buffer = malloc( DVD_VIDEO_LB_LEN );
-  if( buffer == NULL ) {
-    fprintf( stderr, "libdvdread: DVDISOVolumeInfo, failed to "
-	     "allocate memory for file read!\n" );
+  if( dvd->dev == NULL ) {
+    /* No block access, so no ISO... */
+    errno = EINVAL;
+    return -1;
+  }
+  
+  buffer_start = malloc( 2 * DVD_VIDEO_LB_LEN );
+  if( buffer_start == NULL ) {
     return -1;
   }
 
+  buffer = DVD_ALIGN(buffer_start);
+  
   ret = UDFReadBlocksRaw( dvd, 16, 1, buffer, 0 );
   if( ret != 1 ) {
+    if(dvd->verbose >= 1) {
     fprintf( stderr, "libdvdread: DVDISOVolumeInfo, failed to "
 	     "read ISO9660 Primary Volume Descriptor!\n" );
+    }
+    free(buffer_start);
     return -1;
   }
   
@@ -1114,6 +1398,8 @@
     }
     memcpy(volsetid, &buffer[190], volsetid_size);
   }
+  free(buffer_start);
+
   return 0;
 }
 
--- a/dvdread/dvd_reader.h	Wed Aug 15 10:34:53 2007 +0000
+++ b/dvdread/dvd_reader.h	Wed Aug 15 11:47:22 2007 +0000
@@ -31,9 +31,14 @@
  */
 
 /**
- * The current version.
+ * The current version. (0.9.4 => 904, 1.2.3 => 10203)
  */
-#define DVDREAD_VERSION 904
+#define DVDREAD_VERSION 905
+
+/**
+ * Returns the compiled version. (DVDREAD_VERSION as an int)
+ */
+int DVDVersion(void);
 
 /**
  * The length of one Logical Block of a DVD.
@@ -80,6 +85,10 @@
  * @return If successful a a read handle is returned. Otherwise 0 is returned.
  *
  * dvd = DVDOpen(path);
+ *
+ * Threads: this function uses chdir() and getcwd().
+ * The current working directory is global to all threads,
+ * so using chdir/getcwd in another thread could give unexpected results.
  */
 dvd_reader_t *DVDOpen( const char * );
 
@@ -95,6 +104,35 @@
 void DVDClose( dvd_reader_t * );
 
 /**
+ * Initializes libdvdread to be used with multithreading apps.
+ *
+ * You must call this function before using any other functions of libdvdread
+ * if you are going to use libdvdread in multiple threads in your program.
+ * If you are not using threads, or using libdvdread from just one thread,
+ * you do not need to call this, but you are allowed to do so anyway.
+ * 
+ * There are several restrictions on how you can use libdvdread in
+ * multithreading apps, see further documentation.
+ *
+ * If you have called DVDFinish() you need to call DVDInit again to use
+ * libdvdread in multiple threads.
+ *
+ * DVDInit(void);
+ */
+void DVDInit(void);
+
+/**
+ * frees any dlopened objects.
+ *
+ * You must DVDClose all handles opened with DVDOpen before calling this.
+ * Use this function if you need to close the dlopened libs and any other
+ * objects that have been dynamically allocated by libdvdread.
+ * 
+ * DVDFinish(void);
+ */
+void DVDFinish(void);
+
+/**
  * 
  */
 typedef enum {
@@ -141,6 +179,8 @@
  * @param offset Block offset from the start of the file to start reading at.
  * @param block_count Number of block to read.
  * @param data Pointer to a buffer to write the data into.
+ *             It must be aligned to the logical block size of the device when
+ *             reading from a raw/O_DIRECT device (2048 bytes for DVD)
  * @return Returns number of blocks read on success, -1 on error.
  *
  * blocks_read = DVDReadBlocks(dvd_file, offset, block_count, data);
--- a/dvdread/dvd_udf.c	Wed Aug 15 10:34:53 2007 +0000
+++ b/dvdread/dvd_udf.c	Wed Aug 15 11:47:22 2007 +0000
@@ -37,23 +37,173 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#ifndef __MINGW32__
-#include <sys/ioctl.h>
-#endif
+
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#include <errno.h>
+
+#if defined(HAVE_INTTYPES_H)
 #include <inttypes.h>
+#elif defined(HAVE_STDINT_H)
+#include <stdint.h>
+#endif
 
 #include "dvd_reader.h"
 #include "dvd_udf.h"
+#include "dvdread_internal.h"
+
+#ifndef EMEDIUMTYPE
+#define EMEDIUMTYPE ENOENT
+#endif
+
+#ifndef HAVE_UINTPTR_T
+#warning "Assuming that (unsigned long) can hold (void *)"
+typedef unsigned long uintptr_t;
+#endif
+
+#define DVD_ALIGN(ptr) (void *)((((uintptr_t)(ptr)) + (DVD_VIDEO_LB_LEN-1)) \
+                                / DVD_VIDEO_LB_LEN * DVD_VIDEO_LB_LEN)
+
+typedef struct {
+  void *start;
+  void *aligned;
+} dvdalign_ptrs_t;
+
+typedef struct {
+  dvdalign_ptrs_t *ptrs;
+  uint32_t ptrs_in_use;
+  uint32_t ptrs_max;
+} dvdalign_t;
+
+extern void *GetAlignHandle(dvd_reader_t *device);
+extern void SetAlignHandle(dvd_reader_t *device, void *align);
+
+/**
+ * Allocates aligned memory (for use with reads from raw/O_DIRECT devices).
+ * This memory must be freed with dvdalign_free()
+ * The size of the memory that is allocate is num_lbs*2048 bytes.
+ * The memory will be suitably aligned for use with
+ * block reads from raw/O_DIRECT device.
+ * @param num_lbs Number of logical blocks (2048 bytes) to allocate.
+ * @return Returns pointer to allocated memory, or NULL on failure
+ * This isn't supposed to be fast/efficient, if that is needed
+ * this function should be rewritten to use posix_memalign or similar.
+ * It's just needed for aligning memory for small block reads from
+ * raw/O_DIRECT devices. 
+ * We assume that 2048 is enough alignment for all systems at the moment.
+ * Not thread safe. Only use this from one thread.
+ * Depends on sizeof(unsigned long) being at least as large as sizeof(void *)
+ */
+static void *dvdalign_lbmalloc(dvd_reader_t *device, uint32_t num_lbs)
+{
+  void *m;
+  int n;
+  dvdalign_t *a;
+  
+  m = malloc((num_lbs+1)*DVD_VIDEO_LB_LEN);
+  if(m == NULL) {
+    return m;
+  }
+  a = (dvdalign_t *)GetAlignHandle(device);
+  if(a == NULL) {
+    a = malloc(sizeof(dvdalign_t));
+    if(a == NULL) {
+      return a;
+    }
+    a->ptrs = NULL;
+    a->ptrs_in_use = 0;
+    a->ptrs_max = 0;
+    SetAlignHandle(device, (void *)a);
+  }
+  
+  if(a->ptrs_in_use >= a->ptrs_max) {
+    a->ptrs = realloc(a->ptrs, (a->ptrs_max+10)*sizeof(dvdalign_ptrs_t));
+    if(a->ptrs == NULL) {
+      free(m);
+      return NULL;
+    }
+    a->ptrs_max+=10;
+    for(n = a->ptrs_in_use; n < a->ptrs_max; n++) {
+      a->ptrs[n].start = NULL;
+      a->ptrs[n].aligned = NULL;
+    }
+    n = a->ptrs_in_use;
+  } else {
+    for(n = 0; n < a->ptrs_max; n++) {
+      if(a->ptrs[n].start == NULL) {
+        break;
+      }
+    }
+  }
+
+  a->ptrs[n].start = m;
+  a->ptrs[n].aligned = DVD_ALIGN(m);
+
+  a->ptrs_in_use++;
+
+  /* If this function starts to be used too much print a warning.
+     Either there is a memory leak somewhere or we need to rewrite this to
+     a more efficient version.
+  */
+  if(a->ptrs_in_use > 50) {
+    if(dvdread_verbose(device) >= 0) {
+      fprintf(stderr, "libdvdread: dvdalign_lbmalloc(), more allocs than supposed: %u\n", a->ptrs_in_use);
+    }
+  }
+
+  return  a->ptrs[n].aligned;
+}
+
+/**
+ * Frees memory allocated with dvdalign_lbmemory() 
+ * @param ptr Pointer to memory space to free
+ * Not thread safe.
+ */
+static void dvdalign_lbfree(dvd_reader_t *device, void *ptr)
+{
+  int n;
+  dvdalign_t *a;
+
+  a = (dvdalign_t *)GetAlignHandle(device);
+  if(a && a->ptrs) {
+    for(n = 0; n < a->ptrs_max; n++) {
+      if(a->ptrs[n].aligned == ptr) {
+        free(a->ptrs[n].start);
+        a->ptrs[n].start = NULL;
+        a->ptrs[n].aligned = NULL;
+        a->ptrs_in_use--;
+        if(a->ptrs_in_use == 0) {
+          free(a->ptrs);
+          a->ptrs = NULL;
+          a->ptrs_max = 0;
+          free(a);
+          a = NULL;
+          SetAlignHandle(device, (void *)a);
+        }
+        return;
+      }
+    }
+  }
+  if(dvdread_verbose(device) >= 0) {
+    fprintf(stderr, "libdvdread: dvdalign_lbfree(), error trying to free mem: %08lx (%u)\n", (unsigned long)ptr, a ? a->ptrs_in_use : 0);
+  }
+}
+
 
 /* Private but located in/shared with dvd_reader.c */
 extern int UDFReadBlocksRaw( dvd_reader_t *device, uint32_t lb_number,
 				size_t block_count, unsigned char *data, 
 				int encrypted );
 
-/* It's required to either fail or deliver all the blocks asked for. */
+/** @internal
+ * Its required to either fail or deliver all the blocks asked for. 
+ *
+ * @param data Pointer to a buffer where data is returned. This must be large
+ *   enough to hold lb_number*2048 bytes.
+ *   It must be aligned to system specific (2048) logical blocks size when
+ *   reading from raw/O_DIRECT device.
+ */
 static int DVDReadLBUDF( dvd_reader_t *device, uint32_t lb_number,
 			 size_t block_count, unsigned char *data, 
 			 int encrypted )
@@ -149,12 +299,24 @@
 extern void *GetUDFCacheHandle(dvd_reader_t *device);
 extern void SetUDFCacheHandle(dvd_reader_t *device, void *cache);
 
-void FreeUDFCache(void *cache)
+
+void FreeUDFCache(dvd_reader_t *device, void *cache)
 {
+  int n;
+  
   struct udf_cache *c = (struct udf_cache *)cache;
   if(c == NULL) {
     return;
   }
+
+  for(n = 0; n < c->lb_num; n++) {
+    if(c->lbs[n].data) {
+      /* free data */
+      dvdalign_lbfree(device, c->lbs[n].data);
+    }
+  }
+  c->lb_num = 0;
+
   if(c->lbs) {
     free(c->lbs);
   }
@@ -493,7 +655,7 @@
 static int UDFMapICB( dvd_reader_t *device, struct AD ICB, uint8_t *FileType,
 		      struct Partition *partition, struct AD *File ) 
 {
-    uint8_t LogBlock[DVD_VIDEO_LB_LEN];
+  uint8_t *LogBlock;
     uint32_t lbnum;
     uint16_t TagID;
     struct icbmap tmpmap;
@@ -506,6 +668,11 @@
       return 1;
     }
 
+  LogBlock = dvdalign_lbmalloc(device, 1);
+  if(!LogBlock) {
+    return 0;
+  }
+    
     do {
         if( DVDReadLBUDF( device, lbnum++, 1, LogBlock, 0 ) <= 0 ) {
             TagID = 0;
@@ -518,11 +685,13 @@
            tmpmap.file = *File;
            tmpmap.filetype = *FileType;
            SetUDFCache(device, MapCache, tmpmap.lbn, &tmpmap);
+      dvdalign_lbfree(device, LogBlock);
             return 1;
         };
     } while( ( lbnum <= partition->Start + ICB.Location + ( ICB.Length - 1 )
              / DVD_VIDEO_LB_LEN ) && ( TagID != 261 ) );
 
+  dvdalign_lbfree(device, LogBlock);
     return 0;
 }
 
@@ -537,7 +706,7 @@
 		       int cache_file_info) 
 {
     char filename[ MAX_UDF_FILE_NAME_LEN ];
-    uint8_t directory[ 2 * DVD_VIDEO_LB_LEN ];
+  uint8_t *directory;
     uint32_t lbnum;
     uint16_t TagID;
     uint8_t filechar;
@@ -556,19 +725,13 @@
       
       if(!GetUDFCache(device, LBUDFCache, lbnum, &cached_dir)) {
 	dir_lba = (Dir.Length + DVD_VIDEO_LB_LEN) / DVD_VIDEO_LB_LEN;
-	if((cached_dir = malloc(dir_lba * DVD_VIDEO_LB_LEN)) == NULL) {
+      if((cached_dir = dvdalign_lbmalloc(device, dir_lba)) == NULL) {
 	  return 0;
 	}
 	if( DVDReadLBUDF( device, lbnum, dir_lba, cached_dir, 0) <= 0 ) {
-	  free(cached_dir);
+        dvdalign_lbfree(device, cached_dir);
 	  cached_dir = NULL;
 	}
-	/*
-	if(cached_dir) {
-	  fprintf(stderr, "malloc dir: %d\n",
-		  dir_lba * DVD_VIDEO_LB_LEN);
-	}
-	*/
 	SetUDFCache(device, LBUDFCache, lbnum, &cached_dir);
       } else {
 	in_cache = 1;
@@ -615,7 +778,12 @@
       return 0;
     }
 
+  directory = dvdalign_lbmalloc(device, 2);
+  if(!directory) {
+    return 0;
+  }
     if( DVDReadLBUDF( device, lbnum, 2, directory, 0 ) <= 0 ) {
+    dvdalign_lbfree(device, directory);
         return 0;
     }
 
@@ -626,6 +794,7 @@
             p -= DVD_VIDEO_LB_LEN;
             Dir.Length -= DVD_VIDEO_LB_LEN;
             if( DVDReadLBUDF( device, lbnum, 2, directory, 0 ) <= 0 ) {
+        dvdalign_lbfree(device, directory);
                 return 0;
             }
         }
@@ -634,13 +803,16 @@
             p += UDFFileIdentifier( &directory[ p ], &filechar,
                                     filename, FileICB );
             if( !strcasecmp( FileName, filename ) ) {
+        dvdalign_lbfree(device, directory);
                 return 1;
             }
         } else {
+      dvdalign_lbfree(device, directory);
             return 0;
         }
     }
 
+  dvdalign_lbfree(device, directory);
     return 0;
 }
 
@@ -648,7 +820,7 @@
 static int UDFGetAVDP( dvd_reader_t *device,
 		       struct avdp_t *avdp)
 {
-  uint8_t Anchor[ DVD_VIDEO_LB_LEN ];
+  uint8_t *Anchor;
   uint32_t lbnum, MVDS_location, MVDS_length;
   uint16_t TagID;
   uint32_t lastsector;
@@ -664,6 +836,10 @@
   lbnum = 256;   /* Try #1, prime anchor */
   terminate = 0;
   
+  Anchor = dvdalign_lbmalloc(device, 1);
+  if(!Anchor) {
+    return 0;
+  }
   for(;;) {
     if( DVDReadLBUDF( device, lbnum, 1, Anchor, 0 ) > 0 ) {
       UDFDescriptor( Anchor, &TagID );
@@ -672,10 +848,13 @@
     }
     if (TagID != 2) {
       /* Not an anchor */
-      if( terminate ) return 0; /* Final try failed */
+      if( terminate ) {
+        dvdalign_lbfree(device, Anchor);
+        errno = EMEDIUMTYPE;
+        return 0; /* Final try failed */
+      } 
       
       if( lastsector ) {
-	
 	/* We already found the last sector.  Try #3, alternative
 	 * backup anchor.  If that fails, don't try again.
 	 */
@@ -688,6 +867,8 @@
 	  lbnum = lastsector - 256;
 	} else {
 	  /* Unable to find last sector */
+          dvdalign_lbfree(device, Anchor);
+          errno = EMEDIUMTYPE;
 	  return 0;
 	}
       }
@@ -708,6 +889,7 @@
   
   SetUDFCache(device, AVDPCache, 0, avdp);
   
+  dvdalign_lbfree(device, Anchor);
   return 1;
 }
 
@@ -719,7 +901,7 @@
 static int UDFFindPartition( dvd_reader_t *device, int partnum,
 			     struct Partition *part ) 
 {
-    uint8_t LogBlock[ DVD_VIDEO_LB_LEN ];
+  uint8_t *LogBlock;
     uint32_t lbnum, MVDS_location, MVDS_length;
     uint16_t TagID;
     int i, volvalid;
@@ -730,6 +912,10 @@
       return 0;
     }
 
+  LogBlock = dvdalign_lbmalloc(device, 1);
+  if(!LogBlock) {
+    return 0;
+  }
     /* Main volume descriptor */
     MVDS_location = avdp.mvds.location;
     MVDS_length = avdp.mvds.length;
@@ -774,6 +960,7 @@
         }
     } while( i-- && ( ( !part->valid ) || ( !volvalid ) ) );
 
+  dvdalign_lbfree(device, LogBlock);
     /* We only care for the partition, not the volume */
     return part->valid;
 }
@@ -781,7 +968,7 @@
 uint32_t UDFFindFile( dvd_reader_t *device, char *filename,
 		      uint32_t *filesize )
 {
-    uint8_t LogBlock[ DVD_VIDEO_LB_LEN ];
+  uint8_t *LogBlock;
     uint32_t lbnum;
     uint16_t TagID;
     struct Partition partition;
@@ -790,7 +977,9 @@
     char *token;
     uint8_t filetype;
 
+  if(filesize) {
     *filesize = 0;
+  }
     tokenline[0] = '\0';
     strcat( tokenline, filename );
 
@@ -798,9 +987,15 @@
     if(!(GetUDFCache(device, PartitionCache, 0, &partition) &&
         GetUDFCache(device, RootICBCache, 0, &RootICB))) {
       /* Find partition, 0 is the standard location for DVD Video.*/
-      if( !UDFFindPartition( device, 0, &partition ) ) return 0;
+    if( !UDFFindPartition( device, 0, &partition ) ) {
+      return 0;
+    }
       SetUDFCache(device, PartitionCache, 0, &partition);
       
+    LogBlock = dvdalign_lbmalloc(device, 1);
+    if(!LogBlock) {
+      return 0;
+    }
       /* Find root dir ICB */
       lbnum = partition.Start;
       do {
@@ -817,16 +1012,25 @@
     } while( ( lbnum < partition.Start + partition.Length )
              && ( TagID != 8 ) && ( TagID != 256 ) );
 
+    dvdalign_lbfree(device, LogBlock);
+      
     /* Sanity checks. */
-    if( TagID != 256 ) return 0;
-    if( RootICB.Partition != 0 ) return 0;
+    if( TagID != 256 ) {
+      return 0;
+    }
+    if( RootICB.Partition != 0 ) {
+      return 0;
+    }
     SetUDFCache(device, RootICBCache, 0, &RootICB);
     }
 
     /* Find root dir */
-    if( !UDFMapICB( device, RootICB, &filetype, &partition, &File ) ) return 0;
-    if( filetype != 4 ) return 0;  /* Root dir should be dir */
-
+  if( !UDFMapICB( device, RootICB, &filetype, &partition, &File ) ) {
+    return 0;
+  }
+  if( filetype != 4 ) {
+    return 0;  /* Root dir should be dir */
+  }
     {
       int cache_file_info = 0;
       /* Tokenize filepath */
@@ -849,15 +1053,20 @@
     } 
 
     /* Sanity check. */
-    if( File.Partition != 0 ) return 0;
+  if( File.Partition != 0 ) {
+    return 0;
+  }
    
+  if(filesize) {
     *filesize = File.Length;
+  }
     /* Hack to not return partition.Start for empty files. */
-    if( !File.Location )
+  if( !File.Location ) {
       return 0;
-    else
+  } else {
       return partition.Start + File.Location;
 }
+}
 
 
 
@@ -865,7 +1074,8 @@
  * Gets a Descriptor .
  * Returns 1 if descriptor found, 0 on error.
  * id, tagid of descriptor
- * bufsize, size of BlockBuf (must be >= DVD_VIDEO_LB_LEN).
+ * bufsize, size of BlockBuf (must be >= DVD_VIDEO_LB_LEN)
+ * and aligned for raw/O_DIRECT read.
  */
 static int UDFGetDescriptor( dvd_reader_t *device, int id,
 			     uint8_t *descriptor, int bufsize) 
@@ -919,19 +1129,25 @@
     }
   } while( i-- && ( !desc_found )  );
   
+  
   return desc_found;
 }
 
 
 static int UDFGetPVD(dvd_reader_t *device, struct pvd_t *pvd)
 {
-  uint8_t pvd_buf[DVD_VIDEO_LB_LEN];
+  uint8_t *pvd_buf;
   
   if(GetUDFCache(device, PVDCache, 0, pvd)) {
     return 1;
   }
 
-  if(!UDFGetDescriptor( device, 1, pvd_buf, sizeof(pvd_buf))) {
+  pvd_buf = dvdalign_lbmalloc(device, 1);
+  if(!pvd_buf) {
+    return 0;
+  }
+  if(!UDFGetDescriptor( device, 1, pvd_buf, 1*DVD_VIDEO_LB_LEN)) {
+    dvdalign_lbfree(device, pvd_buf);
     return 0;
   }
   
@@ -939,6 +1155,8 @@
   memcpy(pvd->VolumeSetIdentifier, &pvd_buf[72], 128);
   SetUDFCache(device, PVDCache, 0, pvd);
   
+  dvdalign_lbfree(device, pvd_buf);
+
   return 1;
 }
 
--- a/dvdread/dvd_udf.h	Wed Aug 15 10:34:53 2007 +0000
+++ b/dvdread/dvd_udf.h	Wed Aug 15 11:47:22 2007 +0000
@@ -31,7 +31,11 @@
  * http://www.gnu.org/copyleft/gpl.html
  */
 
+#if defined(HAVE_INTTYPES_H)
 #include <inttypes.h>
+#elif defined(HAVE_STDINT_H)
+#include <stdint.h>
+#endif
 
 #include "dvd_reader.h"
 
@@ -48,7 +52,7 @@
  */
 uint32_t UDFFindFile( dvd_reader_t *device, char *filename, uint32_t *size );
 
-void FreeUDFCache(void *cache);
+void FreeUDFCache(dvd_reader_t *device, void *cache);
 int UDFGetVolumeIdentifier(dvd_reader_t *device,
 			   char *volid, unsigned int volid_size);
 int UDFGetVolumeSetIdentifier(dvd_reader_t *device,
--- a/dvdread/dvdread_internal.h	Wed Aug 15 10:34:53 2007 +0000
+++ b/dvdread/dvdread_internal.h	Wed Aug 15 11:47:22 2007 +0000
@@ -5,4 +5,8 @@
 #define CHECK_VALUE(arg)
 
 
+int get_verbose(void);
+int dvdread_verbose(dvd_reader_t *dvd);
+dvd_reader_t *device_of_file(dvd_file_t *file);
+
 #endif /* DVDREAD_INTERNAL_H */
--- a/dvdread/ifo_print.c	Wed Aug 15 10:34:53 2007 +0000
+++ b/dvdread/ifo_print.c	Wed Aug 15 11:47:22 2007 +0000
@@ -27,13 +27,19 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
-#include <inttypes.h>
 #include <string.h>
 #include <ctype.h>
 
+#if defined(HAVE_INTTYPES_H)
+#include <inttypes.h>
+#elif defined(HAVE_STDINT_H)
+#include <stdint.h>
+#endif
+
 #include "ifo_types.h"
 #include "ifo_read.h"
 #include "ifo_print.h"
+#include "cmd_print.h"
 #include "dvdread_internal.h"
 
 /* Put this in some other file / package?  It's used in nav_print too. */
@@ -67,20 +73,6 @@
   printf(" @ %s fps", rate);
 }
 
-/* Put this in some other file / package?  It's used in nav_print too.
-   Possibly also by the vm / navigator. */
-static void ifoPrint_CMD(int row, vm_cmd_t *command) {
-  int i;
-
-  printf("(%03d) ", row + 1);
-  for(i=0;i<8;i++)
-    printf("%02x ", command->bytes[i]);
-  printf("| ");
-
-  //vmcmd(command);
-  printf("\n");
-}
-
 static void ifoPrint_video_attributes(video_attr_t *attr) {
   
   /* The following test is shorter but not correct ISO C,
@@ -261,6 +253,9 @@
   case 1:
     printf("%c%c (%c) ", attr->lang_code>>8, attr->lang_code & 0xff,
            attr->lang_extension ? attr->lang_extension : ' ');
+    if(attr->lang_extension) {
+      printf("(please send a bug report) lang_extension != 0");
+    }
     break;
   default:
     printf("(please send a bug report) ");
@@ -280,6 +275,29 @@
     printf("(please send a bug report) ");
   }
   
+  switch(attr->audio_format) {
+  case 0: //ac3
+    if(attr->quantization != 3) {
+      printf("(please send a bug report) ac3 quant/drc not 3 (%d)",
+             attr->quantization);
+    }
+    break;
+  case 2: //mpeg 1 or mpeg 2 without extension stream
+  case 3: //mpeg 2 with extension stream
+    switch(attr->quantization) {
+    case 0: //no drc
+      printf("no drc ");
+      break;
+    case 1:
+      printf("drc ");
+      break;
+    default:
+      printf("(please send a bug report) mpeg reserved quant/drc  (%d)",
+             attr->quantization);
+      break;
+    }
+    break;
+  case 4:
   switch(attr->quantization) {
   case 0:
     printf("16bit ");
@@ -291,10 +309,19 @@
     printf("24bit ");
     break;
   case 3:
-    printf("drc ");
+      printf("(please send a bug report) lpcm reserved quant/drc  (%d)",
+             attr->quantization);
+      break;
+    }
+    break;
+  case 6: //dts
+    if(attr->quantization != 3) {
+      printf("(please send a bug report) dts quant/drc not 3 (%d)",
+             attr->quantization);
+    }
     break;
   default:
-    printf("(please send a bug report) ");
+    break;
   }
   
   switch(attr->sample_frequency) {
@@ -302,7 +329,7 @@
     printf("48kHz ");
     break;
   case 1:
-    printf("??kHz ");
+    printf("96kHz ");
     break;
   default:
     printf("sample_frequency %i (please send a bug report) ", 
@@ -387,10 +414,9 @@
   
   printf("%d ", attr->zero1);
   printf("%d ", attr->zero2);
-  printf("%d ", attr->code_extension);
+  printf("%d ", attr->lang_extension);
   
-  /* Is this correct?  should it not be subp_code_ext here instead? */
-  switch(attr->lang_extension) {
+  switch(attr->code_extension) {
   case 0:
     printf("Not specified ");
     break;
@@ -640,17 +666,17 @@
   
   printf("Number of Pre commands: %i\n", cmd_tbl->nr_of_pre);
   for(i = 0; i < cmd_tbl->nr_of_pre; i++) {
-    ifoPrint_CMD(i, &cmd_tbl->pre_cmds[i]);
+    cmdPrint_CMD(i, &cmd_tbl->pre_cmds[i]);
   }
 
   printf("Number of Post commands: %i\n", cmd_tbl->nr_of_post);
   for(i = 0; i < cmd_tbl->nr_of_post; i++) {
-    ifoPrint_CMD(i, &cmd_tbl->post_cmds[i]);
+    cmdPrint_CMD(i, &cmd_tbl->post_cmds[i]);
   }
 
   printf("Number of Cell commands: %i\n", cmd_tbl->nr_of_cell);
   for(i = 0; i < cmd_tbl->nr_of_cell; i++) {
-    ifoPrint_CMD(i, &cmd_tbl->cell_cmds[i]);
+    cmdPrint_CMD(i, &cmd_tbl->cell_cmds[i]);
   }
 }
 
@@ -754,6 +780,11 @@
 void ifoPrint_PGC(pgc_t *pgc) {
   int i;
   
+  if(pgc == NULL) {
+    printf("Error: No PGC present\n");
+    return;
+  }
+
   printf("Number of Programs: %i\n", pgc->nr_of_programs);
   printf("Number of Cells: %i\n", pgc->nr_of_cells);
   /* Check that time is 0:0:0:0 also if nr_of_programs==0 */
@@ -765,14 +796,14 @@
   ifoPrint_USER_OPS(&pgc->prohibited_ops);
   
     for(i = 0; i < 8; i++) {
-      if(pgc->audio_control[i].present) {
+    if(pgc->audio_control[i].present) { /* The 'is present' bit */
 	printf("Audio stream %i control: %04x\n", 
 	       i, pgc->audio_control[i]);
       }
     }
   
   for(i = 0; i < 32; i++) {
-    if(pgc->subp_control[i].present) {
+    if(pgc->subp_control[i].present) { /* The 'is present' bit */
       printf("Subpicture stream %2i control: %08x\n", 
 	     i, pgc->subp_control[i]);
     }
@@ -918,7 +949,7 @@
   
   printf("Number of VOBs in this VOBS: %i\n", c_adt->nr_of_vobs);
   //entries = c_adt->nr_of_vobs;
-  entries = (c_adt->last_byte + 1 - C_ADT_SIZE)/sizeof(c_adt_t);
+  entries = (c_adt->last_byte + 1 - C_ADT_SIZE)/sizeof(cell_adr_t);
   
   for(i = 0; i < entries; i++) {
     printf("VOB ID: %3i, Cell ID: %3i   ", 
@@ -1030,7 +1061,9 @@
 
   ifohandle = ifoOpen(dvd, title);
   if(!ifohandle) {
+    if(dvdread_verbose(dvd) >= 0) {
     fprintf(stderr, "Can't open info file for title %d\n", title);
+    }
     return;
   }
   
@@ -1041,7 +1074,11 @@
     ifoPrint_VMGI_MAT(ifohandle->vmgi_mat);
 
     printf("\nFirst Play PGC\n--------------\n");
+    if(ifohandle->first_play_pgc) {
     ifoPrint_PGC(ifohandle->first_play_pgc);
+    } else {
+      printf("No First Play PGC present\n");
+    }
 
     printf("\nTitle Track search pointer table\n");
     printf(  "------------------------------------------------\n");
--- a/dvdread/ifo_read.c	Wed Aug 15 10:34:53 2007 +0000
+++ b/dvdread/ifo_read.c	Wed Aug 15 11:47:22 2007 +0000
@@ -26,8 +26,15 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+
+#if defined(HAVE_INTTYPES_H)
 #include <inttypes.h>
+#elif defined(HAVE_STDINT_H)
+#include <stdint.h>
+#endif
+
 #include <string.h>
+#include <errno.h>
 
 #include "bswap.h"
 #include "ifo_types.h"
@@ -92,6 +99,11 @@
 static void ifoFree_PGC_COMMAND_TBL(pgc_command_tbl_t *cmd_tbl);
 static void ifoFree_PGCIT_internal(pgcit_t *pgcit);
 
+static ifo_handle_t *ifoOpen_File(ifo_handle_t *ifofile, int title, 
+                                  char *suffix);
+static ifo_handle_t *ifoOpenVMGI_File(ifo_handle_t *ifofile, char *suffix);
+static ifo_handle_t *ifoOpenVTSI_File(ifo_handle_t *ifofile, int title,
+                                      char *suffix);
 
 static inline int DVDFileSeek_( dvd_file_t *dvd_file, uint32_t offset ) {
   return (DVDFileSeek(dvd_file, (int)offset) == (int)offset);
@@ -103,21 +115,52 @@
 
   ifofile = malloc(sizeof(ifo_handle_t));
   if(!ifofile)
-    return 0;
+    return NULL;
 
   memset(ifofile, 0, sizeof(ifo_handle_t));
 
   ifofile->file = DVDOpenFile(dvd, title, DVD_READ_INFO_FILE);
-  if(!ifofile->file) /* Should really catch any error and try to fallback */
+  if(!ifoOpen_File(ifofile, title, "IFO")) {
+    if(title) {
+      if(dvdread_verbose(dvd) >= 1) {
+        fprintf(stderr, "libdvdread: Can't open file VTS_%02d_0.%s.\n", 
+                title, "IFO");
+      }
+    } else {
+      if(dvdread_verbose(dvd) >= 1) {
+        fprintf(stderr, "libdvdread: Can't open file VIDEO_TS.%s.\n", "IFO");
+      }
+    }
+    /* lower functions free the pointer, reallocate */
+    ifofile = (ifo_handle_t *)malloc(sizeof(ifo_handle_t));
+    if(!ifofile)
+      return NULL;
+
+    memset(ifofile, 0, sizeof(ifo_handle_t));
+
     ifofile->file = DVDOpenFile(dvd, title, DVD_READ_INFO_BACKUP_FILE);
-  if(!ifofile->file) {
+    if(!ifoOpen_File(ifofile, title, "BUP")) {
     if(title) {
-      fprintf(stderr, "libdvdread: Can't open file VTS_%02d_0.IFO.\n", title);
+        if(dvdread_verbose(dvd) >= 1) {
+          fprintf(stderr, "libdvdread: Can't open file VTS_%02d_0.%s.\n", 
+                  title, "BUP");
+        }
     } else {
-      fprintf(stderr, "libdvdread: Can't open file VIDEO_TS.IFO.\n");
+        if(dvdread_verbose(dvd) >= 1) {
+          fprintf(stderr, "libdvdread: Can't open file VIDEO_TS.%s.\n", "BUP");
+        }
+      }
+      return NULL;
+    }
     }
+  return ifofile;
+}
+
+static ifo_handle_t *ifoOpen_File(ifo_handle_t *ifofile, int title, 
+                                  char *suffix) {
+  if(!ifofile->file) {
     free(ifofile);
-    return 0;
+    return NULL;
   }
 
   /* First check if this is a VMGI file. */
@@ -125,9 +168,12 @@
 
     /* These are both mandatory. */
     if(!ifoRead_FP_PGC(ifofile) || !ifoRead_TT_SRPT(ifofile)) {
-      fprintf(stderr, "libdvdread: Invalid main menu IFO (VIDEO_TS.IFO).\n");
+      if(dvdread_verbose(device_of_file(ifofile->file)) >= 0) {
+        fprintf(stderr, "libdvdread: Invalid main menu IFO (VIDEO_TS.%s).\n",
+                suffix);
+      }
       ifoClose(ifofile);
-      return 0;
+      return NULL;
     }
 
     ifoRead_PGCI_UT(ifofile);
@@ -135,9 +181,12 @@
 
     /* This is also mandatory. */
     if(!ifoRead_VTS_ATRT(ifofile)) {
-      fprintf(stderr, "libdvdread: Invalid main menu IFO (VIDEO_TS.IFO).\n");
+      if(dvdread_verbose(device_of_file(ifofile->file)) >= 0) {
+        fprintf(stderr, "libdvdread: Invalid main menu IFO (VIDEO_TS.%s).\n",
+                suffix);
+      }
       ifoClose(ifofile);
-      return 0;
+      return NULL;
     }
 
     ifoRead_TXTDT_MGI(ifofile);
@@ -150,36 +199,44 @@
   if(ifoRead_VTS(ifofile)) {
 
     if(!ifoRead_VTS_PTT_SRPT(ifofile) || !ifoRead_PGCIT(ifofile)) {
-      fprintf(stderr, "libdvdread: Invalid title IFO (VTS_%02d_0.IFO).\n",
-              title);
+      if(dvdread_verbose(device_of_file(ifofile->file)) >= 0) {
+        fprintf(stderr, "libdvdread: Invalid title IFO (VTS_%02d_0.%s).\n",
+                title, suffix);
+      }
       ifoClose(ifofile);
-      return 0;
+      return NULL;
     }
 
-
     ifoRead_PGCI_UT(ifofile);
     ifoRead_VTS_TMAPT(ifofile);
     ifoRead_C_ADT(ifofile);
     ifoRead_VOBU_ADMAP(ifofile);
 
     if(!ifoRead_TITLE_C_ADT(ifofile) || !ifoRead_TITLE_VOBU_ADMAP(ifofile)) {
-      fprintf(stderr, "libdvdread: Invalid title IFO (VTS_%02d_0.IFO).\n",
-              title);
+      if(dvdread_verbose(device_of_file(ifofile->file)) >= 0) {
+        fprintf(stderr, "libdvdread: Invalid title IFO (VTS_%02d_0.%s).\n",
+                title, suffix);
+      }
       ifoClose(ifofile);
-      return 0;
+      return NULL;
     }
 
     return ifofile;
   }
 
   if(title) {
-    fprintf(stderr, "libdvdread: Invalid IFO for title %d (VTS_%02d_0.IFO).\n",
-	    title, title);
+    if(dvdread_verbose(device_of_file(ifofile->file)) >= 0) {
+      fprintf(stderr, "libdvdread: Invalid IFO for title %d (VTS_%02d_0.%s).\n",
+              title, title, suffix);
+    }
   } else {
-    fprintf(stderr, "libdvdread: Invalid IFO for VMGM (VIDEO_TS.IFO).\n");
+    if(dvdread_verbose(device_of_file(ifofile->file)) >= 0) {
+      fprintf(stderr, "libdvdread: Invalid IFO for VMGM (VIDEO_TS.%s).\n", 
+              suffix);
+    }
   }
   ifoClose(ifofile);
-  return 0;
+  return NULL;
 }
 
 
@@ -188,25 +245,50 @@
 
   ifofile = malloc(sizeof(ifo_handle_t));
   if(!ifofile)
-    return 0;
+    return NULL;
 
   memset(ifofile, 0, sizeof(ifo_handle_t));
 
   ifofile->file = DVDOpenFile(dvd, 0, DVD_READ_INFO_FILE);
-  if(!ifofile->file) /* Should really catch any error and try to fallback */
+  if(!ifoOpenVMGI_File(ifofile, "IFO")) {
+    if(dvdread_verbose(dvd) >= 1) {
+      fprintf(stderr, "libdvdread: Can't open file VIDEO_TS.IFO: %s\n",
+              strerror(errno));
+    }
+
+    /* lower functions free the pointer, reallocate */
+    ifofile = (ifo_handle_t *)malloc(sizeof(ifo_handle_t));
+    if(!ifofile)
+      return NULL;
+
+    memset(ifofile, 0, sizeof(ifo_handle_t));
+
     ifofile->file = DVDOpenFile(dvd, 0, DVD_READ_INFO_BACKUP_FILE);
+    if(!ifoOpenVMGI_File(ifofile, "BUP"))
+      if(dvdread_verbose(dvd) >= 1) {
+        fprintf(stderr, "libdvdread: Can't open file VIDEO_TS.BUP: %s\n",
+                strerror(errno));
+      }
+      return NULL;
+  }
+  return ifofile;
+}
+
+static ifo_handle_t *ifoOpenVMGI_File(ifo_handle_t *ifofile, char *suffix) {
   if(!ifofile->file) {
-    fprintf(stderr, "libdvdread: Can't open file VIDEO_TS.IFO.\n");
     free(ifofile);
-    return 0;
+    return NULL;
   }
 
   if(ifoRead_VMG(ifofile))
     return ifofile;
 
-  fprintf(stderr, "libdvdread: Invalid main menu IFO (VIDEO_TS.IFO).\n");
+  if(dvdread_verbose(device_of_file(ifofile->file)) >= 0) {
+    fprintf(stderr, "libdvdread: Invalid main menu IFO (VIDEO_TS.%s).\n", 
+            suffix);
+  }
   ifoClose(ifofile);
-  return 0;
+  return NULL;
 }
 
 
@@ -215,33 +297,57 @@
   
   ifofile = malloc(sizeof(ifo_handle_t));
   if(!ifofile)
-    return 0;
+    return NULL;
 
   memset(ifofile, 0, sizeof(ifo_handle_t));
   
   if(title <= 0 || title > 99) {
+    if(dvdread_verbose(dvd) >= 0) {
     fprintf(stderr, "libdvdread: ifoOpenVTSI invalid title (%d).\n", title);
+    }
     free(ifofile);
-    return 0;
+    errno = EINVAL;
+    return NULL;
   }
     
   ifofile->file = DVDOpenFile(dvd, title, DVD_READ_INFO_FILE);
-  if(!ifofile->file) /* Should really catch any error and try to fallback */
+  if(!ifoOpenVTSI_File(ifofile, title, "IFO")) {
+    if(dvdread_verbose(dvd) >= 1) {
+      fprintf(stderr, "libdvdread: Can't open file VTS_%02d_0.%s.\n", title, "IFO");
+    }
+    /* lower functions free the pointer, reallocate */
+    ifofile = (ifo_handle_t *)malloc(sizeof(ifo_handle_t));
+    if(!ifofile)
+      return NULL;
+
+    memset(ifofile, 0, sizeof(ifo_handle_t));
+
     ifofile->file = DVDOpenFile(dvd, title, DVD_READ_INFO_BACKUP_FILE);
+    if(!ifoOpenVTSI_File(ifofile, title, "BUP"))
+      if(dvdread_verbose(dvd) >= 1) {
+        fprintf(stderr, "libdvdread: Can't open file VTS_%02d_0.%s.\n", title, "BUP");
+      }
+      return NULL;
+  }
+  return ifofile;
+}
+
+static ifo_handle_t *ifoOpenVTSI_File(ifo_handle_t* ifofile, int title, char *suffix) {
   if(!ifofile->file) {
-    fprintf(stderr, "libdvdread: Can't open file VTS_%02d_0.IFO.\n", title);
     free(ifofile);
-    return 0;
+    return NULL;
   }
 
   ifoRead_VTS(ifofile);
   if(ifofile->vtsi_mat)
     return ifofile;
 
-  fprintf(stderr, "libdvdread: Invalid IFO for title %d (VTS_%02d_0.IFO).\n",
-          title, title);
+  if(dvdread_verbose(device_of_file(ifofile->file)) >= 0) {
+    fprintf(stderr, "libdvdread: Invalid IFO for title %d (VTS_%02d_0.%s).\n",
+            title, title, suffix);
+  }
   ifoClose(ifofile);
-  return 0;
+  return NULL;
 }
 
 
@@ -261,6 +367,7 @@
   ifoFree_FP_PGC(ifofile);
   ifoFree_PGCIT(ifofile);
   ifoFree_VTS_PTT_SRPT(ifofile);
+  ifoFree_VTS_TMAPT(ifofile);
 
   if(ifofile->vmgi_mat)
     free(ifofile->vmgi_mat);
@@ -480,6 +587,7 @@
 static int ifoRead_PGC_COMMAND_TBL(ifo_handle_t *ifofile, 
                                    pgc_command_tbl_t *cmd_tbl, 
 				   unsigned int offset) {
+  unsigned int total;
   
   memset(cmd_tbl, 0, sizeof(pgc_command_tbl_t));
   
@@ -492,8 +600,12 @@
   B2N_16(cmd_tbl->nr_of_pre);
   B2N_16(cmd_tbl->nr_of_post);
   B2N_16(cmd_tbl->nr_of_cell);
+  B2N_16(cmd_tbl->last_byte);
 
-  CHECK_VALUE(cmd_tbl->nr_of_pre + cmd_tbl->nr_of_post + cmd_tbl->nr_of_cell<= 255);
+  total = cmd_tbl->nr_of_pre + cmd_tbl->nr_of_post + cmd_tbl->nr_of_cell;
+  CHECK_VALUE(PGC_COMMAND_TBL_SIZE + total * COMMAND_DATA_SIZE 
+              <= cmd_tbl->last_byte + 1U);
+  CHECK_VALUE(total <= 255);
      
   if(cmd_tbl->nr_of_pre != 0) {
     unsigned int pre_cmds_size  = cmd_tbl->nr_of_pre * COMMAND_DATA_SIZE;
@@ -684,6 +796,8 @@
   }
   
   if(pgc->program_map_offset != 0) {
+    if(pgc->nr_of_programs != 0) {
+
     pgc->program_map = malloc(pgc->nr_of_programs * sizeof(pgc_program_map_t));
     if(!pgc->program_map) {
       ifoFree_PGC_COMMAND_TBL(pgc->command_tbl);
@@ -698,8 +812,13 @@
   } else {
     pgc->program_map = NULL;
   }
+  } else {
+    pgc->program_map = NULL;
+  }
   
   if(pgc->cell_playback_offset != 0) {
+    if(pgc->nr_of_cells != 0) {
+
     pgc->cell_playback = malloc(pgc->nr_of_cells * sizeof(cell_playback_t));
     if(!pgc->cell_playback) {
       ifoFree_PGC_COMMAND_TBL(pgc->command_tbl);
@@ -719,8 +838,13 @@
   } else {
     pgc->cell_playback = NULL;
   }
+  } else {
+    pgc->cell_playback = NULL;
+  }
   
   if(pgc->cell_position_offset != 0) {
+    if(pgc->nr_of_cells != 0) {
+
     pgc->cell_position = malloc(pgc->nr_of_cells * sizeof(cell_position_t));
     if(!pgc->cell_position) {
       ifoFree_PGC(pgc);
@@ -735,6 +859,9 @@
   } else {
     pgc->cell_position = NULL;
   }
+  } else {
+    pgc->cell_position = NULL;
+  }
 
   return 1;
 }
@@ -813,7 +940,9 @@
   ifofile->tt_srpt = tt_srpt;
   
   if(!(DVDReadBytes(ifofile->file, tt_srpt, TT_SRPT_SIZE))) {
+    if(dvdread_verbose(device_of_file(ifofile->file)) >= 1) {
     fprintf(stderr, "libdvdread: Unable to read read TT_SRPT.\n");
+    }
     free(tt_srpt);
     return 0;
   }
@@ -830,7 +959,9 @@
     return 0;
   }
   if(!(DVDReadBytes(ifofile->file, tt_srpt->title, info_length))) {
+    if(dvdread_verbose(device_of_file(ifofile->file)) >= 1) {
     fprintf(stderr, "libdvdread: Unable to read read TT_SRPT.\n");
+    }
     ifoFree_TT_SRPT(ifofile);
     return 0;
   }
@@ -845,7 +976,7 @@
   CHECK_ZERO(tt_srpt->zero_1);
   CHECK_VALUE(tt_srpt->nr_of_srpts != 0);
   CHECK_VALUE(tt_srpt->nr_of_srpts < 100); // ??
-  CHECK_VALUE((int)tt_srpt->nr_of_srpts * sizeof(title_info_t) <= info_length);
+  CHECK_VALUE(tt_srpt->nr_of_srpts * sizeof(title_info_t) <= info_length);
   
   for(i = 0; i < tt_srpt->nr_of_srpts; i++) {
     CHECK_VALUE(tt_srpt->title[i].pb_ty.zero_1 == 0);
@@ -915,7 +1046,9 @@
   ifofile->vts_ptt_srpt = vts_ptt_srpt;
 
   if(!(DVDReadBytes(ifofile->file, vts_ptt_srpt, VTS_PTT_SRPT_SIZE))) {
+    if(dvdread_verbose(device_of_file(ifofile->file)) >= 1) {
     fprintf(stderr, "libdvdread: Unable to read PTT search table.\n");
+    }
     free(vts_ptt_srpt);
     return 0;
   }
@@ -936,7 +1069,9 @@
     return 0;
   }
   if(!(DVDReadBytes(ifofile->file, data, info_length))) {
+    if(dvdread_verbose(device_of_file(ifofile->file)) >= 1) {
     fprintf(stderr, "libdvdread: Unable to read PTT search table.\n");
+    }
     free(vts_ptt_srpt);
     free(data);
     ifofile->vts_ptt_srpt = 0;
@@ -1080,7 +1215,9 @@
   
   for(i = 0; i < ptl_mait->nr_of_countries; i++) {
     if(!(DVDReadBytes(ifofile->file, &ptl_mait->countries[i], PTL_MAIT_COUNTRY_SIZE))) {
+      if(dvdread_verbose(device_of_file(ifofile->file)) >= 1) {
       fprintf(stderr, "libdvdread: Unable to read PTL_MAIT.\n");
+      }
       free(ptl_mait->countries);
       free(ptl_mait);
       ifofile->ptl_mait = 0;
@@ -1096,8 +1233,8 @@
   for(i = 0; i < ptl_mait->nr_of_countries; i++) {
     CHECK_ZERO(ptl_mait->countries[i].zero_1);
     CHECK_ZERO(ptl_mait->countries[i].zero_2);    
-    CHECK_VALUE(ptl_mait->countries[i].pf_ptl_mai_start_byte
-		+ 8*2 * (ptl_mait->nr_of_vtss + 1) <= ptl_mait->last_byte + 1);
+    CHECK_VALUE(ptl_mait->countries[i].pf_ptl_mai_start_byte +
+                16U * (ptl_mait->nr_of_vtss + 1) <= ptl_mait->last_byte + 1U);
   }
 
   for(i = 0; i < ptl_mait->nr_of_countries; i++) {
@@ -1106,7 +1243,9 @@
     if(!DVDFileSeek_(ifofile->file, 
 		     ifofile->vmgi_mat->ptl_mait * DVD_BLOCK_LEN
                      + ptl_mait->countries[i].pf_ptl_mai_start_byte)) {
+      if(dvdread_verbose(device_of_file(ifofile->file)) >= 1) {
       fprintf(stderr, "libdvdread: Unable to seak PTL_MAIT table.\n");
+      }
       free(ptl_mait->countries);
       free(ptl_mait);
       return 0;
@@ -1122,7 +1261,9 @@
       return 0;
     }
     if(!(DVDReadBytes(ifofile->file, pf_temp, info_length))) {
+      if(dvdread_verbose(device_of_file(ifofile->file)) >= 1) {
        fprintf(stderr, "libdvdread: Unable to read PTL_MAIT table.\n");
+      }
        free(pf_temp);
        for(j = 0; j < i ; j++) {
 	  free(ptl_mait->countries[j].pf_ptl_mai);
@@ -1187,9 +1328,9 @@
   if(!ifofile->vtsi_mat)
     return 0;
 
-  if(ifofile->vtsi_mat->vts_tmapt == 0) { /* optional(?) */
+  /* Seems to be optional, at least when there are no OneSequencial Titles */
+  if(ifofile->vtsi_mat->vts_tmapt == 0) {
     ifofile->vts_tmapt = NULL;
-    fprintf(stderr,"Please send bug report - no VTS_TMAPT ?? \n");
     return 1;
   }
   
@@ -1205,7 +1346,9 @@
   ifofile->vts_tmapt = vts_tmapt;
   
   if(!(DVDReadBytes(ifofile->file, vts_tmapt, VTS_TMAPT_SIZE))) {
+    if(dvdread_verbose(device_of_file(ifofile->file)) >= 1) {
     fprintf(stderr, "libdvdread: Unable to read VTS_TMAPT.\n");
+    }
     free(vts_tmapt);
     ifofile->vts_tmapt = NULL;
     return 0;
@@ -1228,7 +1371,9 @@
   vts_tmapt->tmap_offset = vts_tmap_srp;
   
   if(!(DVDReadBytes(ifofile->file, vts_tmap_srp, info_length))) {
+    if(dvdread_verbose(device_of_file(ifofile->file)) >= 1) {
     fprintf(stderr, "libdvdread: Unable to read VTS_TMAPT.\n");
+    }
     free(vts_tmap_srp);
     free(vts_tmapt);
     ifofile->vts_tmapt = NULL;
@@ -1259,7 +1404,9 @@
     }
 
     if(!(DVDReadBytes(ifofile->file, &vts_tmapt->tmap[i], VTS_TMAP_SIZE))) {
+      if(dvdread_verbose(device_of_file(ifofile->file)) >= 1) {
       fprintf(stderr, "libdvdread: Unable to read VTS_TMAP.\n");
+      }
       ifoFree_VTS_TMAPT(ifofile);
       return 0;
     }
@@ -1281,7 +1428,9 @@
     }
 
     if(!(DVDReadBytes(ifofile->file, vts_tmapt->tmap[i].map_ent, info_length))) {
+      if(dvdread_verbose(device_of_file(ifofile->file)) >= 1) {
       fprintf(stderr, "libdvdread: Unable to read VTS_TMAP_ENT.\n");
+      }
       ifoFree_VTS_TMAPT(ifofile);
       return 0;
     }
@@ -1392,7 +1541,9 @@
      Enemy of the State region 2 (de) has Titles where nr_of_vobs field
      is to high, they high ones are never referenced though. */
   if(info_length / sizeof(cell_adr_t) < c_adt->nr_of_vobs) {
+    if(dvdread_verbose(device_of_file(ifofile->file)) >= 1) {
     fprintf(stderr, "libdvdread: *C_ADT nr_of_vobs > avaiable info entries\n");
+    }
     c_adt->nr_of_vobs = info_length / sizeof(cell_adr_t);
   }
   
@@ -1624,8 +1775,8 @@
   }
   ptr = data;
   for(i = 0; i < pgcit->nr_of_pgci_srp; i++) {
-    memcpy(&pgcit->pgci_srp[i], ptr, PGCI_LU_SIZE);
-    ptr += PGCI_LU_SIZE;
+    memcpy(&pgcit->pgci_srp[i], ptr, PGCI_SRP_SIZE);
+    ptr += PGCI_SRP_SIZE;
     B2N_16(pgcit->pgci_srp[i].ptl_id_mask);
     B2N_32(pgcit->pgci_srp[i].pgc_start_byte);
     CHECK_VALUE(pgcit->pgci_srp[i].unknown1 == 0);
@@ -1643,6 +1794,8 @@
         ifoFree_PGC(pgcit->pgci_srp[j].pgc);
         free(pgcit->pgci_srp[j].pgc);
       }
+      free(pgcit->pgci_srp);
+      pgcit->pgci_srp = NULL;
       return 0;
     }
     if(!ifoRead_PGC(ifofile, pgcit->pgci_srp[i].pgc, 
@@ -1653,6 +1806,7 @@
         free(pgcit->pgci_srp[j].pgc);
       }
       free(pgcit->pgci_srp);
+      pgcit->pgci_srp = NULL;
       return 0;
     }
   }
@@ -1663,8 +1817,10 @@
 static void ifoFree_PGCIT_internal(pgcit_t *pgcit) {
   if(pgcit) {
     int i;
-    for(i = 0; i < pgcit->nr_of_pgci_srp; i++)
+    for(i = 0; i < pgcit->nr_of_pgci_srp; i++) {
       ifoFree_PGC(pgcit->pgci_srp[i].pgc);
+      free(pgcit->pgci_srp[i].pgc);
+    }
     free(pgcit->pgci_srp);
   }
 }
@@ -2000,7 +2156,9 @@
   ifofile->txtdt_mgi = txtdt_mgi;
 
   if(!(DVDReadBytes(ifofile->file, txtdt_mgi, TXTDT_MGI_SIZE))) {
+    if(dvdread_verbose(device_of_file(ifofile->file)) >= 1) {
     fprintf(stderr, "libdvdread: Unable to read TXTDT_MGI.\n");
+    }
     free(txtdt_mgi);
     ifofile->txtdt_mgi = 0;
     return 0;
--- a/dvdread/ifo_types.h	Wed Aug 15 10:34:53 2007 +0000
+++ b/dvdread/ifo_types.h	Wed Aug 15 11:47:22 2007 +0000
@@ -24,9 +24,17 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include <inttypes.h>
 #include <dvdread/dvd_reader.h>
 
+#if defined(__BEOS__)
+#if !defined(_INTTYPES_H_) && !defined(_INTTYPES_H) && !defined(_STDINT_H_) && !defined(_STDINT_H)
+#error "Must include <inttypes.h> or <stdint.h> before any libdvdread header."
+#endif
+#else
+#if !defined(UINT8_MAX) || !defined(UINT16_MAX) || !defined(INT32_MAX)
+#error "Must include <inttypes.h> or <stdint.h> before any libdvdread header."
+#endif
+#endif
 
 #undef ATTRIBUTE_PACKED
 #undef PRAGMA_PACK_BEGIN 
@@ -72,7 +80,7 @@
 typedef struct {
   uint8_t bytes[8];
 } ATTRIBUTE_PACKED vm_cmd_t;
-#define COMMAND_DATA_SIZE 8
+#define COMMAND_DATA_SIZE 8U
 
 
 /**
@@ -140,7 +148,7 @@
   uint8_t  code_extension;
   uint8_t unknown3;
   union {
-    struct ATTRIBUTE_PACKED {
+    struct {
 #ifdef WORDS_BIGENDIAN
       unsigned int unknown4           : 1;
       unsigned int channel_assignment : 3;
@@ -154,8 +162,8 @@
       unsigned int channel_assignment : 3;
       unsigned int unknown4           : 1;
 #endif
-    } karaoke;
-    struct ATTRIBUTE_PACKED {
+    } ATTRIBUTE_PACKED karaoke;
+    struct {
 #ifdef WORDS_BIGENDIAN
       unsigned int unknown5           : 4;
       unsigned int dolby_encoded      : 1; /* suitable for surround decoding */
@@ -165,7 +173,7 @@
       unsigned int dolby_encoded      : 1;
       unsigned int unknown5           : 4;
 #endif
-    } surround;
+    } ATTRIBUTE_PACKED surround;
   } app_info;
 } ATTRIBUTE_PACKED audio_attr_t;
 
@@ -265,12 +273,12 @@
   uint16_t nr_of_pre;
   uint16_t nr_of_post;
   uint16_t nr_of_cell;
-  uint16_t zero_1;
+  uint16_t last_byte;
   vm_cmd_t *pre_cmds;
   vm_cmd_t *post_cmds;
   vm_cmd_t *cell_cmds;
 } ATTRIBUTE_PACKED pgc_command_tbl_t;
-#define PGC_COMMAND_TBL_SIZE 8
+#define PGC_COMMAND_TBL_SIZE 8U
 
 /**
  * PGC Program Map
@@ -460,8 +468,8 @@
   uint16_t next_pgc_nr;
   uint16_t prev_pgc_nr;
   uint16_t goup_pgc_nr;
+  uint8_t  pg_playback_mode;
   uint8_t  still_time;
-  uint8_t  pg_playback_mode;
   uint32_t palette[16]; /* New type struct {zero_1, Y, Cr, Cb} ? */
   uint16_t command_tbl_offset;
   uint16_t program_map_offset;
@@ -472,7 +480,7 @@
   cell_playback_t *cell_playback;
   cell_position_t *cell_position;
 } ATTRIBUTE_PACKED pgc_t;
-#define PGC_SIZE 236
+#define PGC_SIZE 236U
 
 /**
  * Program Chain Information Search Pointer.
@@ -492,7 +500,7 @@
   uint32_t pgc_start_byte;
   pgc_t *pgc;
 } ATTRIBUTE_PACKED pgci_srp_t;
-#define PGCI_SRP_SIZE 8
+#define PGCI_SRP_SIZE 8U
 
 /**
  * Program Chain Information Table.
@@ -503,7 +511,7 @@
   uint32_t last_byte;
   pgci_srp_t *pgci_srp;
 } ATTRIBUTE_PACKED pgcit_t;
-#define PGCIT_SIZE 8
+#define PGCIT_SIZE 8U
 
 /**
  * Menu PGCI Language Unit.
@@ -515,7 +523,7 @@
   uint32_t lang_start_byte;
   pgcit_t *pgcit;
 } ATTRIBUTE_PACKED pgci_lu_t;
-#define PGCI_LU_SIZE 8
+#define PGCI_LU_SIZE 8U
 
 /**
  * Menu PGCI Unit Table.
@@ -526,7 +534,7 @@
   uint32_t last_byte;
   pgci_lu_t *lu;
 } ATTRIBUTE_PACKED pgci_ut_t;
-#define PGCI_UT_SIZE 8
+#define PGCI_UT_SIZE 8U
 
 /**
  * Cell Address Information.
@@ -548,7 +556,7 @@
   uint32_t last_byte;
   cell_adr_t *cell_adr_table;  /* No explicit size given. */
 } ATTRIBUTE_PACKED c_adt_t;
-#define C_ADT_SIZE 8
+#define C_ADT_SIZE 8U
 
 /**
  * VOBU Address Map.
@@ -557,7 +565,7 @@
   uint32_t last_byte;
   uint32_t *vobu_start_sectors;
 } ATTRIBUTE_PACKED vobu_admap_t;
-#define VOBU_ADMAP_SIZE 4
+#define VOBU_ADMAP_SIZE 4U
 
 
 
@@ -655,7 +663,7 @@
   uint32_t last_byte;
   title_info_t *title;
 } ATTRIBUTE_PACKED tt_srpt_t;
-#define TT_SRPT_SIZE 8
+#define TT_SRPT_SIZE 8U
 
 
 /**
@@ -674,7 +682,7 @@
   uint16_t zero_2;
   pf_level_t *pf_ptl_mai; /* table of (nr_of_vtss + 1), video_ts is first */
 } ATTRIBUTE_PACKED ptl_mait_country_t;
-#define PTL_MAIT_COUNTRY_SIZE 8
+#define PTL_MAIT_COUNTRY_SIZE 8U
 
 /**
  * Parental Management Information Table.
@@ -685,7 +693,7 @@
   uint32_t last_byte;
   ptl_mait_country_t *countries;
 } ATTRIBUTE_PACKED ptl_mait_t;
-#define PTL_MAIT_SIZE 8
+#define PTL_MAIT_SIZE 8U
 
 /**
  * Video Title Set Attributes.
@@ -716,8 +724,8 @@
   uint8_t  nr_of_vtstt_subp_streams;
   subp_attr_t vtstt_subp_attr[32];
 } ATTRIBUTE_PACKED vts_attributes_t;
-#define VTS_ATTRIBUTES_SIZE 542
-#define VTS_ATTRIBUTES_MIN_SIZE 356
+#define VTS_ATTRIBUTES_SIZE 542U
+#define VTS_ATTRIBUTES_MIN_SIZE 356U
 
 /**
  * Video Title Set Attribute Table.
@@ -729,7 +737,7 @@
   vts_attributes_t *vts;
   uint32_t *vts_atrt_offsets; /* offsets table for each vts_attributes */
 } ATTRIBUTE_PACKED vts_atrt_t;
-#define VTS_ATRT_SIZE 8
+#define VTS_ATRT_SIZE 8U
 
 /**
  * Text Data. (Incomplete)
@@ -762,7 +770,7 @@
   uint32_t txtdt_start_byte;  /* prt, rel start of vmg_txtdt_mgi  */
   txtdt_t  *txtdt;
 } ATTRIBUTE_PACKED txtdt_lu_t;
-#define TXTDT_LU_SIZE 8
+#define TXTDT_LU_SIZE 8U
 
 /**
  * Text Data Manager Information. (Incomplete)
@@ -773,7 +781,7 @@
   uint32_t last_byte;
   txtdt_lu_t *lu;
 } ATTRIBUTE_PACKED txtdt_mgi_t;
-#define TXTDT_MGI_SIZE 20
+#define TXTDT_MGI_SIZE 20U
 
 
 /**
@@ -865,7 +873,7 @@
   ttu_t  *title;
   uint32_t *ttu_offset; /* offset table for each ttu */
 } ATTRIBUTE_PACKED vts_ptt_srpt_t;
-#define VTS_PTT_SRPT_SIZE 8
+#define VTS_PTT_SRPT_SIZE 8U
 
 
 /**
@@ -883,7 +891,7 @@
   uint16_t nr_of_entries;
   map_ent_t *map_ent;
 } ATTRIBUTE_PACKED vts_tmap_t;
-#define VTS_TMAP_SIZE 4
+#define VTS_TMAP_SIZE 4U
 
 /**
  * Time Map Table.
@@ -895,7 +903,7 @@
   vts_tmap_t *tmap;
   uint32_t *tmap_offset; /* offset table for each tmap */
 } ATTRIBUTE_PACKED vts_tmapt_t;
-#define VTS_TMAPT_SIZE 8
+#define VTS_TMAPT_SIZE 8U
 
 
 #if PRAGMA_PACK
--- a/dvdread/nav_print.c	Wed Aug 15 10:34:53 2007 +0000
+++ b/dvdread/nav_print.c	Wed Aug 15 11:47:22 2007 +0000
@@ -26,10 +26,16 @@
 #include "config.h"
 
 #include <stdio.h>
+
+#if defined(HAVE_INTTYPES_H)
 #include <inttypes.h>
+#elif defined(HAVE_STDINT_H)
+#include <stdint.h>
+#endif
 
 #include "nav_types.h"
 #include "nav_print.h"
+#include "cmd_print.h"
 #include "dvdread_internal.h"
 
 static void print_time(dvd_time_t *dtime) {
@@ -167,7 +173,7 @@
 	printf("left %d, ", btni->left);
 	printf("right %d\n", btni->right);
 	
-	// ifoPrint_COMMAND(&btni->cmd);
+        cmdPrint_CMD(0, &btni->cmd);
 	printf("\n");
       }
     }
--- a/dvdread/nav_read.c	Wed Aug 15 10:34:53 2007 +0000
+++ b/dvdread/nav_read.c	Wed Aug 15 11:47:22 2007 +0000
@@ -20,7 +20,11 @@
 
 #include <stdio.h>
 #include <string.h>
+#if defined(HAVE_INTTYPES_H)
 #include <inttypes.h>
+#elif defined(HAVE_STDINT_H)
+#include <stdint.h>
+#endif
 
 #include "bswap.h"
 #include "nav_types.h"
--- a/dvdread/nav_types.h	Wed Aug 15 10:34:53 2007 +0000
+++ b/dvdread/nav_types.h	Wed Aug 15 11:47:22 2007 +0000
@@ -29,9 +29,8 @@
  * USA
  */
 
-#include <inttypes.h>
 #include <dvdread/ifo_types.h> /* only dvd_time_t, vm_cmd_t and user_ops_t */
-
+/* If it's ever removed add a uintX_t test. */
 
 #undef ATTRIBUTE_PACKED
 #undef PRAGMA_PACK_BEGIN 
--- a/stream/stream_dvd_common.c	Wed Aug 15 10:34:53 2007 +0000
+++ b/stream/stream_dvd_common.c	Wed Aug 15 11:47:22 2007 +0000
@@ -1,3 +1,4 @@
+#include <inttypes.h>
 #include <dvdread/ifo_types.h>
 #include "stream_dvd_common.h"