2 * Copyright (C) 2001, 2002, 2003 Billy Biggs <vektor@dumbterm.net>,
3 * Håkan Hjort <d95hjort@dtek.chalmers.se>,
4 * Björn Englund <d4bjorn@dtek.chalmers.se>
6 * Modified for use with MPlayer, changes contained in libdvdread_changes.diff.
7 * detailed changelog at http://svn.mplayerhq.hu/mplayer/trunk/
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or (at
13 * your option) any later version.
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
27 #include <sys/types.h>
29 #include <sys/time.h> /* For the timing of dvdcss_title crack. */
39 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__bsdi__)|| defined(__DARWIN__) || defined(__DragonFly__)
44 #include <sys/mnttab.h>
46 #include </usr/conf/h/mnttab.h>
47 #elif defined(SYS_BSD)
49 #elif defined(__linux__) || defined(__CYGWIN__)
53 #if defined(__MINGW32__) && (__MINGW32_MAJOR_VERSION <= 3) && (__MINGW32_MINOR_VERSION < 10)
54 #include <sys/timeb.h>
55 static void gettimeofday(struct timeval
* t
,void* timezone
){
56 struct timeb timebuffer
;
58 t
->tv_sec
=timebuffer
.time
;
59 t
->tv_usec
=1000*timebuffer
.millitm
;
64 #include "dvd_input.h"
65 #include "dvd_reader.h"
68 #define DEFAULT_UDF_CACHE_LEVEL 0
71 /* Basic information. */
74 /* Hack for keeping track of the css status.
75 * 0: no css, 1: perhaps (need init of keys), 2: have done init */
77 int css_title
; /* Last title that we have called dvdinpute_title for. */
79 /* Information required for an image file. */
82 /* Information required for a directory path drive. */
85 /* Filesystem cache */
86 int udfcache_level
; /* 0 - turned off, 1 - on */
91 /* Basic information. */
94 /* Hack for selecting the right css title. */
97 /* Information required for an image file. */
101 /* Information required for a directory path drive. */
102 size_t title_sizes
[ 9 ];
103 dvd_input_t title_devs
[ 9 ];
105 /* Calculated at open-time, size in blocks. */
110 * Set the level of caching on udf
111 * level = 0 (no caching)
112 * level = 1 (caching filesystem info)
114 int DVDUDFCacheLevel(dvd_reader_t
*device
, int level
)
116 struct dvd_reader_s
*dev
= (struct dvd_reader_s
*)device
;
120 } else if(level
< 0) {
121 return dev
->udfcache_level
;
124 dev
->udfcache_level
= level
;
129 void *GetUDFCacheHandle(dvd_reader_t
*device
)
131 struct dvd_reader_s
*dev
= (struct dvd_reader_s
*)device
;
133 return dev
->udfcache
;
136 void SetUDFCacheHandle(dvd_reader_t
*device
, void *cache
)
138 struct dvd_reader_s
*dev
= (struct dvd_reader_s
*)device
;
140 dev
->udfcache
= cache
;
145 /* Loop over all titles and call dvdcss_title to crack the keys. */
146 static int initAllCSSKeys( dvd_reader_t
*dvd
)
148 struct timeval all_s
, all_e
;
149 struct timeval t_s
, t_e
;
150 char filename
[ MAX_UDF_FILE_NAME_LEN
];
154 char *nokeys_str
= getenv("DVDREAD_NOKEYS");
155 if(nokeys_str
!= NULL
)
158 fprintf( stderr
, "\n" );
159 fprintf( stderr
, "libdvdread: Attempting to retrieve all CSS keys\n" );
160 fprintf( stderr
, "libdvdread: This can take a _long_ time, "
161 "please be patient\n\n" );
163 gettimeofday(&all_s
, NULL
);
165 for( title
= 0; title
< 100; title
++ ) {
166 gettimeofday( &t_s
, NULL
);
168 sprintf( filename
, "/VIDEO_TS/VIDEO_TS.VOB" );
170 sprintf( filename
, "/VIDEO_TS/VTS_%02d_%d.VOB", title
, 0 );
172 start
= UDFFindFile( dvd
, filename
, &len
);
173 if( start
!= 0 && len
!= 0 ) {
174 /* Perform CSS key cracking for this title. */
175 fprintf( stderr
, "libdvdread: Get key for %s at 0x%08x\n",
177 if( dvdinput_title( dvd
->dev
, (int)start
) < 0 ) {
178 fprintf( stderr
, "libdvdread: Error cracking CSS key for %s (0x%08x)\n", filename
, start
);
180 gettimeofday( &t_e
, NULL
);
181 fprintf( stderr
, "libdvdread: Elapsed time %ld\n",
182 (long int) t_e
.tv_sec
- t_s
.tv_sec
);
185 if( title
== 0 ) continue;
187 gettimeofday( &t_s
, NULL
);
188 sprintf( filename
, "/VIDEO_TS/VTS_%02d_%d.VOB", title
, 1 );
189 start
= UDFFindFile( dvd
, filename
, &len
);
190 if( start
== 0 || len
== 0 ) break;
192 /* Perform CSS key cracking for this title. */
193 fprintf( stderr
, "libdvdread: Get key for %s at 0x%08x\n",
195 if( dvdinput_title( dvd
->dev
, (int)start
) < 0 ) {
196 fprintf( stderr
, "libdvdread: Error cracking CSS key for %s (0x%08x)!!\n", filename
, start
);
198 gettimeofday( &t_e
, NULL
);
199 fprintf( stderr
, "libdvdread: Elapsed time %ld\n",
200 (long int) t_e
.tv_sec
- t_s
.tv_sec
);
204 fprintf( stderr
, "libdvdread: Found %d VTS's\n", title
);
205 gettimeofday(&all_e
, NULL
);
206 fprintf( stderr
, "libdvdread: Elapsed time %ld\n",
207 (long int) all_e
.tv_sec
- all_s
.tv_sec
);
215 * Open a DVD image or block device file.
217 static dvd_reader_t
*DVDOpenImageFile( const char *location
, int have_css
)
222 dev
= dvdinput_open( location
);
224 fprintf( stderr
, "libdvdread: Can't open %s for reading\n", location
);
228 dvd
= (dvd_reader_t
*) malloc( sizeof( dvd_reader_t
) );
230 dvd
->isImageFile
= 1;
234 dvd
->udfcache_level
= DEFAULT_UDF_CACHE_LEVEL
;
235 dvd
->udfcache
= NULL
;
238 /* Only if DVDCSS_METHOD = title, a bit if it's disc or if
239 * DVDCSS_METHOD = key but region missmatch. Unfortunaly we
240 * don't have that information. */
242 dvd
->css_state
= 1; /* Need key init. */
249 static dvd_reader_t
*DVDOpenPath( const char *path_root
)
253 dvd
= (dvd_reader_t
*) malloc( sizeof( dvd_reader_t
) );
255 dvd
->isImageFile
= 0;
257 dvd
->path_root
= strdup( path_root
);
259 dvd
->udfcache_level
= DEFAULT_UDF_CACHE_LEVEL
;
260 dvd
->udfcache
= NULL
;
262 dvd
->css_state
= 0; /* Only used in the UDF path */
263 dvd
->css_title
= 0; /* Only matters in the UDF path */
269 /* /dev/rdsk/c0t6d0s0 (link to /devices/...)
270 /vol/dev/rdsk/c0t6d0/??
272 static char *sun_block2char( const char *path
)
276 /* Must contain "/dsk/" */
277 if( !strstr( path
, "/dsk/" ) ) return (char *) strdup( path
);
279 /* Replace "/dsk/" with "/rdsk/" */
280 new_path
= malloc( strlen(path
) + 2 );
281 strcpy( new_path
, path
);
282 strcpy( strstr( new_path
, "/dsk/" ), "" );
283 strcat( new_path
, "/rdsk/" );
284 strcat( new_path
, strstr( path
, "/dsk/" ) + strlen( "/dsk/" ) );
291 /* FreeBSD /dev/(r)(a)cd0c (a is for atapi), recomended to _not_ use r
292 OpenBSD /dev/rcd0c, it needs to be the raw device
293 NetBSD /dev/rcd0[d|c|..] d for x86, c (for non x86), perhaps others
294 Darwin /dev/rdisk0, it needs to be the raw device
295 BSD/OS /dev/sr0c (if not mounted) or /dev/rsr0c ('c' any letter will do) */
296 static char *bsd_block2char( const char *path
)
297 #if defined(__FreeBSD__)
299 return (char *) strdup( path
);
305 /* If it doesn't start with "/dev/" or does start with "/dev/r" exit */
306 if( strncmp( path
, "/dev/", 5 ) || !strncmp( path
, "/dev/r", 6 ) )
307 return (char *) strdup( path
);
309 /* Replace "/dev/" with "/dev/r" */
310 new_path
= malloc( strlen(path
) + 2 );
311 strcpy( new_path
, "/dev/r" );
312 strcat( new_path
, path
+ strlen( "/dev/" ) );
316 #endif /* __FreeBSD__ */
319 dvd_reader_t
*DVDOpen( const char *path
)
321 struct stat fileinfo
;
329 /* Stat doesn't work on devices under mingwin/cygwin. */
330 if( path
[0] && path
[1] == ':' && path
[2] == '\0' )
332 /* Don't try to stat the file */
333 fileinfo
.st_mode
= S_IFBLK
;
338 ret
= stat( path
, &fileinfo
);
340 /* If we can't stat the file, give up */
341 fprintf( stderr
, "libdvdread: Can't stat %s\n", path
);
347 /* Try to open libdvdcss or fall back to standard functions */
348 have_css
= dvdinput_setup();
350 /* First check if this is a block/char device or a file*/
351 if( S_ISBLK( fileinfo
.st_mode
) ||
352 S_ISCHR( fileinfo
.st_mode
) ||
353 S_ISREG( fileinfo
.st_mode
) ) {
356 * Block devices and regular files are assumed to be DVD-Video images.
359 return DVDOpenImageFile( sun_block2char( path
), have_css
);
360 #elif defined(SYS_BSD)
361 return DVDOpenImageFile( bsd_block2char( path
), have_css
);
363 return DVDOpenImageFile( path
, have_css
);
366 } else if( S_ISDIR( fileinfo
.st_mode
) ) {
367 dvd_reader_t
*auth_drive
= 0;
371 #elif defined(__sun) || defined(__linux__) || defined(__CYGWIN__)
375 /* XXX: We should scream real loud here. */
376 if( !(path_copy
= strdup( path
) ) ) return 0;
378 /* Resolve any symlinks and get the absolut dir name. */
381 int cdir
= open( ".", O_RDONLY
);
385 new_path
= getcwd( NULL
, PATH_MAX
);
392 path_copy
= new_path
;
398 * If we're being asked to open a directory, check if that directory
399 * is the mountpoint for a DVD-ROM which we can use instead.
402 if( strlen( path_copy
) > 1 ) {
403 if( path_copy
[ strlen( path_copy
) - 1 ] == '/' )
404 path_copy
[ strlen( path_copy
) - 1 ] = '\0';
407 if( strlen( path_copy
) > 9 ) {
408 if( !strcasecmp( &(path_copy
[ strlen( path_copy
) - 9 ]),
410 path_copy
[ strlen( path_copy
) - 9 ] = '\0';
415 if( ( fe
= getfsfile( path_copy
) ) ) {
416 dev_name
= bsd_block2char( fe
->fs_spec
);
418 "libdvdread: Attempting to use device %s"
419 " mounted on %s for CSS authentication\n",
422 auth_drive
= DVDOpenImageFile( dev_name
, have_css
);
425 mntfile
= fopen( MNTTAB
, "r" );
430 while( ( res
= getmntent( mntfile
, &mp
) ) != -1 ) {
431 if( res
== 0 && !strcmp( mp
.mnt_mountp
, path_copy
) ) {
432 dev_name
= sun_block2char( mp
.mnt_special
);
434 "libdvdread: Attempting to use device %s"
435 " mounted on %s for CSS authentication\n",
438 auth_drive
= DVDOpenImageFile( dev_name
, have_css
);
444 #elif defined(__linux__) || defined(__CYGWIN__)
445 mntfile
= fopen( MOUNTED
, "r" );
449 while( ( me
= getmntent( mntfile
) ) ) {
450 if( !strcmp( me
->mnt_dir
, path_copy
) ) {
452 "libdvdread: Attempting to use device %s"
453 " mounted on %s for CSS authentication\n",
456 auth_drive
= DVDOpenImageFile( me
->mnt_fsname
, have_css
);
457 dev_name
= strdup(me
->mnt_fsname
);
463 #elif defined(__MINGW32__)
464 dev_name
= strdup(path
);
465 auth_drive
= DVDOpenImageFile( path
, have_css
);
468 fprintf( stderr
, "libdvdread: Couldn't find device name.\n" );
469 } else if( !auth_drive
) {
470 fprintf( stderr
, "libdvdread: Device %s inaccessible, "
471 "CSS authentication not available.\n", dev_name
);
478 * If we've opened a drive, just use that.
480 if( auth_drive
) return auth_drive
;
483 * Otherwise, we now try to open the directory tree instead.
485 return DVDOpenPath( path
);
488 /* If it's none of the above, screw it. */
489 fprintf( stderr
, "libdvdread: Could not open %s\n", path
);
493 void DVDClose( dvd_reader_t
*dvd
)
496 if( dvd
->dev
) dvdinput_close( dvd
->dev
);
497 if( dvd
->path_root
) free( dvd
->path_root
);
498 if( dvd
->udfcache
) FreeUDFCache( dvd
->udfcache
);
504 * Open an unencrypted file on a DVD image file.
506 static dvd_file_t
*DVDOpenFileUDF( dvd_reader_t
*dvd
, char *filename
)
509 dvd_file_t
*dvd_file
;
511 start
= UDFFindFile( dvd
, filename
, &len
);
512 if( !start
) return 0;
514 dvd_file
= (dvd_file_t
*) malloc( sizeof( dvd_file_t
) );
515 if( !dvd_file
) return 0;
517 dvd_file
->lb_start
= start
;
518 dvd_file
->seek_pos
= 0;
519 memset( dvd_file
->title_sizes
, 0, sizeof( dvd_file
->title_sizes
) );
520 memset( dvd_file
->title_devs
, 0, sizeof( dvd_file
->title_devs
) );
521 dvd_file
->filesize
= len
/ DVD_VIDEO_LB_LEN
;
527 * Searches for <file> in directory <path>, ignoring case.
528 * Returns 0 and full filename in <filename>.
529 * or -1 on file not found.
530 * or -2 on path not found.
532 static int findDirFile( const char *path
, const char *file
, char *filename
)
537 dir
= opendir( path
);
538 if( !dir
) return -2;
540 while( ( ent
= readdir( dir
) ) != NULL
) {
541 if( !strcasecmp( ent
->d_name
, file
) ) {
542 sprintf( filename
, "%s%s%s", path
,
543 ( ( path
[ strlen( path
) - 1 ] == '/' ) ? "" : "/" ),
552 static int findDVDFile( dvd_reader_t
*dvd
, const char *file
, char *filename
)
554 char video_path
[ PATH_MAX
+ 1 ];
555 const char *nodirfile
;
558 /* Strip off the directory for our search */
559 if( !strncasecmp( "/VIDEO_TS/", file
, 10 ) ) {
560 nodirfile
= &(file
[ 10 ]);
565 ret
= findDirFile( dvd
->path_root
, nodirfile
, filename
);
567 /* Try also with adding the path, just in case. */
568 sprintf( video_path
, "%s/VIDEO_TS/", dvd
->path_root
);
569 ret
= findDirFile( video_path
, nodirfile
, filename
);
571 /* Try with the path, but in lower case. */
572 sprintf( video_path
, "%s/video_ts/", dvd
->path_root
);
573 ret
= findDirFile( video_path
, nodirfile
, filename
);
584 * Open an unencrypted file from a DVD directory tree.
586 static dvd_file_t
*DVDOpenFilePath( dvd_reader_t
*dvd
, char *filename
)
588 char full_path
[ PATH_MAX
+ 1 ];
589 dvd_file_t
*dvd_file
;
590 struct stat fileinfo
;
593 /* Get the full path of the file. */
594 if( !findDVDFile( dvd
, filename
, full_path
) ) return 0;
596 dev
= dvdinput_open( full_path
);
599 dvd_file
= (dvd_file_t
*) malloc( sizeof( dvd_file_t
) );
600 if( !dvd_file
) return 0;
602 dvd_file
->lb_start
= 0;
603 dvd_file
->seek_pos
= 0;
604 memset( dvd_file
->title_sizes
, 0, sizeof( dvd_file
->title_sizes
) );
605 memset( dvd_file
->title_devs
, 0, sizeof( dvd_file
->title_devs
) );
606 dvd_file
->filesize
= 0;
608 if( stat( full_path
, &fileinfo
) < 0 ) {
609 fprintf( stderr
, "libdvdread: Can't stat() %s.\n", filename
);
613 dvd_file
->title_sizes
[ 0 ] = fileinfo
.st_size
/ DVD_VIDEO_LB_LEN
;
614 dvd_file
->title_devs
[ 0 ] = dev
;
615 dvd_file
->filesize
= dvd_file
->title_sizes
[ 0 ];
620 static dvd_file_t
*DVDOpenVOBUDF( dvd_reader_t
*dvd
, int title
, int menu
)
622 char filename
[ MAX_UDF_FILE_NAME_LEN
];
624 dvd_file_t
*dvd_file
;
627 sprintf( filename
, "/VIDEO_TS/VIDEO_TS.VOB" );
629 sprintf( filename
, "/VIDEO_TS/VTS_%02d_%d.VOB", title
, menu
? 0 : 1 );
631 start
= UDFFindFile( dvd
, filename
, &len
);
632 if( start
== 0 ) return 0;
634 dvd_file
= (dvd_file_t
*) malloc( sizeof( dvd_file_t
) );
635 if( !dvd_file
) return 0;
637 /*Hack*/ dvd_file
->css_title
= title
<< 1 | menu
;
638 dvd_file
->lb_start
= start
;
639 dvd_file
->seek_pos
= 0;
640 memset( dvd_file
->title_sizes
, 0, sizeof( dvd_file
->title_sizes
) );
641 memset( dvd_file
->title_devs
, 0, sizeof( dvd_file
->title_devs
) );
642 dvd_file
->filesize
= len
/ DVD_VIDEO_LB_LEN
;
644 /* Calculate the complete file size for every file in the VOBS */
648 for( cur
= 2; cur
< 10; cur
++ ) {
649 sprintf( filename
, "/VIDEO_TS/VTS_%02d_%d.VOB", title
, cur
);
650 if( !UDFFindFile( dvd
, filename
, &len
) ) break;
651 dvd_file
->filesize
+= len
/ DVD_VIDEO_LB_LEN
;
655 if( dvd
->css_state
== 1 /* Need key init */ ) {
656 // initAllCSSKeys( dvd );
657 // dvd->css_state = 2;
660 if( dvdinput_title( dvd_file->dvd->dev, (int)start ) < 0 ) {
661 fprintf( stderr, "libdvdread: Error cracking CSS key for %s\n",
669 static dvd_file_t
*DVDOpenVOBPath( dvd_reader_t
*dvd
, int title
, int menu
)
671 char filename
[ MAX_UDF_FILE_NAME_LEN
];
672 char full_path
[ PATH_MAX
+ 1 ];
673 struct stat fileinfo
;
674 dvd_file_t
*dvd_file
;
677 dvd_file
= (dvd_file_t
*) malloc( sizeof( dvd_file_t
) );
678 if( !dvd_file
) return 0;
680 /*Hack*/ dvd_file
->css_title
= title
<< 1 | menu
;
681 dvd_file
->lb_start
= 0;
682 dvd_file
->seek_pos
= 0;
683 memset( dvd_file
->title_sizes
, 0, sizeof( dvd_file
->title_sizes
) );
684 memset( dvd_file
->title_devs
, 0, sizeof( dvd_file
->title_devs
) );
685 dvd_file
->filesize
= 0;
691 sprintf( filename
, "VIDEO_TS.VOB" );
693 sprintf( filename
, "VTS_%02i_0.VOB", title
);
695 if( !findDVDFile( dvd
, filename
, full_path
) ) {
700 dev
= dvdinput_open( full_path
);
706 if( stat( full_path
, &fileinfo
) < 0 ) {
707 fprintf( stderr
, "libdvdread: Can't stat() %s.\n", filename
);
711 dvd_file
->title_sizes
[ 0 ] = fileinfo
.st_size
/ DVD_VIDEO_LB_LEN
;
712 dvd_file
->title_devs
[ 0 ] = dev
;
713 dvdinput_title( dvd_file
->title_devs
[0], 0);
714 dvd_file
->filesize
= dvd_file
->title_sizes
[ 0 ];
717 for( i
= 0; i
< 9; ++i
) {
719 sprintf( filename
, "VTS_%02i_%i.VOB", title
, i
+ 1 );
720 if( !findDVDFile( dvd
, filename
, full_path
) ) {
724 if( stat( full_path
, &fileinfo
) < 0 ) {
725 fprintf( stderr
, "libdvdread: Can't stat() %s.\n", filename
);
729 dvd_file
->title_sizes
[ i
] = fileinfo
.st_size
/ DVD_VIDEO_LB_LEN
;
730 dvd_file
->title_devs
[ i
] = dvdinput_open( full_path
);
731 dvdinput_title( dvd_file
->title_devs
[ i
], 0 );
732 dvd_file
->filesize
+= dvd_file
->title_sizes
[ i
];
734 if( !dvd_file
->title_devs
[ 0 ] ) {
743 dvd_file_t
*DVDOpenFile( dvd_reader_t
*dvd
, int titlenum
,
744 dvd_read_domain_t domain
)
746 char filename
[ MAX_UDF_FILE_NAME_LEN
];
748 /* Check arguments. */
749 if( dvd
== NULL
|| titlenum
< 0 )
753 case DVD_READ_INFO_FILE
:
754 if( titlenum
== 0 ) {
755 sprintf( filename
, "/VIDEO_TS/VIDEO_TS.IFO" );
757 sprintf( filename
, "/VIDEO_TS/VTS_%02i_0.IFO", titlenum
);
760 case DVD_READ_INFO_BACKUP_FILE
:
761 if( titlenum
== 0 ) {
762 sprintf( filename
, "/VIDEO_TS/VIDEO_TS.BUP" );
764 sprintf( filename
, "/VIDEO_TS/VTS_%02i_0.BUP", titlenum
);
767 case DVD_READ_MENU_VOBS
:
768 if( dvd
->isImageFile
) {
769 return DVDOpenVOBUDF( dvd
, titlenum
, 1 );
771 return DVDOpenVOBPath( dvd
, titlenum
, 1 );
774 case DVD_READ_TITLE_VOBS
:
775 if( titlenum
== 0 ) return 0;
776 if( dvd
->isImageFile
) {
777 return DVDOpenVOBUDF( dvd
, titlenum
, 0 );
779 return DVDOpenVOBPath( dvd
, titlenum
, 0 );
783 fprintf( stderr
, "libdvdread: Invalid domain for file open.\n" );
787 if( dvd
->isImageFile
) {
788 return DVDOpenFileUDF( dvd
, filename
);
790 return DVDOpenFilePath( dvd
, filename
);
794 void DVDCloseFile( dvd_file_t
*dvd_file
)
799 if( dvd_file
->dvd
->isImageFile
) {
802 for( i
= 0; i
< 9; ++i
) {
803 if( dvd_file
->title_devs
[ i
] ) {
804 dvdinput_close( dvd_file
->title_devs
[i
] );
814 /* Internal, but used from dvd_udf.c */
815 int UDFReadBlocksRaw( dvd_reader_t
*device
, uint32_t lb_number
,
816 size_t block_count
, unsigned char *data
,
822 fprintf( stderr
, "libdvdread: Fatal error in block read.\n" );
826 ret
= dvdinput_seek( device
->dev
, (int) lb_number
);
827 if( ret
!= (int) lb_number
) {
828 fprintf( stderr
, "libdvdread: Can't seek to block %u\n", lb_number
);
832 return dvdinput_read( device
->dev
, (char *) data
,
833 (int) block_count
, encrypted
);
836 /* This is using a single input and starting from 'dvd_file->lb_start' offset.
838 * Reads 'block_count' blocks from 'dvd_file' at block offset 'offset'
839 * into the buffer located at 'data' and if 'encrypted' is set
840 * descramble the data if it's encrypted. Returning either an
841 * negative error or the number of blocks read. */
842 static int DVDReadBlocksUDF( dvd_file_t
*dvd_file
, uint32_t offset
,
843 size_t block_count
, unsigned char *data
,
846 return UDFReadBlocksRaw( dvd_file
->dvd
, dvd_file
->lb_start
+ offset
,
847 block_count
, data
, encrypted
);
850 /* This is using possibly several inputs and starting from an offset of '0'.
852 * Reads 'block_count' blocks from 'dvd_file' at block offset 'offset'
853 * into the buffer located at 'data' and if 'encrypted' is set
854 * descramble the data if it's encrypted. Returning either an
855 * negative error or the number of blocks read. */
856 static int DVDReadBlocksPath( dvd_file_t
*dvd_file
, unsigned int offset
,
857 size_t block_count
, unsigned char *data
,
865 for( i
= 0; i
< 9; ++i
) {
866 if( !dvd_file
->title_sizes
[ i
] ) return 0; /* Past end of file */
868 if( offset
< dvd_file
->title_sizes
[ i
] ) {
869 if( ( offset
+ block_count
) <= dvd_file
->title_sizes
[ i
] ) {
870 off
= dvdinput_seek( dvd_file
->title_devs
[ i
], (int)offset
);
871 if( off
< 0 || off
!= (int)offset
) {
872 fprintf( stderr
, "libdvdread: Can't seek to block %d\n",
874 return off
< 0 ? off
: 0;
876 ret
= dvdinput_read( dvd_file
->title_devs
[ i
], data
,
877 (int)block_count
, encrypted
);
880 size_t part1_size
= dvd_file
->title_sizes
[ i
] - offset
;
881 /* FIXME: Really needs to be a while loop.
882 * (This is only true if you try and read >1GB at a time) */
885 off
= dvdinput_seek( dvd_file
->title_devs
[ i
], (int)offset
);
886 if( off
< 0 || off
!= (int)offset
) {
887 fprintf( stderr
, "libdvdread: Can't seek to block %d\n",
889 return off
< 0 ? off
: 0;
891 ret
= dvdinput_read( dvd_file
->title_devs
[ i
], data
,
892 (int)part1_size
, encrypted
);
893 if( ret
< 0 ) return ret
;
894 /* FIXME: This is wrong if i is the last file in the set.
895 * also error from this read will not show in ret. */
897 /* Does the next part exist? If not then return now. */
898 if( !dvd_file
->title_devs
[ i
+ 1 ] ) return ret
;
901 off
= dvdinput_seek( dvd_file
->title_devs
[ i
+ 1 ], 0 );
902 if( off
< 0 || off
!= 0 ) {
903 fprintf( stderr
, "libdvdread: Can't seek to block %d\n",
905 return off
< 0 ? off
: 0;
907 ret2
= dvdinput_read( dvd_file
->title_devs
[ i
+ 1 ],
909 * (int64_t)DVD_VIDEO_LB_LEN
),
910 (int)(block_count
- part1_size
),
912 if( ret2
< 0 ) return ret2
;
916 offset
-= dvd_file
->title_sizes
[ i
];
923 /* This is broken reading more than 2Gb at a time is ssize_t is 32-bit. */
924 ssize_t
DVDReadBlocks( dvd_file_t
*dvd_file
, int offset
,
925 size_t block_count
, unsigned char *data
)
929 /* Check arguments. */
930 if( dvd_file
== NULL
|| offset
< 0 || data
== NULL
)
933 /* Hack, and it will still fail for multiple opens in a threaded app ! */
934 if( dvd_file
->dvd
->css_title
!= dvd_file
->css_title
) {
935 dvd_file
->dvd
->css_title
= dvd_file
->css_title
;
936 if( dvd_file
->dvd
->isImageFile
) {
937 dvdinput_title( dvd_file
->dvd
->dev
, (int)dvd_file
->lb_start
);
939 /* Here each vobu has it's own dvdcss handle, so no need to update
941 dvdinput_title( dvd_file->title_devs[ 0 ], (int)dvd_file->lb_start );
945 if( dvd_file
->dvd
->isImageFile
) {
946 ret
= DVDReadBlocksUDF( dvd_file
, (uint32_t)offset
,
947 block_count
, data
, DVDINPUT_READ_DECRYPT
);
949 ret
= DVDReadBlocksPath( dvd_file
, (unsigned int)offset
,
950 block_count
, data
, DVDINPUT_READ_DECRYPT
);
956 int DVDFileSeek( dvd_file_t
*dvd_file
, int offset
)
958 /* Check arguments. */
959 if( dvd_file
== NULL
|| offset
< 0 )
962 if( offset
> dvd_file
->filesize
* DVD_VIDEO_LB_LEN
) {
965 dvd_file
->seek_pos
= (uint32_t) offset
;
969 ssize_t
DVDReadBytes( dvd_file_t
*dvd_file
, void *data
, size_t byte_size
)
971 unsigned char *secbuf
;
972 unsigned int numsec
, seek_sector
, seek_byte
;
975 /* Check arguments. */
976 if( dvd_file
== NULL
|| data
== NULL
)
979 seek_sector
= dvd_file
->seek_pos
/ DVD_VIDEO_LB_LEN
;
980 seek_byte
= dvd_file
->seek_pos
% DVD_VIDEO_LB_LEN
;
982 numsec
= ( ( seek_byte
+ byte_size
) / DVD_VIDEO_LB_LEN
) +
983 ( ( ( seek_byte
+ byte_size
) % DVD_VIDEO_LB_LEN
) ? 1 : 0 );
985 secbuf
= (unsigned char *) malloc( numsec
* DVD_VIDEO_LB_LEN
);
987 fprintf( stderr
, "libdvdread: Can't allocate memory "
988 "for file read!\n" );
992 if( dvd_file
->dvd
->isImageFile
) {
993 ret
= DVDReadBlocksUDF( dvd_file
, (uint32_t) seek_sector
,
994 (size_t) numsec
, secbuf
, DVDINPUT_NOFLAGS
);
996 ret
= DVDReadBlocksPath( dvd_file
, seek_sector
,
997 (size_t) numsec
, secbuf
, DVDINPUT_NOFLAGS
);
1000 if( ret
!= (int) numsec
) {
1002 return ret
< 0 ? ret
: 0;
1005 memcpy( data
, &(secbuf
[ seek_byte
]), byte_size
);
1008 dvd_file
->seek_pos
+= byte_size
;
1012 ssize_t
DVDFileSize( dvd_file_t
*dvd_file
)
1014 /* Check arguments. */
1015 if( dvd_file
== NULL
)
1018 return dvd_file
->filesize
;
1021 int DVDDiscID( dvd_reader_t
*dvd
, unsigned char *discid
)
1026 /* Check arguments. */
1027 if( dvd
== NULL
|| discid
== NULL
)
1030 /* Go through the first 10 IFO:s, in order,
1031 * and md5sum them, i.e VIDEO_TS.IFO and VTS_0?_0.IFO */
1032 md5_init_ctx( &ctx
);
1033 for( title
= 0; title
< 10; title
++ ) {
1034 dvd_file_t
*dvd_file
= DVDOpenFile( dvd
, title
, DVD_READ_INFO_FILE
);
1035 if( dvd_file
!= NULL
) {
1037 size_t file_size
= dvd_file
->filesize
* DVD_VIDEO_LB_LEN
;
1038 char *buffer
= malloc( file_size
);
1040 if( buffer
== NULL
) {
1041 fprintf( stderr
, "libdvdread: DVDDiscId, failed to "
1042 "allocate memory for file read!\n" );
1045 bytes_read
= DVDReadBytes( dvd_file
, buffer
, file_size
);
1046 if( bytes_read
!= file_size
) {
1047 fprintf( stderr
, "libdvdread: DVDDiscId read returned %d bytes"
1048 ", wanted %d\n", bytes_read
, file_size
);
1049 DVDCloseFile( dvd_file
);
1053 md5_process_bytes( buffer
, file_size
, &ctx
);
1055 DVDCloseFile( dvd_file
);
1059 md5_finish_ctx( &ctx
, discid
);
1065 int DVDISOVolumeInfo( dvd_reader_t
*dvd
,
1066 char *volid
, unsigned int volid_size
,
1067 unsigned char *volsetid
, unsigned int volsetid_size
)
1069 unsigned char *buffer
;
1072 /* Check arguments. */
1076 if( dvd
->dev
== NULL
) {
1077 /* No block access, so no ISO... */
1081 buffer
= malloc( DVD_VIDEO_LB_LEN
);
1082 if( buffer
== NULL
) {
1083 fprintf( stderr
, "libdvdread: DVDISOVolumeInfo, failed to "
1084 "allocate memory for file read!\n" );
1088 ret
= UDFReadBlocksRaw( dvd
, 16, 1, buffer
, 0 );
1090 fprintf( stderr
, "libdvdread: DVDISOVolumeInfo, failed to "
1091 "read ISO9660 Primary Volume Descriptor!\n" );
1095 if( (volid
!= NULL
) && (volid_size
> 0) ) {
1097 for(n
= 0; n
< 32; n
++) {
1098 if(buffer
[40+n
] == 0x20) {
1103 if(volid_size
> n
+1) {
1107 memcpy(volid
, &buffer
[40], volid_size
-1);
1108 volid
[volid_size
-1] = '\0';
1111 if( (volsetid
!= NULL
) && (volsetid_size
> 0) ) {
1112 if(volsetid_size
> 128) {
1113 volsetid_size
= 128;
1115 memcpy(volsetid
, &buffer
[190], volsetid_size
);
1121 int DVDUDFVolumeInfo( dvd_reader_t
*dvd
,
1122 char *volid
, unsigned int volid_size
,
1123 unsigned char *volsetid
, unsigned int volsetid_size
)
1126 /* Check arguments. */
1130 if( dvd
->dev
== NULL
) {
1131 /* No block access, so no UDF VolumeSet Identifier */
1135 if( (volid
!= NULL
) && (volid_size
> 0) ) {
1136 ret
= UDFGetVolumeIdentifier(dvd
, volid
, volid_size
);
1141 if( (volsetid
!= NULL
) && (volsetid_size
> 0) ) {
1142 ret
= UDFGetVolumeSetIdentifier(dvd
, volsetid
, volsetid_size
);