MythTV  0.26-pre
dvd_reader.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2001-2004 Billy Biggs <vektor@dumbterm.net>,
00003  *                         Håkan Hjort <d95hjort@dtek.chalmers.se>,
00004  *                         Björn Englund <d4bjorn@dtek.chalmers.se>
00005  *
00006  * This file is part of libdvdread.
00007  *
00008  * libdvdread is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * libdvdread is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License along
00019  * with libdvdread; if not, write to the Free Software Foundation, Inc.,
00020  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00021  */
00022 
00023 #include <sys/types.h>
00024 #include <sys/stat.h>
00025 #include <sys/time.h> /* For the timing of dvdcss_title crack. */
00026 #include <fcntl.h>
00027 #include <stdlib.h>
00028 #include <stdio.h>
00029 #include <errno.h>
00030 #include <string.h>
00031 #include <ctype.h>
00032 #include <unistd.h>
00033 #include <limits.h>
00034 #include <dirent.h>
00035 
00036 /* misc win32 helpers */
00037 #ifdef WIN32
00038 #ifndef HAVE_GETTIMEOFDAY
00039 /* replacement gettimeofday implementation */
00040 #include <sys/timeb.h>
00041 static inline int _private_gettimeofday( struct timeval *tv, void *tz )
00042 {
00043   struct timeb t;
00044   ftime( &t );
00045   tv->tv_sec = t.time;
00046   tv->tv_usec = t.millitm * 1000;
00047   return 0;
00048 }
00049 #define gettimeofday(TV, TZ) _private_gettimeofday((TV), (TZ))
00050 #endif
00051 #include <io.h> /* read() */
00052 #define lseek64 _lseeki64
00053 #endif
00054 
00055 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__bsdi__) || defined(__APPLE__)
00056 #define SYS_BSD 1
00057 #endif
00058 
00059 #if defined(__sun)
00060 #include <sys/mnttab.h>
00061 #elif defined(SYS_BSD)
00062 #include <fstab.h>
00063 #elif defined(__linux__)
00064 #include <mntent.h>
00065 #include <paths.h>
00066 #endif
00067 
00068 #include "dvdread/dvd_udf.h"
00069 #include "dvd_input.h"
00070 #include "dvdread/dvd_reader.h"
00071 #include "md5.h"
00072 #include "mythiowrapper.h"
00073 
00074 #define DEFAULT_UDF_CACHE_LEVEL 1
00075 
00076 struct dvd_reader_s {
00077   /* Basic information. */
00078   int isImageFile;
00079 
00080   /* Hack for keeping track of the css status.
00081    * 0: no css, 1: perhaps (need init of keys), 2: have done init */
00082   int css_state;
00083   int css_title; /* Last title that we have called dvdinpute_title for. */
00084 
00085   /* Information required for an image file. */
00086   dvd_input_t dev;
00087 
00088   /* Information required for a directory path drive. */
00089   char *path_root;
00090 
00091   /* Filesystem cache */
00092   int udfcache_level; /* 0 - turned off, 1 - on */
00093   void *udfcache;
00094 };
00095 
00096 #define TITLES_MAX 9
00097 
00098 struct dvd_file_s {
00099   /* Basic information. */
00100   dvd_reader_t *dvd;
00101 
00102   /* Hack for selecting the right css title. */
00103   int css_title;
00104 
00105   /* Information required for an image file. */
00106   uint32_t lb_start;
00107   uint32_t seek_pos;
00108 
00109   /* Information required for a directory path drive. */
00110   size_t title_sizes[ TITLES_MAX ];
00111   dvd_input_t title_devs[ TITLES_MAX ];
00112 
00113   /* Calculated at open-time, size in blocks. */
00114   ssize_t filesize;
00115 };
00116 
00117 int UDFReadBlocksRaw( dvd_reader_t *device, uint32_t lb_number,
00118                       size_t block_count, unsigned char *data,
00119                       int encrypted );
00120 
00126 int DVDUDFCacheLevel(dvd_reader_t *device, int level)
00127 {
00128   struct dvd_reader_s *dev = (struct dvd_reader_s *)device;
00129 
00130   if(level > 0) {
00131     level = 1;
00132   } else if(level < 0) {
00133     return dev->udfcache_level;
00134   }
00135 
00136   dev->udfcache_level = level;
00137 
00138   return level;
00139 }
00140 
00141 void *GetUDFCacheHandle(dvd_reader_t *device)
00142 {
00143   struct dvd_reader_s *dev = (struct dvd_reader_s *)device;
00144 
00145   return dev->udfcache;
00146 }
00147 
00148 void SetUDFCacheHandle(dvd_reader_t *device, void *cache)
00149 {
00150   struct dvd_reader_s *dev = (struct dvd_reader_s *)device;
00151 
00152   dev->udfcache = cache;
00153 }
00154 
00155 
00156 
00157 /* Loop over all titles and call dvdcss_title to crack the keys. */
00158 static int initAllCSSKeys( dvd_reader_t *dvd )
00159 {
00160   struct timeval all_s, all_e;
00161   struct timeval t_s, t_e;
00162   char filename[ MAX_UDF_FILE_NAME_LEN ];
00163   uint32_t start, len;
00164   int title;
00165 
00166   char *nokeys_str = getenv("DVDREAD_NOKEYS");
00167   if(nokeys_str != NULL)
00168     return 0;
00169 
00170   fprintf( stderr, "\n" );
00171   fprintf( stderr, "libdvdread: Attempting to retrieve all CSS keys\n" );
00172   fprintf( stderr, "libdvdread: This can take a _long_ time, "
00173            "please be patient\n\n" );
00174   gettimeofday(&all_s, NULL);
00175 
00176   for( title = 0; title < 100; title++ ) {
00177     gettimeofday( &t_s, NULL );
00178     if( title == 0 ) {
00179       sprintf( filename, "/VIDEO_TS/VIDEO_TS.VOB" );
00180     } else {
00181       sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, 0 );
00182     }
00183     start = UDFFindFile( dvd, filename, &len );
00184     if( start != 0 && len != 0 ) {
00185       /* Perform CSS key cracking for this title. */
00186       fprintf( stderr, "libdvdread: Get key for %s at 0x%08x\n",
00187                filename, start );
00188       if( dvdinput_title( dvd->dev, (int)start ) < 0 ) {
00189         fprintf( stderr, "libdvdread: Error cracking CSS key for %s (0x%08x)\n", filename, start);
00190       }
00191       gettimeofday( &t_e, NULL );
00192       fprintf( stderr, "libdvdread: Elapsed time %ld\n",
00193                (long int) t_e.tv_sec - t_s.tv_sec );
00194     }
00195 
00196     if( title == 0 ) continue;
00197 
00198     gettimeofday( &t_s, NULL );
00199     sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, 1 );
00200     start = UDFFindFile( dvd, filename, &len );
00201     if( start == 0 || len == 0 ) break;
00202 
00203     /* Perform CSS key cracking for this title. */
00204     fprintf( stderr, "libdvdread: Get key for %s at 0x%08x\n",
00205              filename, start );
00206     if( dvdinput_title( dvd->dev, (int)start ) < 0 ) {
00207       fprintf( stderr, "libdvdread: Error cracking CSS key for %s (0x%08x)!!\n", filename, start);
00208     }
00209     gettimeofday( &t_e, NULL );
00210     fprintf( stderr, "libdvdread: Elapsed time %ld\n",
00211              (long int) t_e.tv_sec - t_s.tv_sec );
00212   }
00213   title--;
00214 
00215   fprintf( stderr, "libdvdread: Found %d VTS's\n", title );
00216   gettimeofday(&all_e, NULL);
00217   fprintf( stderr, "libdvdread: Elapsed time %ld\n",
00218            (long int) all_e.tv_sec - all_s.tv_sec );
00219 
00220   return 0;
00221 }
00222 
00223 
00224 
00228 static dvd_reader_t *DVDOpenImageFile( const char *location, int have_css )
00229 {
00230   dvd_reader_t *dvd;
00231   dvd_input_t dev;
00232 
00233   dev = dvdinput_open( location );
00234   if( !dev ) {
00235     fprintf( stderr, "libdvdread: Can't open %s for reading\n", location );
00236     return NULL;
00237   }
00238 
00239   dvd = (dvd_reader_t *) malloc( sizeof( dvd_reader_t ) );
00240   if( !dvd ) {
00241     dvdinput_close(dev);
00242     return NULL;
00243   }
00244   memset( dvd, 0, sizeof( dvd_reader_t ) );
00245   dvd->isImageFile = 1;
00246   dvd->dev = dev;
00247   dvd->path_root = NULL;
00248 
00249   dvd->udfcache_level = DEFAULT_UDF_CACHE_LEVEL;
00250   dvd->udfcache = NULL;
00251 
00252   if( have_css ) {
00253     /* Only if DVDCSS_METHOD = title, a bit if it's disc or if
00254      * DVDCSS_METHOD = key but region mismatch. Unfortunately we
00255      * don't have that information. */
00256 
00257     dvd->css_state = 1; /* Need key init. */
00258   }
00259   dvd->css_title = 0;
00260 
00261   return dvd;
00262 }
00263 
00264 static dvd_reader_t *DVDOpenPath( const char *path_root )
00265 {
00266   dvd_reader_t *dvd;
00267 
00268   dvd = (dvd_reader_t *) malloc( sizeof( dvd_reader_t ) );
00269   if( !dvd ) return NULL;
00270   dvd->isImageFile = 0;
00271   dvd->dev = 0;
00272   dvd->path_root = strdup( path_root );
00273   if(!dvd->path_root) {
00274     free(dvd);
00275     return 0;
00276   }
00277   dvd->udfcache_level = DEFAULT_UDF_CACHE_LEVEL;
00278   dvd->udfcache = NULL;
00279 
00280   dvd->css_state = 0; /* Only used in the UDF path */
00281   dvd->css_title = 0; /* Only matters in the UDF path */
00282 
00283   return dvd;
00284 }
00285 
00286 #if defined(__sun)
00287 /* /dev/rdsk/c0t6d0s0 (link to /devices/...)
00288    /vol/dev/rdsk/c0t6d0/??
00289    /vol/rdsk/<name> */
00290 static char *sun_block2char( const char *path )
00291 {
00292   char *new_path;
00293 
00294   /* Must contain "/dsk/" */
00295   if( !strstr( path, "/dsk/" ) ) return (char *) strdup( path );
00296 
00297   /* Replace "/dsk/" with "/rdsk/" */
00298   new_path = malloc( strlen(path) + 2 );
00299   strcpy( new_path, path );
00300   strcpy( strstr( new_path, "/dsk/" ), "" );
00301   strcat( new_path, "/rdsk/" );
00302   strcat( new_path, strstr( path, "/dsk/" ) + strlen( "/dsk/" ) );
00303 
00304   return new_path;
00305 }
00306 #endif
00307 
00308 #if defined(SYS_BSD)
00309 /* FreeBSD /dev/(r)(a)cd0c (a is for atapi), recommended to _not_ use r
00310    update: FreeBSD and DragonFly no longer uses the prefix so don't add it.
00311    OpenBSD /dev/rcd0c, it needs to be the raw device
00312    NetBSD  /dev/rcd0[d|c|..] d for x86, c (for non x86), perhaps others
00313    Darwin  /dev/rdisk0,  it needs to be the raw device
00314    BSD/OS  /dev/sr0c (if not mounted) or /dev/rsr0c ('c' any letter will do)
00315    returns a string allocated with strdup. It should be freed when no longer
00316    used. */
00317 static char *bsd_block2char( const char *path )
00318 {
00319 #if defined(__FreeBSD__) || defined(__DragonFly__)
00320   return (char *) strdup( path );
00321 #else
00322   char *new_path;
00323 
00324   /* If it doesn't start with "/dev/" or does start with "/dev/r" exit */
00325   if( strncmp( path, "/dev/",  5 ) || !strncmp( path, "/dev/r", 6 ) )
00326     return (char *) strdup( path );
00327 
00328   /* Replace "/dev/" with "/dev/r" */
00329   new_path = malloc( strlen(path) + 2 );
00330   strcpy( new_path, "/dev/r" );
00331   strcat( new_path, path + strlen( "/dev/" ) );
00332 
00333   return new_path;
00334 #endif /* __FreeBSD__ || __DragonFly__ */
00335 }
00336 #endif
00337 
00338 
00339 dvd_reader_t *DVDOpen( const char *ppath )
00340 {
00341   struct stat fileinfo;
00342   int ret, have_css, retval, cdir = -1;
00343   dvd_reader_t *ret_val = NULL;
00344   char *dev_name = NULL;
00345   char *path = NULL, *new_path = NULL, *path_copy = NULL;
00346 
00347 #if defined(_WIN32) || defined(__OS2__)
00348       int len;
00349 #endif
00350 
00351   if( ppath == NULL )
00352     goto DVDOpen_error;
00353 
00354       path = strdup(ppath);
00355   if( path == NULL )
00356     goto DVDOpen_error;
00357 
00358   /* Try to open libdvdcss or fall back to standard functions */
00359   have_css = dvdinput_setup(path);
00360 
00361 #if defined(_WIN32) || defined(__OS2__)
00362   /* Strip off the trailing \ if it is not a drive */
00363   len = strlen(path);
00364   if ((len > 1) &&
00365       (path[len - 1] == '\\')  &&
00366       (path[len - 2] != ':'))
00367   {
00368     path[len-1] = '\0';
00369   }
00370 #endif
00371 
00372   ret = mythfile_stat( path, &fileinfo );
00373 
00374   if( ret < 0 ) {
00375 
00376     /* maybe "host:port" url? try opening it with acCeSS library */
00377     if( strchr(path,':') ) {
00378                     ret_val = DVDOpenImageFile( path, have_css );
00379                     free(path);
00380             return ret_val;
00381     }
00382 
00383     /* If we can't stat the file, give up */
00384     fprintf( stderr, "libdvdread: Can't stat %s\n", path );
00385     perror("");
00386     goto DVDOpen_error;
00387   }
00388 
00389   /* First check if this is a block/char device or a file*/
00390   if( S_ISBLK( fileinfo.st_mode ) ||
00391       S_ISCHR( fileinfo.st_mode ) ||
00392       S_ISREG( fileinfo.st_mode ) ) {
00393 
00397     dvd_reader_t *dvd = NULL;
00398 #if defined(__sun)
00399     dev_name = sun_block2char( path );
00400 #elif defined(SYS_BSD)
00401     dev_name = bsd_block2char( path );
00402 #else
00403     dev_name = strdup( path );
00404 #endif
00405     dvd = DVDOpenImageFile( dev_name, have_css );
00406     free( dev_name );
00407     free(path);
00408     return dvd;
00409   } else if( S_ISDIR( fileinfo.st_mode ) ) {
00410     dvd_reader_t *auth_drive = 0;
00411 #if defined(SYS_BSD)
00412     struct fstab* fe;
00413 #elif defined(__sun) || defined(__linux__)
00414     FILE *mntfile;
00415 #endif
00416 
00417     /* XXX: We should scream real loud here. */
00418     if( !(path_copy = strdup( path ) ) )
00419       goto DVDOpen_error;
00420 
00421 #ifndef WIN32 /* don't have fchdir, and getcwd( NULL, ... ) is strange */
00422               /* Also WIN32 does not have symlinks, so we don't need this bit of code. */
00423 
00424     /* Resolve any symlinks and get the absolute dir name. */
00425     if (!strncmp(path, "myth://", 7))
00426         dev_name = strdup( path );
00427     else
00428     {
00429       if( ( cdir  = open( ".", O_RDONLY ) ) >= 0 ) {
00430         if( chdir( path_copy ) == -1 ) {
00431           goto DVDOpen_error;
00432         }
00433         new_path = malloc(PATH_MAX+1);
00434         if(!new_path) {
00435           goto DVDOpen_error;
00436         }
00437         if( getcwd( new_path, PATH_MAX ) == NULL ) {
00438           goto DVDOpen_error;
00439         }
00440         retval = fchdir( cdir );
00441         close( cdir );
00442         cdir = -1;
00443         if( retval == -1 ) {
00444           goto DVDOpen_error;
00445         }
00446         path_copy = new_path;
00447         new_path = NULL;
00448       }
00449     }
00450 #endif
00451 
00457     if( strlen( path_copy ) > 1 ) {
00458       if( path_copy[ strlen( path_copy ) - 1 ] == '/' ) {
00459         path_copy[ strlen( path_copy ) - 1 ] = '\0';
00460       }
00461     }
00462 
00463 #if defined(_WIN32) || defined(__OS2__)
00464     if(strlen(path_copy) > TITLES_MAX) {
00465       if(!strcasecmp(&(path_copy[strlen( path_copy ) - TITLES_MAX]),
00466                        "\\video_ts"))
00467         path_copy[strlen(path_copy) - (TITLES_MAX-1)] = '\0';
00468     }
00469 #endif
00470     if( strlen( path_copy ) > TITLES_MAX ) {
00471       if( !strcasecmp( &(path_copy[ strlen( path_copy ) - TITLES_MAX ]),
00472                        "/video_ts" ) ) {
00473         path_copy[ strlen( path_copy ) - TITLES_MAX ] = '\0';
00474       }
00475     }
00476 
00477     if(path_copy[0] == '\0') {
00478       path_copy[0] = '/';
00479       path_copy[1] = '\0';
00480     }
00481 
00482 #if defined(SYS_BSD)
00483     if( ( fe = getfsfile( path_copy ) ) ) {
00484       dev_name = bsd_block2char( fe->fs_spec );
00485       fprintf( stderr,
00486                "libdvdread: Attempting to use device %s"
00487                " mounted on %s for CSS authentication\n",
00488                dev_name,
00489                fe->fs_file );
00490       auth_drive = DVDOpenImageFile( dev_name, have_css );
00491     }
00492 #elif defined(__sun)
00493     mntfile = fopen( MNTTAB, "r" );
00494     if( mntfile ) {
00495       struct mnttab mp;
00496       int res;
00497 
00498       while( ( res = getmntent( mntfile, &mp ) ) != -1 ) {
00499         if( res == 0 && !strcmp( mp.mnt_mountp, path_copy ) ) {
00500           dev_name = sun_block2char( mp.mnt_special );
00501           fprintf( stderr,
00502                    "libdvdread: Attempting to use device %s"
00503                    " mounted on %s for CSS authentication\n",
00504                    dev_name,
00505                    mp.mnt_mountp );
00506           auth_drive = DVDOpenImageFile( dev_name, have_css );
00507           break;
00508         }
00509       }
00510       fclose( mntfile );
00511     }
00512 #elif defined(__linux__)
00513     mntfile = fopen( _PATH_MOUNTED, "r" );
00514     if( mntfile ) {
00515       struct mntent *me;
00516 
00517       while( ( me = getmntent( mntfile ) ) ) {
00518         if( !strcmp( me->mnt_dir, path_copy ) ) {
00519           fprintf( stderr,
00520                    "libdvdread: Attempting to use device %s"
00521                    " mounted on %s for CSS authentication\n",
00522                    me->mnt_fsname,
00523                    me->mnt_dir );
00524           auth_drive = DVDOpenImageFile( me->mnt_fsname, have_css );
00525           dev_name = strdup(me->mnt_fsname);
00526           break;
00527         }
00528       }
00529       fclose( mntfile );
00530     }
00531 #elif defined(_WIN32) || defined(__OS2__)
00532 #ifdef __OS2__
00533     /* Use DVDOpenImageFile() only if it is a drive */
00534     if(isalpha(path[0]) && path[1] == ':' &&
00535         ( !path[2] ||
00536           ((path[2] == '\\' || path[2] == '/') && !path[3])))
00537 #endif
00538     auth_drive = DVDOpenImageFile( path, have_css );
00539 #endif
00540 
00541 #if !defined(_WIN32) && !defined(__OS2__)
00542     if( !dev_name ) {
00543       fprintf( stderr, "libdvdread: Couldn't find device name.\n" );
00544     } else if( !auth_drive ) {
00545       fprintf( stderr, "libdvdread: Device %s inaccessible, "
00546                "CSS authentication not available.\n", dev_name );
00547     }
00548 #else
00549     if( !auth_drive ) {
00550         fprintf( stderr, "libdvdread: Device %s inaccessible, "
00551                  "CSS authentication not available.\n", path );
00552     }
00553 #endif
00554 
00555     free( dev_name );
00556     dev_name = NULL;
00557     free( path_copy );
00558     path_copy = NULL;
00559 
00563     if( auth_drive ) {
00564       free(path);
00565       return auth_drive;
00566     }
00570     ret_val = DVDOpenPath( path );
00571       free( path );
00572       return ret_val;
00573   }
00574 
00575 DVDOpen_error:
00576   /* If it's none of the above, screw it. */
00577   fprintf( stderr, "libdvdread: Could not open %s\n", path );
00578   if( path != NULL )
00579     free( path );
00580   if ( path_copy != NULL )
00581     free( path_copy );
00582   if ( cdir >= 0 )
00583     close( cdir );
00584   if ( new_path != NULL )
00585     free( new_path );
00586   return NULL;
00587 }
00588 
00589 void DVDClose( dvd_reader_t *dvd )
00590 {
00591   if( dvd ) {
00592     if( dvd->dev ) dvdinput_close( dvd->dev );
00593     if( dvd->path_root ) free( dvd->path_root );
00594     if( dvd->udfcache ) FreeUDFCache( dvd->udfcache );
00595     free( dvd );
00596   }
00597 }
00598 
00602 static dvd_file_t *DVDOpenFileUDF( dvd_reader_t *dvd, char *filename )
00603 {
00604   uint32_t start, len;
00605   dvd_file_t *dvd_file;
00606 
00607   start = UDFFindFile( dvd, filename, &len );
00608   if( !start ) {
00609     fprintf( stderr, "libdvdnav:DVDOpenFileUDF:UDFFindFile %s failed\n", filename );
00610     return NULL;
00611   }
00612 
00613   dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) );
00614   if( !dvd_file ) {
00615     fprintf( stderr, "libdvdnav:DVDOpenFileUDF:malloc failed\n" );
00616     return NULL;
00617   }
00618   dvd_file->dvd = dvd;
00619   dvd_file->lb_start = start;
00620   dvd_file->seek_pos = 0;
00621   memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) );
00622   memset( dvd_file->title_devs, 0, sizeof( dvd_file->title_devs ) );
00623   dvd_file->filesize = len / DVD_VIDEO_LB_LEN;
00624 
00625   return dvd_file;
00626 }
00627 
00634 static int findDirFile( const char *path, const char *file, char *filename )
00635 {
00636   DIR *dir;
00637   struct dirent *ent;
00638 
00639   if (!strncmp(path, "myth://", 7) && mythfile_exists(path, file))
00640   {
00641     sprintf( filename, "%s%s%s", path,
00642             ( ( path[ strlen( path ) - 1 ] == '/' ) ? "" : "/" ),
00643                file );
00644     return 0;
00645   }
00646 
00647   dir = opendir( path );
00648   if( !dir ) return -2;
00649 
00650   while( ( ent = readdir( dir ) ) != NULL ) {
00651     if( !strcasecmp( ent->d_name, file ) ) {
00652       sprintf( filename, "%s%s%s", path,
00653                ( ( path[ strlen( path ) - 1 ] == '/' ) ? "" : "/" ),
00654                ent->d_name );
00655       closedir(dir);
00656       return 0;
00657     }
00658   }
00659   closedir(dir);
00660   return -1;
00661 }
00662 
00663 static int findDVDFile( dvd_reader_t *dvd, const char *file, char *filename )
00664 {
00665   char video_path[ PATH_MAX + 1 ];
00666   const char *nodirfile;
00667   int ret;
00668 
00669   /* Strip off the directory for our search */
00670   if( !strncasecmp( "/VIDEO_TS/", file, 10 ) ) {
00671     nodirfile = &(file[ 10 ]);
00672   } else {
00673     nodirfile = file;
00674   }
00675 
00676   ret = findDirFile( dvd->path_root, nodirfile, filename );
00677   if( ret < 0 ) {
00678     /* Try also with adding the path, just in case. */
00679     sprintf( video_path, "%s/VIDEO_TS/", dvd->path_root );
00680     ret = findDirFile( video_path, nodirfile, filename );
00681     if( ret < 0 ) {
00682       /* Try with the path, but in lower case. */
00683       sprintf( video_path, "%s/video_ts/", dvd->path_root );
00684       ret = findDirFile( video_path, nodirfile, filename );
00685       if( ret < 0 ) {
00686         return 0;
00687       }
00688     }
00689   }
00690 
00691   return 1;
00692 }
00693 
00697 static dvd_file_t *DVDOpenFilePath( dvd_reader_t *dvd, char *filename )
00698 {
00699   char full_path[ PATH_MAX + 1 ];
00700   dvd_file_t *dvd_file;
00701   struct stat fileinfo;
00702   dvd_input_t dev;
00703 
00704   /* Get the full path of the file. */
00705   if( !findDVDFile( dvd, filename, full_path ) ) {
00706     fprintf( stderr, "libdvdnav:DVDOpenFilePath:findDVDFile %s failed\n", filename );
00707     return NULL;
00708   }
00709 
00710   dev = dvdinput_open( full_path );
00711   if( !dev ) {
00712     fprintf( stderr, "libdvdnav:DVDOpenFilePath:dvdinput_open %s failed\n", full_path );
00713     return NULL;
00714   }
00715 
00716   dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) );
00717   if( !dvd_file ) {
00718     fprintf( stderr, "libdvdnav:DVDOpenFilePath:dvd_file malloc failed\n" );
00719     dvdinput_close(dev);
00720     return NULL;
00721   }
00722   dvd_file->dvd = dvd;
00723   dvd_file->lb_start = 0;
00724   dvd_file->seek_pos = 0;
00725   memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) );
00726   memset( dvd_file->title_devs, 0, sizeof( dvd_file->title_devs ) );
00727   dvd_file->filesize = 0;
00728 
00729   if( mythfile_stat( full_path, &fileinfo ) < 0 ) {
00730     fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename );
00731     free( dvd_file );
00732     dvdinput_close(dev);
00733     return NULL;
00734   }
00735   dvd_file->title_sizes[ 0 ] = fileinfo.st_size / DVD_VIDEO_LB_LEN;
00736   dvd_file->title_devs[ 0 ] = dev;
00737   dvd_file->filesize = dvd_file->title_sizes[ 0 ];
00738 
00739   return dvd_file;
00740 }
00741 
00742 static dvd_file_t *DVDOpenVOBUDF( dvd_reader_t *dvd, int title, int menu )
00743 {
00744   char filename[ MAX_UDF_FILE_NAME_LEN ];
00745   uint32_t start, len;
00746   dvd_file_t *dvd_file;
00747 
00748   if( title == 0 ) {
00749     sprintf( filename, "/VIDEO_TS/VIDEO_TS.VOB" );
00750   } else {
00751     sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, menu ? 0 : 1 );
00752   }
00753   start = UDFFindFile( dvd, filename, &len );
00754   if( start == 0 ) return NULL;
00755 
00756   dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) );
00757   if( !dvd_file ) return NULL;
00758   dvd_file->dvd = dvd;
00759   /*Hack*/ dvd_file->css_title = title << 1 | menu;
00760   dvd_file->lb_start = start;
00761   dvd_file->seek_pos = 0;
00762   memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) );
00763   memset( dvd_file->title_devs, 0, sizeof( dvd_file->title_devs ) );
00764   dvd_file->filesize = len / DVD_VIDEO_LB_LEN;
00765 
00766   /* Calculate the complete file size for every file in the VOBS */
00767   if( !menu ) {
00768     int cur;
00769 
00770     for( cur = 2; cur < 10; cur++ ) {
00771       sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, cur );
00772       if( !UDFFindFile( dvd, filename, &len ) ) break;
00773       dvd_file->filesize += len / DVD_VIDEO_LB_LEN;
00774     }
00775   }
00776 
00777   if( dvd->css_state == 1 /* Need key init */ ) {
00778     initAllCSSKeys( dvd );
00779     dvd->css_state = 2;
00780   }
00781   /*
00782   if( dvdinput_title( dvd_file->dvd->dev, (int)start ) < 0 ) {
00783       fprintf( stderr, "libdvdread: Error cracking CSS key for %s\n",
00784                filename );
00785   }
00786   */
00787 
00788   return dvd_file;
00789 }
00790 
00791 static dvd_file_t *DVDOpenVOBPath( dvd_reader_t *dvd, int title, int menu )
00792 {
00793   char filename[ MAX_UDF_FILE_NAME_LEN ];
00794   char full_path[ PATH_MAX + 1 ];
00795   struct stat fileinfo;
00796   dvd_file_t *dvd_file;
00797   int i;
00798 
00799   dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) );
00800   if( !dvd_file ) return NULL;
00801   dvd_file->dvd = dvd;
00802   /*Hack*/ dvd_file->css_title = title << 1 | menu;
00803   dvd_file->lb_start = 0;
00804   dvd_file->seek_pos = 0;
00805   memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) );
00806   memset( dvd_file->title_devs, 0, sizeof( dvd_file->title_devs ) );
00807   dvd_file->filesize = 0;
00808 
00809   if( menu ) {
00810     dvd_input_t dev;
00811 
00812     if( title == 0 ) {
00813       sprintf( filename, "VIDEO_TS.VOB" );
00814     } else {
00815       sprintf( filename, "VTS_%02i_0.VOB", title );
00816     }
00817     if( !findDVDFile( dvd, filename, full_path ) ) {
00818       free( dvd_file );
00819       return NULL;
00820     }
00821 
00822     dev = dvdinput_open( full_path );
00823     if( dev == NULL ) {
00824       free( dvd_file );
00825       return NULL;
00826     }
00827 
00828     if( mythfile_stat( full_path, &fileinfo ) < 0 ) {
00829       fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename );
00830       dvdinput_close(dev);
00831       free( dvd_file );
00832       return NULL;
00833     }
00834     dvd_file->title_sizes[ 0 ] = fileinfo.st_size / DVD_VIDEO_LB_LEN;
00835     dvd_file->title_devs[ 0 ] = dev;
00836     dvdinput_title( dvd_file->title_devs[0], 0);
00837     dvd_file->filesize = dvd_file->title_sizes[ 0 ];
00838 
00839   } else {
00840     for( i = 0; i < TITLES_MAX; ++i ) {
00841 
00842       sprintf( filename, "VTS_%02i_%i.VOB", title, i + 1 );
00843       if( !findDVDFile( dvd, filename, full_path ) ) {
00844         break;
00845       }
00846 
00847       if( mythfile_stat( full_path, &fileinfo ) < 0 ) {
00848         fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename );
00849         break;
00850       }
00851 
00852       dvd_file->title_sizes[ i ] = fileinfo.st_size / DVD_VIDEO_LB_LEN;
00853       dvd_file->title_devs[ i ] = dvdinput_open( full_path );
00854       dvdinput_title( dvd_file->title_devs[ i ], 0 );
00855       dvd_file->filesize += dvd_file->title_sizes[ i ];
00856     }
00857     if( !dvd_file->title_devs[ 0 ] ) {
00858       free( dvd_file );
00859       return NULL;
00860     }
00861   }
00862 
00863   return dvd_file;
00864 }
00865 
00866 dvd_file_t *DVDOpenFile( dvd_reader_t *dvd, int titlenum,
00867                          dvd_read_domain_t domain )
00868 {
00869   char filename[ MAX_UDF_FILE_NAME_LEN ];
00870 
00871   /* Check arguments. */
00872   if( dvd == NULL || titlenum < 0 )
00873     return NULL;
00874 
00875   switch( domain ) {
00876   case DVD_READ_INFO_FILE:
00877     if( titlenum == 0 ) {
00878       sprintf( filename, "/VIDEO_TS/VIDEO_TS.IFO" );
00879     } else {
00880       sprintf( filename, "/VIDEO_TS/VTS_%02i_0.IFO", titlenum );
00881     }
00882     break;
00883   case DVD_READ_INFO_BACKUP_FILE:
00884     if( titlenum == 0 ) {
00885       sprintf( filename, "/VIDEO_TS/VIDEO_TS.BUP" );
00886     } else {
00887       sprintf( filename, "/VIDEO_TS/VTS_%02i_0.BUP", titlenum );
00888     }
00889     break;
00890   case DVD_READ_MENU_VOBS:
00891     if( dvd->isImageFile ) {
00892       return DVDOpenVOBUDF( dvd, titlenum, 1 );
00893     } else {
00894       return DVDOpenVOBPath( dvd, titlenum, 1 );
00895     }
00896     break;
00897   case DVD_READ_TITLE_VOBS:
00898     if( titlenum == 0 ) return 0;
00899     if( dvd->isImageFile ) {
00900       return DVDOpenVOBUDF( dvd, titlenum, 0 );
00901     } else {
00902       return DVDOpenVOBPath( dvd, titlenum, 0 );
00903     }
00904     break;
00905   default:
00906     fprintf( stderr, "libdvdread: Invalid domain for file open.\n" );
00907     return NULL;
00908   }
00909 
00910   if( dvd->isImageFile ) {
00911     return DVDOpenFileUDF( dvd, filename );
00912   } else {
00913     return DVDOpenFilePath( dvd, filename );
00914   }
00915 }
00916 
00917 void DVDCloseFile( dvd_file_t *dvd_file )
00918 {
00919   int i;
00920 
00921   if( dvd_file ) {
00922     if( !dvd_file->dvd->isImageFile ) {
00923       for( i = 0; i < TITLES_MAX; ++i ) {
00924         if( dvd_file->title_devs[ i ] ) {
00925           dvdinput_close( dvd_file->title_devs[i] );
00926         }
00927       }
00928     }
00929 
00930     free( dvd_file );
00931     dvd_file = 0;
00932   }
00933 }
00934 
00935 static int DVDFileStatVOBUDF( dvd_reader_t *dvd, int title,
00936                               int menu, dvd_stat_t *statbuf )
00937 {
00938   char filename[ MAX_UDF_FILE_NAME_LEN ];
00939   uint32_t size;
00940   off_t tot_size;
00941   off_t parts_size[ 9 ];
00942   int nr_parts = 0;
00943   int n;
00944 
00945   if( title == 0 )
00946     sprintf( filename, "/VIDEO_TS/VIDEO_TS.VOB" );
00947   else
00948     sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, menu ? 0 : 1 );
00949 
00950   if( !UDFFindFile( dvd, filename, &size ) )
00951     return -1;
00952 
00953   tot_size = size;
00954   nr_parts = 1;
00955   parts_size[ 0 ] = size;
00956 
00957   if( !menu ) {
00958     int cur;
00959 
00960     for( cur = 2; cur < 10; cur++ ) {
00961       sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, cur );
00962       if( !UDFFindFile( dvd, filename, &size ) )
00963         break;
00964 
00965       parts_size[ nr_parts ] = size;
00966       tot_size += size;
00967       nr_parts++;
00968     }
00969   }
00970 
00971   statbuf->size = tot_size;
00972   statbuf->nr_parts = nr_parts;
00973   for( n = 0; n < nr_parts; n++ )
00974     statbuf->parts_size[ n ] = parts_size[ n ];
00975 
00976   return 0;
00977 }
00978 
00979 
00980 static int DVDFileStatVOBPath( dvd_reader_t *dvd, int title,
00981                                int menu, dvd_stat_t *statbuf )
00982 {
00983   char filename[ MAX_UDF_FILE_NAME_LEN ];
00984   char full_path[ PATH_MAX + 1 ];
00985   struct stat fileinfo;
00986   off_t tot_size;
00987   off_t parts_size[ 9 ];
00988   int nr_parts = 0;
00989   int n;
00990 
00991   if( title == 0 )
00992     sprintf( filename, "VIDEO_TS.VOB" );
00993   else
00994     sprintf( filename, "VTS_%02d_%d.VOB", title, menu ? 0 : 1 );
00995 
00996   if( !findDVDFile( dvd, filename, full_path ) )
00997     return -1;
00998 
00999   if( mythfile_stat( full_path, &fileinfo ) < 0 ) {
01000     fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename );
01001     return -1;
01002   }
01003 
01004   tot_size = fileinfo.st_size;
01005   nr_parts = 1;
01006   parts_size[ 0 ] = fileinfo.st_size;
01007 
01008   if( !menu ) {
01009     int cur;
01010     for( cur = 2; cur < 10; cur++ ) {
01011       sprintf( filename, "VTS_%02d_%d.VOB", title, cur );
01012       if( !findDVDFile( dvd, filename, full_path ) )
01013         break;
01014 
01015       if( mythfile_stat( full_path, &fileinfo ) < 0 ) {
01016         fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename );
01017         break;
01018       }
01019 
01020       parts_size[ nr_parts ] = fileinfo.st_size;
01021       tot_size += parts_size[ nr_parts ];
01022       nr_parts++;
01023     }
01024   }
01025 
01026   statbuf->size = tot_size;
01027   statbuf->nr_parts = nr_parts;
01028   for( n = 0; n < nr_parts; n++ )
01029     statbuf->parts_size[ n ] = parts_size[ n ];
01030 
01031   return 0;
01032 }
01033 
01034 
01035 int DVDFileStat( dvd_reader_t *dvd, int titlenum,
01036                  dvd_read_domain_t domain, dvd_stat_t *statbuf )
01037 {
01038   char filename[ MAX_UDF_FILE_NAME_LEN ];
01039   char full_path[ PATH_MAX + 1 ];
01040   struct stat fileinfo;
01041   uint32_t size;
01042 
01043   /* Check arguments. */
01044   if( dvd == NULL || titlenum < 0 ) {
01045     errno = EINVAL;
01046     return -1;
01047   }
01048 
01049   switch( domain ) {
01050   case DVD_READ_INFO_FILE:
01051     if( titlenum == 0 )
01052       sprintf( filename, "/VIDEO_TS/VIDEO_TS.IFO" );
01053     else
01054       sprintf( filename, "/VIDEO_TS/VTS_%02i_0.IFO", titlenum );
01055 
01056     break;
01057   case DVD_READ_INFO_BACKUP_FILE:
01058     if( titlenum == 0 )
01059       sprintf( filename, "/VIDEO_TS/VIDEO_TS.BUP" );
01060     else
01061       sprintf( filename, "/VIDEO_TS/VTS_%02i_0.BUP", titlenum );
01062 
01063     break;
01064   case DVD_READ_MENU_VOBS:
01065     if( dvd->isImageFile )
01066       return DVDFileStatVOBUDF( dvd, titlenum, 1, statbuf );
01067     else
01068       return DVDFileStatVOBPath( dvd, titlenum, 1, statbuf );
01069 
01070     break;
01071   case DVD_READ_TITLE_VOBS:
01072     if( titlenum == 0 )
01073       return -1;
01074 
01075     if( dvd->isImageFile )
01076       return DVDFileStatVOBUDF( dvd, titlenum, 0, statbuf );
01077     else
01078       return DVDFileStatVOBPath( dvd, titlenum, 0, statbuf );
01079 
01080     break;
01081   default:
01082     fprintf( stderr, "libdvdread: Invalid domain for file stat.\n" );
01083     errno = EINVAL;
01084     return -1;
01085   }
01086 
01087   if( dvd->isImageFile ) {
01088     if( UDFFindFile( dvd, filename, &size ) ) {
01089       statbuf->size = size;
01090       statbuf->nr_parts = 1;
01091       statbuf->parts_size[ 0 ] = size;
01092       return 0;
01093     }
01094   } else {
01095     if( findDVDFile( dvd, filename, full_path ) ) {
01096       if( mythfile_stat( full_path, &fileinfo ) < 0 )
01097         fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename );
01098       else {
01099         statbuf->size = fileinfo.st_size;
01100         statbuf->nr_parts = 1;
01101         statbuf->parts_size[ 0 ] = statbuf->size;
01102         return 0;
01103       }
01104     }
01105   }
01106   return -1;
01107 }
01108 
01109 /* Internal, but used from dvd_udf.c */
01110 int UDFReadBlocksRaw( dvd_reader_t *device, uint32_t lb_number,
01111                       size_t block_count, unsigned char *data,
01112                       int encrypted )
01113 {
01114   int ret;
01115 
01116   if( !device->dev ) {
01117     fprintf( stderr, "libdvdread: Fatal error in block read.\n" );
01118     return 0;
01119   }
01120 
01121   ret = dvdinput_seek( device->dev, (int) lb_number );
01122   if( ret != (int) lb_number ) {
01123     fprintf( stderr, "libdvdread: Can't seek to block %u\n", lb_number );
01124     return 0;
01125   }
01126 
01127   ret = dvdinput_read( device->dev, (char *) data,
01128                        (int) block_count, encrypted );
01129   return ret;
01130 }
01131 
01132 /* This is using a single input and starting from 'dvd_file->lb_start' offset.
01133  *
01134  * Reads 'block_count' blocks from 'dvd_file' at block offset 'offset'
01135  * into the buffer located at 'data' and if 'encrypted' is set
01136  * descramble the data if it's encrypted.  Returning either an
01137  * negative error or the number of blocks read. */
01138 static int DVDReadBlocksUDF( dvd_file_t *dvd_file, uint32_t offset,
01139                              size_t block_count, unsigned char *data,
01140                              int encrypted )
01141 {
01142   return UDFReadBlocksRaw( dvd_file->dvd, dvd_file->lb_start + offset,
01143                            block_count, data, encrypted );
01144 }
01145 
01146 /* This is using possibly several inputs and starting from an offset of '0'.
01147  *
01148  * Reads 'block_count' blocks from 'dvd_file' at block offset 'offset'
01149  * into the buffer located at 'data' and if 'encrypted' is set
01150  * descramble the data if it's encrypted.  Returning either an
01151  * negative error or the number of blocks read. */
01152 static int DVDReadBlocksPath( dvd_file_t *dvd_file, unsigned int offset,
01153                               size_t block_count, unsigned char *data,
01154                               int encrypted )
01155 {
01156   int i;
01157   int ret, ret2, off;
01158 
01159   ret = 0;
01160   ret2 = 0;
01161   for( i = 0; i < TITLES_MAX; ++i ) {
01162     if( !dvd_file->title_sizes[ i ] ) return 0; /* Past end of file */
01163 
01164     if( offset < dvd_file->title_sizes[ i ] ) {
01165       if( ( offset + block_count ) <= dvd_file->title_sizes[ i ] ) {
01166         off = dvdinput_seek( dvd_file->title_devs[ i ], (int)offset );
01167         if( off < 0 || off != (int)offset ) {
01168           fprintf( stderr, "libdvdread: Can't seek to block %d\n",
01169                    offset );
01170           return off < 0 ? off : 0;
01171         }
01172         ret = dvdinput_read( dvd_file->title_devs[ i ], data,
01173                              (int)block_count, encrypted );
01174         break;
01175       } else {
01176         size_t part1_size = dvd_file->title_sizes[ i ] - offset;
01177         /* FIXME: Really needs to be a while loop.
01178          * (This is only true if you try and read >1GB at a time) */
01179 
01180         /* Read part 1 */
01181         off = dvdinput_seek( dvd_file->title_devs[ i ], (int)offset );
01182         if( off < 0 || off != (int)offset ) {
01183           fprintf( stderr, "libdvdread: Can't seek to block %d\n",
01184                    offset );
01185           return off < 0 ? off : 0;
01186         }
01187         ret = dvdinput_read( dvd_file->title_devs[ i ], data,
01188                              (int)part1_size, encrypted );
01189         if( ret < 0 ) return ret;
01190         /* FIXME: This is wrong if i is the last file in the set.
01191          * also error from this read will not show in ret. */
01192 
01193         /* Does the next part exist? If not then return now. */
01194         if( i + 1 >= TITLES_MAX || !dvd_file->title_devs[ i + 1 ] )
01195           return ret;
01196 
01197         /* Read part 2 */
01198         off = dvdinput_seek( dvd_file->title_devs[ i + 1 ], 0 );
01199         if( off < 0 || off != 0 ) {
01200           fprintf( stderr, "libdvdread: Can't seek to block %d\n",
01201                    0 );
01202           return off < 0 ? off : 0;
01203         }
01204         ret2 = dvdinput_read( dvd_file->title_devs[ i + 1 ],
01205                               data + ( part1_size
01206                                        * (int64_t)DVD_VIDEO_LB_LEN ),
01207                               (int)(block_count - part1_size),
01208                               encrypted );
01209         if( ret2 < 0 ) return ret2;
01210         break;
01211       }
01212     } else {
01213       offset -= dvd_file->title_sizes[ i ];
01214     }
01215   }
01216 
01217   return ret + ret2;
01218 }
01219 
01220 /* This is broken reading more than 2Gb at a time is ssize_t is 32-bit. */
01221 ssize_t DVDReadBlocks( dvd_file_t *dvd_file, int offset,
01222                        size_t block_count, unsigned char *data )
01223 {
01224   int ret;
01225 
01226   /* Check arguments. */
01227   if( dvd_file == NULL || offset < 0 || data == NULL )
01228     return -1;
01229 
01230   /* Hack, and it will still fail for multiple opens in a threaded app ! */
01231   if( dvd_file->dvd->css_title != dvd_file->css_title ) {
01232     dvd_file->dvd->css_title = dvd_file->css_title;
01233     if( dvd_file->dvd->isImageFile ) {
01234       dvdinput_title( dvd_file->dvd->dev, (int)dvd_file->lb_start );
01235     }
01236     /* Here each vobu has it's own dvdcss handle, so no need to update
01237     else {
01238       dvdinput_title( dvd_file->title_devs[ 0 ], (int)dvd_file->lb_start );
01239     }*/
01240   }
01241 
01242   if( dvd_file->dvd->isImageFile ) {
01243     ret = DVDReadBlocksUDF( dvd_file, (uint32_t)offset,
01244                             block_count, data, DVDINPUT_READ_DECRYPT );
01245   } else {
01246     ret = DVDReadBlocksPath( dvd_file, (unsigned int)offset,
01247                              block_count, data, DVDINPUT_READ_DECRYPT );
01248   }
01249 
01250   return (ssize_t)ret;
01251 }
01252 
01253 int32_t DVDFileSeek( dvd_file_t *dvd_file, int32_t offset )
01254 {
01255   /* Check arguments. */
01256   if( dvd_file == NULL || offset < 0 )
01257     return -1;
01258 
01259   if( offset > dvd_file->filesize * DVD_VIDEO_LB_LEN ) {
01260     return -1;
01261   }
01262   dvd_file->seek_pos = (uint32_t) offset;
01263   return offset;
01264 }
01265 
01266 int DVDFileSeekForce(dvd_file_t *dvd_file, int offset, int force_size)
01267 {
01268   /* Check arguments. */
01269   if( dvd_file == NULL || offset <= 0 )
01270       return -1;
01271 
01272   if( dvd_file->dvd->isImageFile ) {
01273     if( force_size < 0 )
01274       force_size = (offset - 1) / DVD_VIDEO_LB_LEN + 1;
01275     if( dvd_file->filesize < force_size ) {
01276       dvd_file->filesize = force_size;
01277       fprintf(stderr, "libdvdread: Ignored size of file indicated in UDF.\n");
01278     }
01279   }
01280 
01281   if( offset > dvd_file->filesize * DVD_VIDEO_LB_LEN )
01282     return -1;
01283 
01284   dvd_file->seek_pos = (uint32_t) offset;
01285   return offset;
01286 }
01287 
01288 ssize_t DVDReadBytes( dvd_file_t *dvd_file, void *data, size_t byte_size )
01289 {
01290   unsigned char *secbuf_base, *secbuf;
01291   unsigned int numsec, seek_sector, seek_byte;
01292   int ret;
01293 
01294   /* Check arguments. */
01295   if( dvd_file == NULL || data == NULL )
01296     return -1;
01297 
01298   seek_sector = dvd_file->seek_pos / DVD_VIDEO_LB_LEN;
01299   seek_byte   = dvd_file->seek_pos % DVD_VIDEO_LB_LEN;
01300 
01301   numsec = ( ( seek_byte + byte_size ) / DVD_VIDEO_LB_LEN ) +
01302     ( ( ( seek_byte + byte_size ) % DVD_VIDEO_LB_LEN ) ? 1 : 0 );
01303 
01304   secbuf_base = (unsigned char *) malloc( numsec * DVD_VIDEO_LB_LEN + 2048 );
01305   secbuf = (unsigned char *)(((uintptr_t)secbuf_base & ~((uintptr_t)2047)) + 2048);
01306   if( !secbuf_base ) {
01307     fprintf( stderr, "libdvdread: Can't allocate memory "
01308              "for file read!\n" );
01309     return 0;
01310   }
01311 
01312   if( dvd_file->dvd->isImageFile ) {
01313     ret = DVDReadBlocksUDF( dvd_file, (uint32_t) seek_sector,
01314                             (size_t) numsec, secbuf, DVDINPUT_NOFLAGS );
01315   } else {
01316     ret = DVDReadBlocksPath( dvd_file, seek_sector,
01317                              (size_t) numsec, secbuf, DVDINPUT_NOFLAGS );
01318   }
01319 
01320   if( ret != (int) numsec ) {
01321     free( secbuf_base );
01322     return ret < 0 ? ret : 0;
01323   }
01324 
01325   memcpy( data, &(secbuf[ seek_byte ]), byte_size );
01326   free( secbuf_base );
01327 
01328   DVDFileSeekForce(dvd_file, dvd_file->seek_pos + byte_size, -1);
01329   return byte_size;
01330 }
01331 
01332 ssize_t DVDFileSize( dvd_file_t *dvd_file )
01333 {
01334   /* Check arguments. */
01335   if( dvd_file == NULL )
01336     return -1;
01337 
01338   return dvd_file->filesize;
01339 }
01340 
01341 int DVDDiscID( dvd_reader_t *dvd, unsigned char *discid )
01342 {
01343   struct md5_ctx ctx;
01344   int title;
01345   int nr_of_files = 0;
01346 
01347   /* Check arguments. */
01348   if( dvd == NULL || discid == NULL )
01349     return 0;
01350 
01351   /* Go through the first 10 IFO:s, in order,
01352    * and md5sum them, i.e  VIDEO_TS.IFO and VTS_0?_0.IFO */
01353   md5_init_ctx( &ctx );
01354   for( title = 0; title < 10; title++ ) {
01355     dvd_file_t *dvd_file = DVDOpenFile( dvd, title, DVD_READ_INFO_FILE );
01356     if( dvd_file != NULL ) {
01357       ssize_t bytes_read;
01358       size_t file_size = dvd_file->filesize * DVD_VIDEO_LB_LEN;
01359       char *buffer_base = malloc( file_size + 2048 );
01360       char *buffer = (char *)(((uintptr_t)buffer_base & ~((uintptr_t)2047)) + 2048);
01361 
01362       if( buffer_base == NULL ) {
01363           DVDCloseFile( dvd_file );
01364           fprintf( stderr, "libdvdread: DVDDiscId, failed to "
01365                    "allocate memory for file read!\n" );
01366           return -1;
01367       }
01368 
01369       bytes_read = DVDReadBytes( dvd_file, buffer, file_size );
01370       if( bytes_read != file_size ) {
01371           fprintf( stderr, "libdvdread: DVDDiscId read returned %zd bytes"
01372                    ", wanted %zd\n", bytes_read, file_size );
01373           DVDCloseFile( dvd_file );
01374           free( buffer_base );
01375           return -1;
01376       }
01377 
01378       md5_process_bytes( buffer, file_size,  &ctx );
01379 
01380       DVDCloseFile( dvd_file );
01381       free( buffer_base );
01382       nr_of_files++;
01383     }
01384   }
01385   md5_finish_ctx( &ctx, discid );
01386   if(!nr_of_files)
01387     return -1;
01388 
01389   return 0;
01390 }
01391 
01392 
01393 int DVDISOVolumeInfo( dvd_reader_t *dvd,
01394                       char *volid, unsigned int volid_size,
01395                       unsigned char *volsetid, unsigned int volsetid_size )
01396 {
01397   unsigned char *buffer, *buffer_base;
01398   int ret;
01399 
01400   /* Check arguments. */
01401   if( dvd == NULL )
01402     return 0;
01403 
01404   if( dvd->dev == NULL ) {
01405     /* No block access, so no ISO... */
01406     return -1;
01407   }
01408 
01409   buffer_base = malloc( DVD_VIDEO_LB_LEN + 2048 );
01410   buffer = (unsigned char *)(((uintptr_t)buffer_base & ~((uintptr_t)2047)) + 2048);
01411 
01412   if( buffer_base == NULL ) {
01413     fprintf( stderr, "libdvdread: DVDISOVolumeInfo, failed to "
01414              "allocate memory for file read!\n" );
01415     return -1;
01416   }
01417 
01418   ret = UDFReadBlocksRaw( dvd, 16, 1, buffer, 0 );
01419   if( ret != 1 ) {
01420     fprintf( stderr, "libdvdread: DVDISOVolumeInfo, failed to "
01421              "read ISO9660 Primary Volume Descriptor!\n" );
01422     free( buffer_base );
01423     return -1;
01424   }
01425 
01426   if( (volid != NULL) && (volid_size > 0) ) {
01427     unsigned int n;
01428     for(n = 0; n < 32; n++) {
01429       if(buffer[40+n] == 0x20) {
01430         break;
01431       }
01432     }
01433 
01434     if(volid_size > n+1) {
01435       volid_size = n+1;
01436     }
01437 
01438     memcpy(volid, &buffer[40], volid_size-1);
01439     volid[volid_size-1] = '\0';
01440   }
01441 
01442   if( (volsetid != NULL) && (volsetid_size > 0) ) {
01443     if(volsetid_size > 128) {
01444       volsetid_size = 128;
01445     }
01446     memcpy(volsetid, &buffer[190], volsetid_size);
01447   }
01448   free( buffer_base );
01449   return 0;
01450 }
01451 
01452 
01453 int DVDUDFVolumeInfo( dvd_reader_t *dvd,
01454                       char *volid, unsigned int volid_size,
01455                       unsigned char *volsetid, unsigned int volsetid_size )
01456 {
01457   int ret;
01458   /* Check arguments. */
01459   if( dvd == NULL )
01460     return -1;
01461 
01462   if( dvd->dev == NULL ) {
01463     /* No block access, so no UDF VolumeSet Identifier */
01464     return -1;
01465   }
01466 
01467   if( (volid != NULL) && (volid_size > 0) ) {
01468     ret = UDFGetVolumeIdentifier(dvd, volid, volid_size);
01469     if(!ret) {
01470       return -1;
01471     }
01472   }
01473   if( (volsetid != NULL) && (volsetid_size > 0) ) {
01474     ret =  UDFGetVolumeSetIdentifier(dvd, volsetid, volsetid_size);
01475     if(!ret) {
01476       return -1;
01477     }
01478   }
01479 
01480   return 0;
01481 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends