[libdvdnav-devel] [Git][videolan/libdvdread][master] 5 commits: ifo_read: refactor and fix BUP fallback

Jean-Baptiste Kempf gitlab at videolan.org
Sun Mar 1 12:23:58 CET 2020



Jean-Baptiste Kempf pushed to branch master at VideoLAN / libdvdread


Commits:
89a5fce5 by Francois Cartegnie at 2020-02-24T16:18:51+01:00
ifo_read: refactor and fix BUP fallback

- - - - -
8ca9828e by Francois Cartegnie at 2020-02-24T16:18:51+01:00
handle VTSI fallback

- - - - -
18b176cb by Francois Cartegnie at 2020-02-24T16:18:51+01:00
handle VMGI fallback

- - - - -
1a01c64c by Francois Cartegnie at 2020-02-24T16:18:51+01:00
Change dvd_reader_t for a real global context

dvd_reader_t is only accessible by dvd_reader.c

- - - - -
6c463b78 by Francois Cartegnie at 2020-02-24T16:18:51+01:00
flag broken IFO to load BUP instead

Fallback isn't done for VMGI. We need to store
earlier IFO fallback state.

Fixes playback with crafted/corrupted IFO

- - - - -


6 changed files:

- src/dvd_reader.c
- src/dvd_udf.c
- src/dvdread/dvd_reader.h
- src/dvdread/dvd_udf.h
- src/dvdread_internal.h
- src/ifo_read.c


Changes:

=====================================
src/dvd_reader.c
=====================================
@@ -79,7 +79,7 @@ static inline int _private_gettimeofday( struct timeval *tv, void *tz )
 
 #define DEFAULT_UDF_CACHE_LEVEL 1
 
-struct dvd_reader_s {
+struct dvd_reader_device_s {
   /* Basic information. */
   int isImageFile;
 
@@ -103,7 +103,7 @@ struct dvd_reader_s {
 
 struct dvd_file_s {
   /* Basic information. */
-  dvd_reader_t *dvd;
+  dvd_reader_t *ctx;
 
   /* Hack for selecting the right css title. */
   int css_title;
@@ -129,9 +129,9 @@ struct dvd_file_s {
  * level = 0 (no caching)
  * level = 1 (caching filesystem info)
  */
-int DVDUDFCacheLevel(dvd_reader_t *device, int level)
+int DVDUDFCacheLevel(dvd_reader_t *reader, int level)
 {
-  struct dvd_reader_s *dev = (struct dvd_reader_s *)device;
+  dvd_reader_device_t *dev = reader->rd;
 
   if(level > 0) {
     level = 1;
@@ -144,16 +144,16 @@ int DVDUDFCacheLevel(dvd_reader_t *device, int level)
   return level;
 }
 
-void *GetUDFCacheHandle(dvd_reader_t *device)
+void *GetUDFCacheHandle(dvd_reader_t *reader)
 {
-  struct dvd_reader_s *dev = (struct dvd_reader_s *)device;
+  dvd_reader_device_t *dev = reader->rd;
 
   return dev->udfcache;
 }
 
-void SetUDFCacheHandle(dvd_reader_t *device, void *cache)
+void SetUDFCacheHandle(dvd_reader_t *reader, void *cache)
 {
-  struct dvd_reader_s *dev = (struct dvd_reader_s *)device;
+  dvd_reader_device_t *dev = reader->rd;
 
   dev->udfcache = cache;
 }
@@ -161,8 +161,9 @@ void SetUDFCacheHandle(dvd_reader_t *device, void *cache)
 
 
 /* Loop over all titles and call dvdcss_title to crack the keys. */
-static int initAllCSSKeys( dvd_reader_t *dvd )
+static int initAllCSSKeys( dvd_reader_t *ctx )
 {
+  dvd_reader_device_t *dvd = ctx->rd;
   struct timeval all_s, all_e;
   struct timeval t_s, t_e;
   char filename[ MAX_UDF_FILE_NAME_LEN ];
@@ -186,7 +187,7 @@ static int initAllCSSKeys( dvd_reader_t *dvd )
     } else {
       sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, 0 );
     }
-    start = UDFFindFile( dvd, filename, &len );
+    start = UDFFindFile( ctx, filename, &len );
     if( start != 0 && len != 0 ) {
       /* Perform CSS key cracking for this title. */
       fprintf( stderr, "libdvdread: Get key for %s at 0x%08x\n",
@@ -203,7 +204,7 @@ static int initAllCSSKeys( dvd_reader_t *dvd )
 
     gettimeofday( &t_s, NULL );
     sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, 1 );
-    start = UDFFindFile( dvd, filename, &len );
+    start = UDFFindFile( ctx, filename, &len );
     if( start == 0 || len == 0 ) break;
 
     /* Perform CSS key cracking for this title. */
@@ -231,12 +232,12 @@ static int initAllCSSKeys( dvd_reader_t *dvd )
 /**
  * Open a DVD image or block device file or use stream_cb functions.
  */
-static dvd_reader_t *DVDOpenImageFile( const char *location,
+static dvd_reader_device_t *DVDOpenImageFile( const char *location,
                                        void *stream,
                                        dvd_reader_stream_cb *stream_cb,
                                        int have_css )
 {
-  dvd_reader_t *dvd;
+  dvd_reader_device_t *dvd;
   dvd_input_t dev;
 
   dev = dvdinput_open( location, stream, stream_cb );
@@ -245,7 +246,7 @@ static dvd_reader_t *DVDOpenImageFile( const char *location,
     return NULL;
   }
 
-  dvd = calloc( 1, sizeof( dvd_reader_t ) );
+  dvd = calloc( 1, sizeof( dvd_reader_device_t ) );
   if( !dvd ) {
     dvdinput_close(dev);
     return NULL;
@@ -266,11 +267,11 @@ static dvd_reader_t *DVDOpenImageFile( const char *location,
   return dvd;
 }
 
-static dvd_reader_t *DVDOpenPath( const char *path_root )
+static dvd_reader_device_t *DVDOpenPath( const char *path_root )
 {
-  dvd_reader_t *dvd;
+  dvd_reader_device_t *dvd;
 
-  dvd = calloc( 1, sizeof( dvd_reader_t ) );
+  dvd = calloc( 1, sizeof( dvd_reader_device_t ) );
   if( !dvd ) return NULL;
   dvd->path_root = strdup( path_root );
   if(!dvd->path_root) {
@@ -342,9 +343,11 @@ static dvd_reader_t *DVDOpenCommon( const char *ppath,
 {
   struct stat fileinfo;
   int ret, have_css, retval, cdir = -1;
-  dvd_reader_t *ret_val = NULL;
   char *dev_name = NULL;
   char *path = NULL, *new_path = NULL, *path_copy = NULL;
+  dvd_reader_t *ctx = calloc(1, sizeof(*ctx));
+  if(!ctx)
+      return NULL;
 
 #if defined(_WIN32) || defined(__OS2__)
       int len;
@@ -354,7 +357,13 @@ static dvd_reader_t *DVDOpenCommon( const char *ppath,
   if( stream != NULL && stream_cb != NULL )
   {
     have_css = dvdinput_setup();
-    return DVDOpenImageFile( NULL, stream, stream_cb, have_css );
+    ctx->rd = DVDOpenImageFile( NULL, stream, stream_cb, have_css );
+    if(!ctx->rd)
+    {
+        free(ctx);
+        return NULL;
+    }
+    return ctx;
   }
 
   if( ppath == NULL )
@@ -384,9 +393,14 @@ static dvd_reader_t *DVDOpenCommon( const char *ppath,
 
     /* maybe "host:port" url? try opening it with acCeSS library */
     if( strchr(path,':') ) {
-      ret_val = DVDOpenImageFile( path, NULL, NULL, have_css );
+      ctx->rd = DVDOpenImageFile( path, NULL, NULL, have_css );
       free(path);
-      return ret_val;
+      if(!ctx->rd)
+      {
+          free(ctx);
+          return NULL;
+      }
+      return ctx;
     }
 
     /* If we can't stat the file, give up */
@@ -403,7 +417,6 @@ static dvd_reader_t *DVDOpenCommon( const char *ppath,
     /**
      * Block devices and regular files are assumed to be DVD-Video images.
      */
-    dvd_reader_t *dvd = NULL;
 #if defined(__sun)
     dev_name = sun_block2char( path );
 #elif defined(SYS_BSD)
@@ -413,12 +426,16 @@ static dvd_reader_t *DVDOpenCommon( const char *ppath,
 #endif
     if(!dev_name)
         goto DVDOpen_error;
-    dvd = DVDOpenImageFile( dev_name, NULL, NULL, have_css );
+    ctx->rd = DVDOpenImageFile( dev_name, NULL, NULL, have_css );
     free( dev_name );
     free(path);
-    return dvd;
+    if(!ctx->rd)
+    {
+        free(ctx);
+        return NULL;
+    }
+    return ctx;
   } else if( S_ISDIR( fileinfo.st_mode ) ) {
-    dvd_reader_t *auth_drive = 0;
 #if defined(SYS_BSD)
     struct fstab* fe;
 #elif defined(__sun) || defined(__linux__)
@@ -505,7 +522,7 @@ static dvd_reader_t *DVDOpenCommon( const char *ppath,
                         " mounted on %s for CSS authentication\n",
                         dev_name,
                         s[i].f_mntonname);
-                auth_drive = DVDOpenImageFile( dev_name, NULL, NULL, have_css );
+                ctx->rd = DVDOpenImageFile( dev_name, NULL, NULL, have_css );
                 break;
             }
         }
@@ -518,7 +535,7 @@ static dvd_reader_t *DVDOpenCommon( const char *ppath,
                " mounted on %s for CSS authentication\n",
                dev_name,
                fe->fs_file );
-      auth_drive = DVDOpenImageFile( dev_name, NULL, NULL, have_css );
+      ctx->rd = DVDOpenImageFile( dev_name, NULL, NULL, have_css );
     }
 #elif defined(__sun)
     mntfile = fopen( MNTTAB, "r" );
@@ -534,7 +551,7 @@ static dvd_reader_t *DVDOpenCommon( const char *ppath,
                    " mounted on %s for CSS authentication\n",
                    dev_name,
                    mp.mnt_mountp );
-          auth_drive = DVDOpenImageFile( dev_name, NULL, NULL, have_css );
+          ctx->rd = DVDOpenImageFile( dev_name, NULL, NULL, have_css );
           break;
         }
       }
@@ -558,7 +575,7 @@ static dvd_reader_t *DVDOpenCommon( const char *ppath,
                    " mounted on %s for CSS authentication\n",
                    me->mnt_fsname,
                    me->mnt_dir );
-          auth_drive = DVDOpenImageFile( me->mnt_fsname, NULL, NULL, have_css );
+          ctx->rd = DVDOpenImageFile( me->mnt_fsname, NULL, NULL, have_css );
           dev_name = strdup(me->mnt_fsname);
           break;
         }
@@ -572,18 +589,18 @@ static dvd_reader_t *DVDOpenCommon( const char *ppath,
         ( !path[2] ||
           ((path[2] == '\\' || path[2] == '/') && !path[3])))
 #endif
-    auth_drive = DVDOpenImageFile( path, NULL, NULL, have_css );
+    ctx->rd = DVDOpenImageFile( path, NULL, NULL, have_css );
 #endif
 
 #if !defined(_WIN32) && !defined(__OS2__)
     if( !dev_name ) {
       fprintf( stderr, "libdvdread: Couldn't find device name.\n" );
-    } else if( !auth_drive ) {
+    } else if( !ctx->rd ) {
       fprintf( stderr, "libdvdread: Device %s inaccessible, "
                "CSS authentication not available.\n", dev_name );
     }
 #else
-    if( !auth_drive ) {
+    if( !ctx->rd ) {
         fprintf( stderr, "libdvdread: Device %s inaccessible, "
                  "CSS authentication not available.\n", path );
     }
@@ -597,16 +614,22 @@ static dvd_reader_t *DVDOpenCommon( const char *ppath,
     /**
      * If we've opened a drive, just use that.
      */
-    if( auth_drive ) {
-      free(path);
-      return auth_drive;
+    if(ctx->rd)
+    {
+        free(path);
+        return ctx;
     }
     /**
      * Otherwise, we now try to open the directory tree instead.
      */
-    ret_val = DVDOpenPath( path );
-      free( path );
-      return ret_val;
+    ctx->rd = DVDOpenPath( path );
+    free( path );
+    if(!ctx->rd)
+    {
+        free(ctx);
+        return NULL;
+    }
+    return ctx;
   }
 
 DVDOpen_error:
@@ -634,9 +657,10 @@ dvd_reader_t *DVDOpenStream( void *stream,
 void DVDClose( dvd_reader_t *dvd )
 {
   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->rd->dev ) dvdinput_close( dvd->rd->dev );
+    if( dvd->rd->path_root ) free( dvd->rd->path_root );
+    if( dvd->rd->udfcache ) FreeUDFCache( dvd->rd->udfcache );
+    free( dvd->rd );
     free( dvd );
   }
 }
@@ -644,13 +668,13 @@ void DVDClose( dvd_reader_t *dvd )
 /**
  * Open an unencrypted file on a DVD image file.
  */
-static dvd_file_t *DVDOpenFileUDF( dvd_reader_t *dvd, const char *filename,
+static dvd_file_t *DVDOpenFileUDF( dvd_reader_t *ctx, const char *filename,
                                    int do_cache )
 {
   uint32_t start, len;
   dvd_file_t *dvd_file;
 
-  start = UDFFindFile( dvd, filename, &len );
+  start = UDFFindFile( ctx, filename, &len );
   if( !start ) {
     fprintf( stderr, "libdvdread:DVDOpenFileUDF:UDFFindFile %s failed\n", filename );
     return NULL;
@@ -661,7 +685,7 @@ static dvd_file_t *DVDOpenFileUDF( dvd_reader_t *dvd, const char *filename,
     fprintf( stderr, "libdvdread:DVDOpenFileUDF:malloc failed\n" );
     return NULL;
   }
-  dvd_file->dvd = dvd;
+  dvd_file->ctx = ctx;
   dvd_file->lb_start = start;
   dvd_file->filesize = len / DVD_VIDEO_LB_LEN;
 
@@ -674,7 +698,7 @@ static dvd_file_t *DVDOpenFileUDF( dvd_reader_t *dvd, const char *filename,
     if( !dvd_file->cache )
         return dvd_file;
 
-    ret = InternalUDFReadBlocksRaw( dvd, dvd_file->lb_start,
+    ret = InternalUDFReadBlocksRaw( ctx, dvd_file->lb_start,
                                     dvd_file->filesize, dvd_file->cache,
                                     DVDINPUT_NOFLAGS );
     if( ret != dvd_file->filesize ) {
@@ -725,16 +749,16 @@ static int findDVDFile( dvd_reader_t *dvd, const char *file, char *filename )
     nodirfile = file;
   }
 
-  ret = findDirFile( dvd->path_root, nodirfile, filename );
+  ret = findDirFile( dvd->rd->path_root, nodirfile, filename );
   if( ret < 0 ) {
     char video_path[ PATH_MAX + 1 ];
 
     /* Try also with adding the path, just in case. */
-    sprintf( video_path, "%s/VIDEO_TS/", dvd->path_root );
+    sprintf( video_path, "%s/VIDEO_TS/", dvd->rd->path_root );
     ret = findDirFile( video_path, nodirfile, filename );
     if( ret < 0 ) {
       /* Try with the path, but in lower case. */
-      sprintf( video_path, "%s/video_ts/", dvd->path_root );
+      sprintf( video_path, "%s/video_ts/", dvd->rd->path_root );
       ret = findDirFile( video_path, nodirfile, filename );
       if( ret < 0 ) {
         return 0;
@@ -748,7 +772,7 @@ static int findDVDFile( dvd_reader_t *dvd, const char *file, char *filename )
 /**
  * Open an unencrypted file from a DVD directory tree.
  */
-static dvd_file_t *DVDOpenFilePath( dvd_reader_t *dvd, const char *filename )
+static dvd_file_t *DVDOpenFilePath( dvd_reader_t *ctx, const char *filename )
 {
   char full_path[ PATH_MAX + 1 ];
   dvd_file_t *dvd_file;
@@ -756,7 +780,7 @@ static dvd_file_t *DVDOpenFilePath( dvd_reader_t *dvd, const char *filename )
   dvd_input_t dev;
 
   /* Get the full path of the file. */
-  if( !findDVDFile( dvd, filename, full_path ) ) {
+  if( !findDVDFile( ctx, filename, full_path ) ) {
     fprintf( stderr, "libdvdread:DVDOpenFilePath:findDVDFile %s failed\n", filename );
     return NULL;
   }
@@ -773,7 +797,7 @@ static dvd_file_t *DVDOpenFilePath( dvd_reader_t *dvd, const char *filename )
     dvdinput_close(dev);
     return NULL;
   }
-  dvd_file->dvd = dvd;
+  dvd_file->ctx = ctx;
 
   if( stat( full_path, &fileinfo ) < 0 ) {
     fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename );
@@ -788,7 +812,7 @@ static dvd_file_t *DVDOpenFilePath( dvd_reader_t *dvd, const char *filename )
   return dvd_file;
 }
 
-static dvd_file_t *DVDOpenVOBUDF( dvd_reader_t *dvd, int title, int menu )
+static dvd_file_t *DVDOpenVOBUDF( dvd_reader_t *ctx, int title, int menu )
 {
   char filename[ MAX_UDF_FILE_NAME_LEN ];
   uint32_t start, len;
@@ -799,12 +823,12 @@ static dvd_file_t *DVDOpenVOBUDF( dvd_reader_t *dvd, int title, int menu )
   } else {
     sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, menu ? 0 : 1 );
   }
-  start = UDFFindFile( dvd, filename, &len );
+  start = UDFFindFile( ctx, filename, &len );
   if( start == 0 ) return NULL;
 
   dvd_file = calloc( 1, sizeof( dvd_file_t ) );
   if( !dvd_file ) return NULL;
-  dvd_file->dvd = dvd;
+  dvd_file->ctx = ctx;
   /*Hack*/ dvd_file->css_title = title << 1 | menu;
   dvd_file->lb_start = start;
   dvd_file->filesize = len / DVD_VIDEO_LB_LEN;
@@ -815,14 +839,14 @@ static dvd_file_t *DVDOpenVOBUDF( dvd_reader_t *dvd, int title, int menu )
 
     for( cur = 2; cur < 10; cur++ ) {
       sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, cur );
-      if( !UDFFindFile( dvd, filename, &len ) ) break;
+      if( !UDFFindFile( ctx, filename, &len ) ) break;
       dvd_file->filesize += len / DVD_VIDEO_LB_LEN;
     }
   }
 
-  if( dvd->css_state == 1 /* Need key init */ ) {
-    initAllCSSKeys( dvd );
-    dvd->css_state = 2;
+  if( ctx->rd->css_state == 1 /* Need key init */ ) {
+    initAllCSSKeys( ctx );
+    ctx->rd->css_state = 2;
   }
   /*
   if( dvdinput_title( dvd_file->dvd->dev, (int)start ) < 0 ) {
@@ -834,7 +858,7 @@ static dvd_file_t *DVDOpenVOBUDF( dvd_reader_t *dvd, int title, int menu )
   return dvd_file;
 }
 
-static dvd_file_t *DVDOpenVOBPath( dvd_reader_t *dvd, int title, int menu )
+static dvd_file_t *DVDOpenVOBPath( dvd_reader_t *ctx, int title, int menu )
 {
   char filename[ MAX_UDF_FILE_NAME_LEN ];
   char full_path[ PATH_MAX + 1 ];
@@ -843,7 +867,7 @@ static dvd_file_t *DVDOpenVOBPath( dvd_reader_t *dvd, int title, int menu )
 
   dvd_file = calloc( 1, sizeof( dvd_file_t ) );
   if( !dvd_file ) return NULL;
-  dvd_file->dvd = dvd;
+  dvd_file->ctx = ctx;
   /*Hack*/ dvd_file->css_title = title << 1 | menu;
 
   if( menu ) {
@@ -854,7 +878,7 @@ static dvd_file_t *DVDOpenVOBPath( dvd_reader_t *dvd, int title, int menu )
     } else {
       sprintf( filename, "VTS_%02i_0.VOB", title );
     }
-    if( !findDVDFile( dvd, filename, full_path ) ) {
+    if( !findDVDFile( ctx, filename, full_path ) ) {
       free( dvd_file );
       return NULL;
     }
@@ -882,7 +906,7 @@ static dvd_file_t *DVDOpenVOBPath( dvd_reader_t *dvd, int title, int menu )
     for( i = 0; i < TITLES_MAX; ++i ) {
 
       sprintf( filename, "VTS_%02i_%i.VOB", title, i + 1 );
-      if( !findDVDFile( dvd, filename, full_path ) ) {
+      if( !findDVDFile( ctx, filename, full_path ) ) {
         break;
       }
 
@@ -905,9 +929,10 @@ static dvd_file_t *DVDOpenVOBPath( dvd_reader_t *dvd, int title, int menu )
   return dvd_file;
 }
 
-dvd_file_t *DVDOpenFile( dvd_reader_t *dvd, int titlenum,
+dvd_file_t *DVDOpenFile( dvd_reader_t *ctx, int titlenum,
                          dvd_read_domain_t domain )
 {
+  dvd_reader_device_t *dvd = ctx->rd;
   char filename[ MAX_UDF_FILE_NAME_LEN ];
   int do_cache = 0;
 
@@ -934,17 +959,17 @@ dvd_file_t *DVDOpenFile( dvd_reader_t *dvd, int titlenum,
     break;
   case DVD_READ_MENU_VOBS:
     if( dvd->isImageFile ) {
-      return DVDOpenVOBUDF( dvd, titlenum, 1 );
+      return DVDOpenVOBUDF( ctx, titlenum, 1 );
     } else {
-      return DVDOpenVOBPath( dvd, titlenum, 1 );
+      return DVDOpenVOBPath( ctx, titlenum, 1 );
     }
     break;
   case DVD_READ_TITLE_VOBS:
     if( titlenum == 0 ) return NULL;
     if( dvd->isImageFile ) {
-      return DVDOpenVOBUDF( dvd, titlenum, 0 );
+      return DVDOpenVOBUDF( ctx, titlenum, 0 );
     } else {
-      return DVDOpenVOBPath( dvd, titlenum, 0 );
+      return DVDOpenVOBPath( ctx, titlenum, 0 );
     }
     break;
   default:
@@ -953,16 +978,17 @@ dvd_file_t *DVDOpenFile( dvd_reader_t *dvd, int titlenum,
   }
 
   if( dvd->isImageFile ) {
-    return DVDOpenFileUDF( dvd, filename, do_cache );
+    return DVDOpenFileUDF( ctx, filename, do_cache );
   } else {
-    return DVDOpenFilePath( dvd, filename );
+    return DVDOpenFilePath( ctx, filename );
   }
 }
 
 void DVDCloseFile( dvd_file_t *dvd_file )
 {
-  if( dvd_file && dvd_file->dvd ) {
-    if( !dvd_file->dvd->isImageFile ) {
+  dvd_reader_device_t *dvd = dvd_file->ctx->rd;
+  if( dvd_file && dvd ) {
+    if( !dvd->isImageFile ) {
       int i;
 
       for( i = 0; i < TITLES_MAX; ++i ) {
@@ -1078,9 +1104,10 @@ static int DVDFileStatVOBPath( dvd_reader_t *dvd, int title,
 }
 
 
-int DVDFileStat( dvd_reader_t *dvd, int titlenum,
+int DVDFileStat( dvd_reader_t *reader, int titlenum,
                  dvd_read_domain_t domain, dvd_stat_t *statbuf )
 {
+  dvd_reader_device_t *dvd = reader->rd;
   char filename[ MAX_UDF_FILE_NAME_LEN ];
   struct stat fileinfo;
   uint32_t size;
@@ -1108,9 +1135,9 @@ int DVDFileStat( dvd_reader_t *dvd, int titlenum,
     break;
   case DVD_READ_MENU_VOBS:
     if( dvd->isImageFile )
-      return DVDFileStatVOBUDF( dvd, titlenum, 1, statbuf );
+      return DVDFileStatVOBUDF( reader, titlenum, 1, statbuf );
     else
-      return DVDFileStatVOBPath( dvd, titlenum, 1, statbuf );
+      return DVDFileStatVOBPath( reader, titlenum, 1, statbuf );
 
     break;
   case DVD_READ_TITLE_VOBS:
@@ -1118,9 +1145,9 @@ int DVDFileStat( dvd_reader_t *dvd, int titlenum,
       return -1;
 
     if( dvd->isImageFile )
-      return DVDFileStatVOBUDF( dvd, titlenum, 0, statbuf );
+      return DVDFileStatVOBUDF( reader, titlenum, 0, statbuf );
     else
-      return DVDFileStatVOBPath( dvd, titlenum, 0, statbuf );
+      return DVDFileStatVOBPath( reader, titlenum, 0, statbuf );
 
     break;
   default:
@@ -1130,7 +1157,7 @@ int DVDFileStat( dvd_reader_t *dvd, int titlenum,
   }
 
   if( dvd->isImageFile ) {
-    if( UDFFindFile( dvd, filename, &size ) ) {
+    if( UDFFindFile( reader, filename, &size ) ) {
       statbuf->size = size;
       statbuf->nr_parts = 1;
       statbuf->parts_size[ 0 ] = size;
@@ -1139,7 +1166,7 @@ int DVDFileStat( dvd_reader_t *dvd, int titlenum,
   } else {
     char full_path[ PATH_MAX + 1 ];
 
-    if( findDVDFile( dvd, filename, full_path ) ) {
+    if( findDVDFile( reader, filename, full_path ) ) {
       if( stat( full_path, &fileinfo ) < 0 )
         fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename );
       else {
@@ -1154,24 +1181,24 @@ int DVDFileStat( dvd_reader_t *dvd, int titlenum,
 }
 
 /* Internal, but used from dvd_udf.c */
-int InternalUDFReadBlocksRaw( const dvd_reader_t *device, uint32_t lb_number,
+int InternalUDFReadBlocksRaw( const dvd_reader_t *ctx, uint32_t lb_number,
                       size_t block_count, unsigned char *data,
                       int encrypted )
 {
   int ret;
 
-  if( !device->dev ) {
+  if( !ctx->rd->dev ) {
     fprintf( stderr, "libdvdread: Fatal error in block read.\n" );
     return -1;
   }
 
-  ret = dvdinput_seek( device->dev, (int) lb_number );
+  ret = dvdinput_seek( ctx->rd->dev, (int) lb_number );
   if( ret != (int) lb_number ) {
     fprintf( stderr, "libdvdread: Can't seek to block %u\n", lb_number );
     return ret;
   }
 
-  ret = dvdinput_read( device->dev, (char *) data,
+  ret = dvdinput_read( ctx->rd->dev, (char *) data,
                        (int) block_count, encrypted );
   return ret;
 }
@@ -1202,7 +1229,7 @@ static int DVDReadBlocksUDF( const dvd_file_t *dvd_file, uint32_t offset,
     return block_count;
   } else {
     /* use dvdinput access */
-    return InternalUDFReadBlocksRaw( dvd_file->dvd, dvd_file->lb_start + offset,
+    return InternalUDFReadBlocksRaw( dvd_file->ctx, dvd_file->lb_start + offset,
                              block_count, data, encrypted );
   }
 }
@@ -1285,6 +1312,8 @@ static int DVDReadBlocksPath( const dvd_file_t *dvd_file, unsigned int offset,
 ssize_t DVDReadBlocks( dvd_file_t *dvd_file, int offset,
                        size_t block_count, unsigned char *data )
 {
+  dvd_reader_t *ctx = dvd_file->ctx;
+  dvd_reader_device_t *dvd = ctx->rd;
   int ret;
 
   /* Check arguments. */
@@ -1292,10 +1321,10 @@ ssize_t DVDReadBlocks( dvd_file_t *dvd_file, int offset,
     return -1;
 
   /* Hack, and it will still fail for multiple opens in a threaded app ! */
-  if( dvd_file->dvd->css_title != dvd_file->css_title ) {
-    dvd_file->dvd->css_title = dvd_file->css_title;
-    if( dvd_file->dvd->isImageFile ) {
-      dvdinput_title( dvd_file->dvd->dev, (int)dvd_file->lb_start );
+  if( dvd->css_title != dvd_file->css_title ) {
+      dvd->css_title = dvd_file->css_title;
+    if( dvd->isImageFile ) {
+      dvdinput_title( dvd->dev, (int)dvd_file->lb_start );
     }
     /* Here each vobu has it's own dvdcss handle, so no need to update
     else {
@@ -1303,7 +1332,7 @@ ssize_t DVDReadBlocks( dvd_file_t *dvd_file, int offset,
     }*/
   }
 
-  if( dvd_file->dvd->isImageFile ) {
+  if( dvd->isImageFile ) {
     ret = DVDReadBlocksUDF( dvd_file, (uint32_t)offset,
                             block_count, data, DVDINPUT_READ_DECRYPT );
   } else {
@@ -1329,11 +1358,13 @@ int32_t DVDFileSeek( dvd_file_t *dvd_file, int32_t offset )
 
 int DVDFileSeekForce(dvd_file_t *dvd_file, int offset, int force_size)
 {
+  dvd_reader_t *ctx = dvd_file->ctx;
+  dvd_reader_device_t *dvd = ctx->rd;
   /* Check arguments. */
   if( dvd_file == NULL || offset <= 0 )
       return -1;
 
-  if( dvd_file->dvd->isImageFile ) {
+  if( dvd->isImageFile ) {
     if( force_size < 0 )
       force_size = (offset - 1) / DVD_VIDEO_LB_LEN + 1;
     if( dvd_file->filesize < force_size ) {
@@ -1353,6 +1384,8 @@ int DVDFileSeekForce(dvd_file_t *dvd_file, int offset, int force_size)
 
 ssize_t DVDReadBytes( dvd_file_t *dvd_file, void *data, size_t byte_size )
 {
+  dvd_reader_t *ctx = dvd_file->ctx;
+  dvd_reader_device_t *dvd = ctx->rd;
   unsigned char *secbuf_base, *secbuf;
   unsigned int numsec, seek_sector, seek_byte;
   int ret;
@@ -1375,7 +1408,7 @@ ssize_t DVDReadBytes( dvd_file_t *dvd_file, void *data, size_t byte_size )
   }
   secbuf = (unsigned char *)(((uintptr_t)secbuf_base & ~((uintptr_t)2047)) + 2048);
 
-  if( dvd_file->dvd->isImageFile ) {
+  if( dvd->isImageFile ) {
     ret = DVDReadBlocksUDF( dvd_file, (uint32_t) seek_sector,
                             (size_t) numsec, secbuf, DVDINPUT_NOFLAGS );
   } else {
@@ -1473,10 +1506,11 @@ int DVDDiscID( dvd_reader_t *dvd, unsigned char *discid )
 }
 
 
-int DVDISOVolumeInfo( dvd_reader_t *dvd,
+int DVDISOVolumeInfo( dvd_reader_t *ctx,
                       char *volid, unsigned int volid_size,
                       unsigned char *volsetid, unsigned int volsetid_size )
 {
+  dvd_reader_device_t *dvd = ctx->rd;
   unsigned char *buffer, *buffer_base;
   int ret;
 
@@ -1499,7 +1533,7 @@ int DVDISOVolumeInfo( dvd_reader_t *dvd,
 
   buffer = (unsigned char *)(((uintptr_t)buffer_base & ~((uintptr_t)2047)) + 2048);
 
-  ret = InternalUDFReadBlocksRaw( dvd, 16, 1, buffer, 0 );
+  ret = InternalUDFReadBlocksRaw( ctx, 16, 1, buffer, 0 );
   if( ret != 1 ) {
     fprintf( stderr, "libdvdread: DVDISOVolumeInfo, failed to "
              "read ISO9660 Primary Volume Descriptor!\n" );
@@ -1534,28 +1568,28 @@ int DVDISOVolumeInfo( dvd_reader_t *dvd,
 }
 
 
-int DVDUDFVolumeInfo( dvd_reader_t *dvd,
+int DVDUDFVolumeInfo( dvd_reader_t *ctx,
                       char *volid, unsigned int volid_size,
                       unsigned char *volsetid, unsigned int volsetid_size )
 {
   int ret;
   /* Check arguments. */
-  if( dvd == NULL )
+  if( ctx == NULL || ctx->rd == NULL )
     return -1;
 
-  if( dvd->dev == NULL ) {
+  if( ctx->rd->dev == NULL ) {
     /* No block access, so no UDF VolumeSet Identifier */
     return -1;
   }
 
   if( (volid != NULL) && (volid_size > 0) ) {
-    ret = UDFGetVolumeIdentifier(dvd, volid, volid_size);
+    ret = UDFGetVolumeIdentifier(ctx, volid, volid_size);
     if(!ret) {
       return -1;
     }
   }
   if( (volsetid != NULL) && (volsetid_size > 0) ) {
-    ret =  UDFGetVolumeSetIdentifier(dvd, volsetid, volsetid_size);
+    ret =  UDFGetVolumeSetIdentifier(ctx, volsetid, volsetid_size);
     if(!ret) {
       return -1;
     }


=====================================
src/dvd_udf.c
=====================================
@@ -44,7 +44,7 @@
 #include "dvdread/dvd_udf.h"
 
 /* It's required to either fail or deliver all the blocks asked for. */
-static int DVDReadLBUDF( dvd_reader_t *device, uint32_t lb_number,
+static int DVDReadLBUDF( dvd_reader_t *ctx, uint32_t lb_number,
                          size_t block_count, unsigned char *data,
                          int encrypted )
 {
@@ -53,7 +53,7 @@ static int DVDReadLBUDF( dvd_reader_t *device, uint32_t lb_number,
   while(count > 0) {
     int ret;
 
-    ret = InternalUDFReadBlocksRaw(device, lb_number, count, data + DVD_VIDEO_LB_LEN * (block_count - count), encrypted);
+    ret = InternalUDFReadBlocksRaw(ctx, lb_number, count, data + DVD_VIDEO_LB_LEN * (block_count - count), encrypted);
 
     if(ret <= 0) {
       /* One of the reads failed or nothing more to read, too bad.
@@ -156,16 +156,16 @@ void FreeUDFCache(void *cache)
 }
 
 
-static int GetUDFCache(dvd_reader_t *device, UDFCacheType type,
+static int GetUDFCache(dvd_reader_t *ctx, UDFCacheType type,
                        uint32_t nr, void *data)
 {
   int n;
   struct udf_cache *c;
 
-  if(DVDUDFCacheLevel(device, -1) <= 0)
+  if(DVDUDFCacheLevel(ctx, -1) <= 0)
     return 0;
 
-  c = (struct udf_cache *)GetUDFCacheHandle(device);
+  c = (struct udf_cache *)GetUDFCacheHandle(ctx);
 
   if(c == NULL)
     return 0;
@@ -218,24 +218,24 @@ static int GetUDFCache(dvd_reader_t *device, UDFCacheType type,
   return 0;
 }
 
-static int SetUDFCache(dvd_reader_t *device, UDFCacheType type,
+static int SetUDFCache(dvd_reader_t *ctx, UDFCacheType type,
                        uint32_t nr, void *data)
 {
   int n;
   struct udf_cache *c;
   void *tmp;
 
-  if(DVDUDFCacheLevel(device, -1) <= 0)
+  if(DVDUDFCacheLevel(ctx, -1) <= 0)
     return 0;
 
-  c = (struct udf_cache *)GetUDFCacheHandle(device);
+  c = (struct udf_cache *)GetUDFCacheHandle(ctx);
 
   if(c == NULL) {
     c = calloc(1, sizeof(struct udf_cache));
     /* fprintf(stderr, "calloc: %d\n", sizeof(struct udf_cache)); */
     if(c == NULL)
       return 0;
-    SetUDFCacheHandle(device, c);
+    SetUDFCacheHandle(ctx, c);
   }
 
 
@@ -511,7 +511,7 @@ static int UDFFileIdentifier( uint8_t *data, uint8_t *FileCharacteristics,
  * File: Location of file the ICB is pointing to
  * return 1 on success, 0 on error;
  */
-static int UDFMapICB( dvd_reader_t *device, struct AD ICB, uint8_t *FileType,
+static int UDFMapICB( dvd_reader_t *ctx, struct AD ICB, uint8_t *FileType,
                       struct Partition *partition, struct AD *File )
 {
   uint8_t LogBlock_base[DVD_VIDEO_LB_LEN + 2048];
@@ -523,14 +523,14 @@ static int UDFMapICB( dvd_reader_t *device, struct AD ICB, uint8_t *FileType,
 
   lbnum = partition->Start + ICB.Location;
   tmpmap.lbn = lbnum;
-  if(GetUDFCache(device, MapCache, lbnum, &tmpmap)) {
+  if(GetUDFCache(ctx, MapCache, lbnum, &tmpmap)) {
     *FileType = tmpmap.filetype;
     memcpy(File, &tmpmap.file, sizeof(tmpmap.file));
     return 1;
   }
 
   do {
-    ret = DVDReadLBUDF( device, lbnum++, 1, LogBlock, 0 );
+    ret = DVDReadLBUDF( ctx, lbnum++, 1, LogBlock, 0 );
     if( ret < 0 ) {
       return ret;
     }
@@ -545,7 +545,7 @@ static int UDFMapICB( dvd_reader_t *device, struct AD ICB, uint8_t *FileType,
       UDFFileEntry( LogBlock, FileType, partition, File );
       memcpy(&tmpmap.file, File, sizeof(tmpmap.file));
       tmpmap.filetype = *FileType;
-      SetUDFCache(device, MapCache, tmpmap.lbn, &tmpmap);
+      SetUDFCache(ctx, MapCache, tmpmap.lbn, &tmpmap);
       return 1;
     };
   } while( ( lbnum <= partition->Start + ICB.Location + ( ICB.Length - 1 )
@@ -560,7 +560,7 @@ static int UDFMapICB( dvd_reader_t *device, struct AD ICB, uint8_t *FileType,
  * FileICB: Location of ICB of the found file
  * return 1 on success, 0 on error;
  */
-static int UDFScanDir( dvd_reader_t *device, struct AD Dir, char *FileName,
+static int UDFScanDir( dvd_reader_t *ctx, struct AD Dir, char *FileName,
                        struct Partition *partition, struct AD *FileICB,
                        int cache_file_info)
 {
@@ -579,18 +579,18 @@ static int UDFScanDir( dvd_reader_t *device, struct AD Dir, char *FileName,
   /* Scan dir for ICB of file */
   lbnum = partition->Start + Dir.Location;
 
-  if(DVDUDFCacheLevel(device, -1) > 0) {
+  if(DVDUDFCacheLevel(ctx, -1) > 0) {
     int found = 0;
     int in_cache = 0;
 
     /* caching */
 
-    if(!GetUDFCache(device, LBUDFCache, lbnum, &cached_dir)) {
+    if(!GetUDFCache(ctx, LBUDFCache, lbnum, &cached_dir)) {
       dir_lba = (Dir.Length + DVD_VIDEO_LB_LEN) / DVD_VIDEO_LB_LEN;
       if((cached_dir_base = malloc(dir_lba * DVD_VIDEO_LB_LEN + 2048)) == NULL)
         return 0;
       cached_dir = (uint8_t *)(((uintptr_t)cached_dir_base & ~((uintptr_t)2047)) + 2048);
-      ret = DVDReadLBUDF( device, lbnum, dir_lba, cached_dir, 0);
+      ret = DVDReadLBUDF( ctx, lbnum, dir_lba, cached_dir, 0);
       if( ret <= 0 ) {
         free(cached_dir_base);
         cached_dir_base = NULL;
@@ -607,7 +607,7 @@ static int UDFScanDir( dvd_reader_t *device, struct AD Dir, char *FileName,
         uint8_t *data[2];
         data[0] = cached_dir_base;
         data[1] = cached_dir;
-        SetUDFCache(device, LBUDFCache, lbnum, data);
+        SetUDFCache(ctx, LBUDFCache, lbnum, data);
       }
     } else
       in_cache = 1;
@@ -633,7 +633,7 @@ static int UDFScanDir( dvd_reader_t *device, struct AD Dir, char *FileName,
             memcpy(FileICB, &tmpICB, sizeof(tmpICB));
             found = 1;
           }
-          if(!UDFMapICB(device, tmpICB, &tmpFiletype, partition, &tmpFile))
+          if(!UDFMapICB(ctx, tmpICB, &tmpFiletype, partition, &tmpFile))
             return 0;
 
         } else {
@@ -653,7 +653,7 @@ static int UDFScanDir( dvd_reader_t *device, struct AD Dir, char *FileName,
     return 0;
   }
 
-  if( DVDReadLBUDF( device, lbnum, 2, directory, 0 ) <= 0 )
+  if( DVDReadLBUDF( ctx, lbnum, 2, directory, 0 ) <= 0 )
     return 0;
 
   p = 0;
@@ -662,7 +662,7 @@ static int UDFScanDir( dvd_reader_t *device, struct AD Dir, char *FileName,
       ++lbnum;
       p -= DVD_VIDEO_LB_LEN;
       Dir.Length -= DVD_VIDEO_LB_LEN;
-      if( DVDReadLBUDF( device, lbnum, 2, directory, 0 ) <= 0 ) {
+      if( DVDReadLBUDF( ctx, lbnum, 2, directory, 0 ) <= 0 ) {
         return 0;
       }
     }
@@ -681,7 +681,7 @@ static int UDFScanDir( dvd_reader_t *device, struct AD Dir, char *FileName,
 }
 
 
-static int UDFGetAVDP( dvd_reader_t *device,
+static int UDFGetAVDP( dvd_reader_t *ctx,
                        struct avdp_t *avdp)
 {
   uint8_t Anchor_base[ DVD_VIDEO_LB_LEN + 2048 ];
@@ -693,7 +693,7 @@ static int UDFGetAVDP( dvd_reader_t *device,
   struct avdp_t;
   int ret;
 
-  if(GetUDFCache(device, AVDPCache, 0, avdp))
+  if(GetUDFCache(ctx, AVDPCache, 0, avdp))
     return 1;
 
   /* Find Anchor */
@@ -702,7 +702,7 @@ static int UDFGetAVDP( dvd_reader_t *device,
   terminate = 0;
 
   for(;;) {
-    ret = DVDReadLBUDF( device, lbnum, 1, Anchor, 0 );
+    ret = DVDReadLBUDF( ctx, lbnum, 1, Anchor, 0 );
     if( ret < 0 ) {
       return ret;
     }
@@ -745,7 +745,7 @@ static int UDFGetAVDP( dvd_reader_t *device,
   avdp->rvds.location = MVDS_location;
   avdp->rvds.length = MVDS_length;
 
-  SetUDFCache(device, AVDPCache, 0, avdp);
+  SetUDFCache(ctx, AVDPCache, 0, avdp);
 
   return 1;
 }
@@ -755,7 +755,7 @@ static int UDFGetAVDP( dvd_reader_t *device,
  *   partnum: Number of the partition, starting at 0.
  *   part: structure to fill with the partition information
  */
-static int UDFFindPartition( dvd_reader_t *device, int partnum,
+static int UDFFindPartition( dvd_reader_t *ctx, int partnum,
                              struct Partition *part )
 {
   uint8_t LogBlock_base[ DVD_VIDEO_LB_LEN + 2048 ];
@@ -765,7 +765,7 @@ static int UDFFindPartition( dvd_reader_t *device, int partnum,
   int i, volvalid, ret;
   struct avdp_t avdp;
 
-  if(!UDFGetAVDP(device, &avdp))
+  if(!UDFGetAVDP(ctx, &avdp))
     return 0;
 
   /* Main volume descriptor */
@@ -781,7 +781,7 @@ static int UDFFindPartition( dvd_reader_t *device, int partnum,
     lbnum = MVDS_location;
     do {
 
-      ret = DVDReadLBUDF( device, lbnum++, 1, LogBlock, 0 );
+      ret = DVDReadLBUDF( ctx, lbnum++, 1, LogBlock, 0 );
       if( ret < 0 ) {
         return ret;
       }
@@ -820,7 +820,7 @@ static int UDFFindPartition( dvd_reader_t *device, int partnum,
   return part->valid;
 }
 
-uint32_t UDFFindFile( dvd_reader_t *device, const char *filename,
+uint32_t UDFFindFile( dvd_reader_t *ctx, const char *filename,
                       uint32_t *filesize )
 {
   uint8_t LogBlock_base[ DVD_VIDEO_LB_LEN + 2048 ];
@@ -838,16 +838,16 @@ uint32_t UDFFindFile( dvd_reader_t *device, const char *filename,
   strncat(tokenline, filename, MAX_UDF_FILE_NAME_LEN - 1);
   memset(&ICB, 0, sizeof(ICB));
 
-  if(!(GetUDFCache(device, PartitionCache, 0, &partition) &&
-       GetUDFCache(device, RootICBCache, 0, &RootICB))) {
+  if(!(GetUDFCache(ctx, PartitionCache, 0, &partition) &&
+       GetUDFCache(ctx, RootICBCache, 0, &RootICB))) {
     /* Find partition, 0 is the standard location for DVD Video.*/
-    if( !UDFFindPartition( device, 0, &partition ) ) return 0;
-    SetUDFCache(device, PartitionCache, 0, &partition);
+    if( !UDFFindPartition( ctx, 0, &partition ) ) return 0;
+    SetUDFCache(ctx, PartitionCache, 0, &partition);
 
     /* Find root dir ICB */
     lbnum = partition.Start;
     do {
-      ret = DVDReadLBUDF( device, lbnum++, 1, LogBlock, 0 );
+      ret = DVDReadLBUDF( ctx, lbnum++, 1, LogBlock, 0 );
       if( ret < 0 ) {
         return ret;
       }
@@ -869,11 +869,11 @@ uint32_t UDFFindFile( dvd_reader_t *device, const char *filename,
       return 0;
     if( RootICB.Partition != 0 )
       return 0;
-    SetUDFCache(device, RootICBCache, 0, &RootICB);
+    SetUDFCache(ctx, RootICBCache, 0, &RootICB);
   }
 
   /* Find root dir */
-  if( !UDFMapICB( device, RootICB, &filetype, &partition, &File ) )
+  if( !UDFMapICB( ctx, RootICB, &filetype, &partition, &File ) )
     return 0;
   if( filetype != 4 )
     return 0;  /* Root dir should be dir */
@@ -883,10 +883,10 @@ uint32_t UDFFindFile( dvd_reader_t *device, const char *filename,
     char *token = strtok(tokenline, "/");
 
     while( token != NULL ) {
-      if( !UDFScanDir( device, File, token, &partition, &ICB,
+      if( !UDFScanDir( ctx, File, token, &partition, &ICB,
                        cache_file_info))
         return 0;
-      if( !UDFMapICB( device, ICB, &filetype, &partition, &File ) )
+      if( !UDFMapICB( ctx, ICB, &filetype, &partition, &File ) )
         return 0;
       if(!strcmp(token, "VIDEO_TS"))
         cache_file_info = 1;
@@ -913,7 +913,7 @@ uint32_t UDFFindFile( dvd_reader_t *device, const char *filename,
  * id, tagid of descriptor
  * bufsize, size of BlockBuf (must be >= DVD_VIDEO_LB_LEN).
  */
-static int UDFGetDescriptor( dvd_reader_t *device, int id,
+static int UDFGetDescriptor( dvd_reader_t *ctx, int id,
                              uint8_t *descriptor, int bufsize)
 {
   uint32_t lbnum, MVDS_location, MVDS_length;
@@ -925,7 +925,7 @@ static int UDFGetDescriptor( dvd_reader_t *device, int id,
   if(bufsize < DVD_VIDEO_LB_LEN)
     return 0;
 
-  if(!UDFGetAVDP(device, &avdp))
+  if(!UDFGetAVDP(ctx, &avdp))
     return 0;
 
   /* Main volume descriptor */
@@ -937,7 +937,7 @@ static int UDFGetDescriptor( dvd_reader_t *device, int id,
     /* Find  Descriptor */
     lbnum = MVDS_location;
     do {
-      ret = DVDReadLBUDF( device, lbnum++, 1, descriptor, 0 );
+      ret = DVDReadLBUDF( ctx, lbnum++, 1, descriptor, 0 );
       if( ret < 0 ) {
         return ret;
       }
@@ -965,19 +965,19 @@ static int UDFGetDescriptor( dvd_reader_t *device, int id,
 }
 
 
-static int UDFGetPVD(dvd_reader_t *device, struct pvd_t *pvd)
+static int UDFGetPVD(dvd_reader_t *ctx, struct pvd_t *pvd)
 {
   uint8_t pvd_buf_base[DVD_VIDEO_LB_LEN + 2048];
   uint8_t *pvd_buf = (uint8_t *)(((uintptr_t)pvd_buf_base & ~((uintptr_t)2047)) + 2048);
-  if(GetUDFCache(device, PVDCache, 0, pvd))
+  if(GetUDFCache(ctx, PVDCache, 0, pvd))
     return 1;
 
-  if(!UDFGetDescriptor( device, 1, pvd_buf, DVD_VIDEO_LB_LEN))
+  if(!UDFGetDescriptor( ctx, 1, pvd_buf, DVD_VIDEO_LB_LEN))
     return 0;
 
   memcpy(pvd->VolumeIdentifier, &pvd_buf[24], 32);
   memcpy(pvd->VolumeSetIdentifier, &pvd_buf[72], 128);
-  SetUDFCache(device, PVDCache, 0, pvd);
+  SetUDFCache(ctx, PVDCache, 0, pvd);
   return 1;
 }
 
@@ -987,14 +987,14 @@ static int UDFGetPVD(dvd_reader_t *device, struct pvd_t *pvd)
  * volid_size, size of the buffer volid points to
  * returns the size of buffer needed for all data
  */
-int UDFGetVolumeIdentifier(dvd_reader_t *device, char *volid,
+int UDFGetVolumeIdentifier(dvd_reader_t *ctx, char *volid,
                            unsigned int volid_size)
 {
   struct pvd_t pvd;
   unsigned int volid_len;
 
   /* get primary volume descriptor */
-  if(!UDFGetPVD(device, &pvd))
+  if(!UDFGetPVD(ctx, &pvd))
     return 0;
 
   volid_len = pvd.VolumeIdentifier[31];
@@ -1017,13 +1017,13 @@ int UDFGetVolumeIdentifier(dvd_reader_t *device, char *volid,
  * returns the size of the available volsetid information (128)
  * or 0 on error
  */
-int UDFGetVolumeSetIdentifier(dvd_reader_t *device, uint8_t *volsetid,
+int UDFGetVolumeSetIdentifier(dvd_reader_t *ctx, uint8_t *volsetid,
                               unsigned int volsetid_size)
 {
   struct pvd_t pvd;
 
   /* get primary volume descriptor */
-  if(!UDFGetPVD(device, &pvd))
+  if(!UDFGetPVD(ctx, &pvd))
     return 0;
 
 


=====================================
src/dvdread/dvd_reader.h
=====================================
@@ -63,6 +63,7 @@ extern "C" {
  * Opaque type that is used as a handle for one instance of an opened DVD.
  */
 typedef struct dvd_reader_s dvd_reader_t;
+typedef struct dvd_reader_device_s dvd_reader_device_t;
 
 /**
  * Opaque type for a file read handle, much like a normal fd or FILE *.


=====================================
src/dvdread/dvd_udf.h
=====================================
@@ -46,11 +46,11 @@ extern "C" {
  * '/VIDEO_TS/VTS_01_1.IFO'.  On success, filesize will be set to the size of
  * the file in bytes.
  */
-uint32_t UDFFindFile( dvd_reader_t *device, const char *filename, uint32_t *size );
+uint32_t UDFFindFile( dvd_reader_t *, const char *filename, uint32_t *size );
 
-int UDFGetVolumeIdentifier(dvd_reader_t *device,
+int UDFGetVolumeIdentifier(dvd_reader_t *,
                            char *volid, unsigned int volid_size);
-int UDFGetVolumeSetIdentifier(dvd_reader_t *device,
+int UDFGetVolumeSetIdentifier(dvd_reader_t *,
                               uint8_t *volsetid, unsigned int volsetid_size);
 
 #ifdef __cplusplus


=====================================
src/dvdread_internal.h
=====================================
@@ -35,6 +35,14 @@
             __FILE__, __LINE__, # arg );                                \
   }
 
+struct dvd_reader_s
+{
+    dvd_reader_device_t *rd;
+    /* Set 100 flags for BUP fallback, most signifiant left
+       [0] for upper remaining VTS, [1] for the first Main + 63 VTS */
+    uint64_t ifoBUPflags[2];
+};
+
 enum TagIdentifier {
   /* ECMA 167 3/7.2.1 */
   PrimaryVolumeDescriptor           = 1,
@@ -60,11 +68,11 @@ enum TagIdentifier {
   ExtendedFileEntry                 = 266,
 };
 
-int InternalUDFReadBlocksRaw(const dvd_reader_t *device, uint32_t lb_number,
+int InternalUDFReadBlocksRaw(const dvd_reader_t *, uint32_t lb_number,
                      size_t block_count, unsigned char *data, int encrypted);
 
-void *GetUDFCacheHandle(dvd_reader_t *device);
-void SetUDFCacheHandle(dvd_reader_t *device, void *cache);
+void *GetUDFCacheHandle(dvd_reader_t *);
+void SetUDFCacheHandle(dvd_reader_t *, void *cache);
 void FreeUDFCache(void *cache);
 
 #endif /* LIBDVDREAD_DVDREAD_INTERNAL_H */


=====================================
src/ifo_read.c
=====================================
@@ -288,25 +288,28 @@ static void free_ptl_mait(ptl_mait_t* ptl_mait, int num_entries) {
   free(ptl_mait);
 }
 
-ifo_handle_t *ifoOpen(dvd_reader_t *dvd, int title) {
+static ifo_handle_t *ifoOpenFileOrBackup(dvd_reader_t *ctx, int title,
+                                         int backup) {
   ifo_handle_t *ifofile;
-  int bup_file_opened = 0;
+  dvd_read_domain_t domain = backup ? DVD_READ_INFO_BACKUP_FILE
+                                    : DVD_READ_INFO_FILE;
   char ifo_filename[13];
 
   ifofile = calloc(1, sizeof(ifo_handle_t));
   if(!ifofile)
     return NULL;
 
-  ifofile->file = DVDOpenFile(dvd, title, DVD_READ_INFO_FILE);
-  if(!ifofile->file) { /* Failed to open IFO, try to open BUP */
-    ifofile->file = DVDOpenFile(dvd, title, DVD_READ_INFO_BACKUP_FILE);
-    bup_file_opened = 1;
+  ifofile->file = DVDOpenFile(ctx, title, domain);
+  if(!ifofile->file)
+  {
+      free(ifofile);
+      return NULL;
   }
 
   if (title)
-    snprintf(ifo_filename, 13, "VTS_%02d_0.%s", title, bup_file_opened ? "BUP" : "IFO");
+    snprintf(ifo_filename, 13, "VTS_%02d_0.%s", title, backup ? "BUP" : "IFO");
   else
-    snprintf(ifo_filename, 13, "VIDEO_TS.%s", bup_file_opened ? "BUP" : "IFO");
+    snprintf(ifo_filename, 13, "VIDEO_TS.%s", backup ? "BUP" : "IFO");
 
   if(!ifofile->file) {
     fprintf(stderr, "libdvdread: Can't open file %s.\n", ifo_filename);
@@ -314,68 +317,6 @@ ifo_handle_t *ifoOpen(dvd_reader_t *dvd, int title) {
     return NULL;
   }
 
-  /* First check if this is a VMGI file. */
-  if(ifoRead_VMG(ifofile)) {
-
-    /* These are both mandatory. */
-    if(!ifoRead_FP_PGC(ifofile) || !ifoRead_TT_SRPT(ifofile))
-      goto ifoOpen_try_bup;
-
-    ifoRead_PGCI_UT(ifofile);
-    ifoRead_PTL_MAIT(ifofile);
-
-    /* This is also mandatory. */
-    if(!ifoRead_VTS_ATRT(ifofile))
-      goto ifoOpen_try_bup;
-
-    ifoRead_TXTDT_MGI(ifofile);
-    ifoRead_C_ADT(ifofile);
-    ifoRead_VOBU_ADMAP(ifofile);
-
-    return ifofile;
-  }
-
-  if(ifoRead_VTS(ifofile)) {
-
-    if(!ifoRead_VTS_PTT_SRPT(ifofile) || !ifoRead_PGCIT(ifofile))
-      goto ifoOpen_try_bup;
-
-    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))
-      goto ifoOpen_try_bup;
-
-    return ifofile;
-  }
-
-ifoOpen_try_bup:
-  if (bup_file_opened)
-    goto ifoOpen_fail;
-
-  /* Try BUP instead */
-  ifoClose(ifofile);
-
-  ifofile = calloc(1, sizeof(ifo_handle_t));
-  if(!ifofile)
-    return NULL;
-
-  ifofile->file = DVDOpenFile(dvd, title, DVD_READ_INFO_BACKUP_FILE);
-
-  if (title)
-    snprintf(ifo_filename, 13, "VTS_%02d_0.BUP", title);
-  else
-    strncpy(ifo_filename, "VIDEO_TS.BUP", 13);
-
-  if (!ifofile->file) {
-    fprintf(stderr, "libdvdread: Can't open file %s.\n", ifo_filename);
-    free(ifofile);
-    return NULL;
-  }
-  bup_file_opened = 1;
-
   /* First check if this is a VMGI file. */
   if(ifoRead_VMG(ifofile)) {
 
@@ -419,60 +360,101 @@ ifoOpen_fail:
   return NULL;
 }
 
+static void ifoSetBupFlag(dvd_reader_t *ctx, int title)
+{
+    if(title > 63)
+        ctx->ifoBUPflags[0] |= 1 << (title - 64);
+    else
+        ctx->ifoBUPflags[1] |= 1 << title;
+}
 
-ifo_handle_t *ifoOpenVMGI(dvd_reader_t *dvd) {
-  ifo_handle_t *ifofile;
+static int ifoGetBupFlag(const dvd_reader_t *ctx, int title)
+{
+    int bupflag;
+    if(title > 63)
+        bupflag = !! (ctx->ifoBUPflags[0] & (1 << (title - 64)));
+    else
+        bupflag = !! (ctx->ifoBUPflags[1] & (1 << title));
+    return bupflag;
+}
 
-  ifofile = calloc(1, sizeof(ifo_handle_t));
-  if(!ifofile)
-    return NULL;
+ifo_handle_t *ifoOpen(dvd_reader_t *ctx, int title) {
+  ifo_handle_t *ifofile;
+  int bupflag = ifoGetBupFlag(ctx, title);
 
-  ifofile->file = DVDOpenFile(dvd, 0, DVD_READ_INFO_FILE);
-  if(!ifofile->file) /* Should really catch any error and try to fallback */
-    ifofile->file = DVDOpenFile(dvd, 0, DVD_READ_INFO_BACKUP_FILE);
-  if(!ifofile->file) {
-    fprintf(stderr, "libdvdread: Can't open file VIDEO_TS.IFO.\n");
-    free(ifofile);
-    return NULL;
+  ifofile = ifoOpenFileOrBackup(ctx, title, bupflag);
+  if(!ifofile) /* Try backup */
+  {
+      ifofile = ifoOpenFileOrBackup(ctx, title, 1);
+      if(ifofile && !bupflag)
+          ifoSetBupFlag(ctx, title);
   }
+  return ifofile;
+}
 
-  if(ifoRead_VMG(ifofile))
-    return ifofile;
+ifo_handle_t *ifoOpenVMGI(dvd_reader_t *ctx) {
+  ifo_handle_t *ifofile;
 
-  fprintf(stderr, "libdvdread,ifoOpenVMGI(): Invalid main menu IFO (VIDEO_TS.IFO).\n");
-  ifoClose(ifofile);
+  for(int backup = ifoGetBupFlag(ctx, 0); backup <= 1; backup++)
+  {
+    ifofile = calloc(1, sizeof(ifo_handle_t));
+    if(!ifofile)
+      return NULL;
+
+    const dvd_read_domain_t domain = backup ? DVD_READ_INFO_BACKUP_FILE
+                                            : DVD_READ_INFO_FILE;
+    const char *ext = backup ? "BUP" : "IFO";
+
+    ifofile->file = DVDOpenFile(ctx, 0, domain);
+    if(!ifofile->file) { /* Should really catch any error */
+      fprintf(stderr, "libdvdread: Can't open file VIDEO_TS.%s.\n", ext);
+      free(ifofile);
+      return NULL;
+    }
+
+    if(ifoRead_VMG(ifofile))
+      return ifofile;
+
+    fprintf(stderr, "libdvdread,ifoOpenVMGI(): Invalid main menu IFO (VIDEO_TS.%s).\n", ext);
+    ifoClose(ifofile);
+  }
   return NULL;
 }
 
 
-ifo_handle_t *ifoOpenVTSI(dvd_reader_t *dvd, int title) {
+ifo_handle_t *ifoOpenVTSI(dvd_reader_t *ctx, int title) {
   ifo_handle_t *ifofile;
 
-  ifofile = calloc(1, sizeof(ifo_handle_t));
-  if(!ifofile)
-    return NULL;
-
   if(title <= 0 || title > 99) {
     fprintf(stderr, "libdvdread: ifoOpenVTSI invalid title (%d).\n", title);
-    free(ifofile);
     return NULL;
   }
 
-  ifofile->file = DVDOpenFile(dvd, title, DVD_READ_INFO_FILE);
-  if(!ifofile->file) /* Should really catch any error and try to fallback */
-    ifofile->file = DVDOpenFile(dvd, title, DVD_READ_INFO_BACKUP_FILE);
-  if(!ifofile->file) {
-    fprintf(stderr, "libdvdread: Can't open file VTS_%02d_0.IFO.\n", title);
-    free(ifofile);
-    return NULL;
-  }
+  for(int backup = ifoGetBupFlag(ctx, title); backup <= 1; backup++)
+  {
+    ifofile = calloc(1, sizeof(ifo_handle_t));
+    if(!ifofile)
+      return NULL;
+
+    const dvd_read_domain_t domain = backup ? DVD_READ_INFO_BACKUP_FILE
+                                            : DVD_READ_INFO_FILE;
+    const char *ext = backup ? "BUP" : "IFO";
+    ifofile->file = DVDOpenFile(ctx, title, domain);
+    /* Should really catch any error */
+    if(!ifofile->file) {
+      fprintf(stderr, "libdvdread: Can't open file VTS_%02d_0.%s.\n", title, ext);
+      free(ifofile);
+      continue;
+    }
 
-  if(ifoRead_VTS(ifofile) && ifofile->vtsi_mat)
-    return ifofile;
+    if(ifoRead_VTS(ifofile) && ifofile->vtsi_mat)
+      return ifofile;
+
+    fprintf(stderr, "libdvdread: Invalid IFO for title %d (VTS_%02d_0.%s).\n",
+            title, title, ext);
+    ifoClose(ifofile);
+  }
 
-  fprintf(stderr, "libdvdread: Invalid IFO for title %d (VTS_%02d_0.IFO).\n",
-          title, title);
-  ifoClose(ifofile);
   return NULL;
 }
 



View it on GitLab: https://code.videolan.org/videolan/libdvdread/-/compare/64e41a83448560374655eab9ab377dcce66e5a64...6c463b78201e2af6a5191c1d4c2272ef5711c45b

-- 
View it on GitLab: https://code.videolan.org/videolan/libdvdread/-/compare/64e41a83448560374655eab9ab377dcce66e5a64...6c463b78201e2af6a5191c1d4c2272ef5711c45b
You're receiving this email because of your account on code.videolan.org.




More information about the libdvdnav-devel mailing list