|
MythTV
0.26-pre
|
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 }
1.7.6.1