2 * Copyright (C) 2001, 2002 Billy Biggs <vektor@dumbterm.net>,
3 * HÃ¥kan Hjort <d95hjort@dtek.chalmers.se>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or (at
8 * your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22 #include <sys/types.h>
24 #include <sys/time.h> /* For the timing of dvdcss_title crack. */
34 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__bsdi__)|| defined(__DARWIN__)
39 #include <sys/mnttab.h>
41 #include </usr/conf/h/mnttab.h>
42 #elif defined(SYS_BSD)
44 #elif defined(__linux__)
49 #include <sys/timeb.h>
50 static void gettimeofday(struct timeval
* t
,void* timezone
){
51 struct timeb timebuffer
;
53 t
->tv_sec
=timebuffer
.time
;
54 t
->tv_usec
=1000*timebuffer
.millitm
;
59 #include "dvd_input.h"
60 #include "dvd_reader.h"
63 /* Basic information. */
66 /* Hack for keeping track of the css status.
67 * 0: no css, 1: perhaps (need init of keys), 2: have done init */
69 int css_title
; /* Last title that we have called DVDinpute_title for. */
71 /* Information required for an image file. */
74 /* Information required for a directory path drive. */
79 /* Basic information. */
82 /* Hack for selecting the right css title. */
85 /* Information required for an image file. */
89 /* Information required for a directory path drive. */
90 size_t title_sizes
[ 9 ];
91 dvd_input_t title_devs
[ 9 ];
93 /* Calculated at open-time, size in blocks. */
97 /* Loop over all titles and call dvdcss_title to crack the keys. */
98 static int initAllCSSKeys( dvd_reader_t
*dvd
)
100 struct timeval all_s
, all_e
;
101 struct timeval t_s
, t_e
;
102 char filename
[ MAX_UDF_FILE_NAME_LEN
];
106 fprintf( stderr
, "\n" );
107 fprintf( stderr
, "libdvdread: Attempting to retrieve all CSS keys\n" );
108 fprintf( stderr
, "libdvdread: This can take a _long_ time, "
109 "please be patient\n\n" );
111 gettimeofday(&all_s
, NULL
);
113 for( title
= 0; title
< 100; title
++ ) {
114 gettimeofday( &t_s
, NULL
);
116 sprintf( filename
, "/VIDEO_TS/VIDEO_TS.VOB" );
118 sprintf( filename
, "/VIDEO_TS/VTS_%02d_%d.VOB", title
, 0 );
120 start
= UDFFindFile( dvd
, filename
, &len
);
121 if( start
!= 0 && len
!= 0 ) {
122 /* Perform CSS key cracking for this title. */
123 fprintf( stderr
, "libdvdread: Get key for %s at 0x%08x\n",
125 if( DVDinput_title( dvd
->dev
, (int)start
) < 0 ) {
126 fprintf( stderr
, "libdvdread: Error cracking CSS key for %s (0x%08x)\n", filename
, start
);
128 gettimeofday( &t_e
, NULL
);
129 fprintf( stderr
, "libdvdread: Elapsed time %ld\n",
130 (long int) t_e
.tv_sec
- t_s
.tv_sec
);
133 if( title
== 0 ) continue;
135 gettimeofday( &t_s
, NULL
);
136 sprintf( filename
, "/VIDEO_TS/VTS_%02d_%d.VOB", title
, 1 );
137 start
= UDFFindFile( dvd
, filename
, &len
);
138 if( start
== 0 || len
== 0 ) break;
140 /* Perform CSS key cracking for this title. */
141 fprintf( stderr
, "libdvdread: Get key for %s at 0x%08x\n",
143 if( DVDinput_title( dvd
->dev
, (int)start
) < 0 ) {
144 fprintf( stderr
, "libdvdread: Error cracking CSS key for %s (0x%08x)!!\n", filename
, start
);
146 gettimeofday( &t_e
, NULL
);
147 fprintf( stderr
, "libdvdread: Elapsed time %ld\n",
148 (long int) t_e
.tv_sec
- t_s
.tv_sec
);
152 fprintf( stderr
, "libdvdread: Found %d VTS's\n", title
);
153 gettimeofday(&all_e
, NULL
);
154 fprintf( stderr
, "libdvdread: Elapsed time %ld\n",
155 (long int) all_e
.tv_sec
- all_s
.tv_sec
);
162 #include "get_path.c"
164 extern char * get_path( char * filename
);
167 //extern char * dvdcss_cache_dir;
170 * Open a DVD image or block device file.
172 static dvd_reader_t
*DVDOpenImageFile( const char *location
, int have_css
)
177 /* setup cache dir is no longer needed, it's now implemented in libdvdcss.c
178 if(!dvdcss_cache_dir){
179 dvdcss_cache_dir=get_path( "" );
180 if ( dvdcss_cache_dir ) { mkdir( dvdcss_cache_dir,493 ); free( dvdcss_cache_dir ); }
181 dvdcss_cache_dir=get_path( "DVDKeys" );
182 if(dvdcss_cache_dir) mkdir( dvdcss_cache_dir,493 );
187 dev
= DVDinput_open( location
);
189 fprintf( stderr
, "libdvdread: Can't open %s for reading\n", location
);
193 dvd
= (dvd_reader_t
*) malloc( sizeof( dvd_reader_t
) );
195 dvd
->isImageFile
= 1;
200 /* Only if DVDCSS_METHOD = title, a bit if it's disc or if
201 * DVDCSS_METHOD = key but region missmatch. Unfortunaly we
202 * don't have that information. */
204 dvd
->css_state
= 1; /* Need key init. */
210 static dvd_reader_t
*DVDOpenPath( const char *path_root
)
214 dvd
= (dvd_reader_t
*) malloc( sizeof( dvd_reader_t
) );
216 dvd
->isImageFile
= 0;
218 dvd
->path_root
= strdup( path_root
);
224 /* /dev/rdsk/c0t6d0s0 (link to /devices/...)
225 /vol/dev/rdsk/c0t6d0/??
227 static char *sun_block2char( const char *path
)
231 /* Must contain "/dsk/" */
232 if( !strstr( path
, "/dsk/" ) ) return (char *) strdup( path
);
234 /* Replace "/dsk/" with "/rdsk/" */
235 new_path
= malloc( strlen(path
) + 2 );
236 strcpy( new_path
, path
);
237 strcpy( strstr( new_path
, "/dsk/" ), "" );
238 strcat( new_path
, "/rdsk/" );
239 strcat( new_path
, strstr( path
, "/dsk/" ) + strlen( "/dsk/" ) );
246 /* FreeBSD /dev/(r)(a)cd0c (a is for atapi), recomended to _not_ use r
247 OpenBSD /dev/rcd0c, it needs to be the raw device
248 NetBSD /dev/rcd0[d|c|..] d for x86, c (for non x86), perhaps others
249 Darwin /dev/rdisk0, it needs to be the raw device
250 BSD/OS /dev/sr0c (if not mounted) or /dev/rsr0c ('c' any letter will do) */
251 static char *bsd_block2char( const char *path
)
255 /* If it doesn't start with "/dev/" or does start with "/dev/r" exit */
256 if( strncmp( path
, "/dev/", 5 ) || !strncmp( path
, "/dev/r", 6 ) )
257 return (char *) strdup( path
);
259 /* Replace "/dev/" with "/dev/r" */
260 new_path
= malloc( strlen(path
) + 2 );
261 strcpy( new_path
, "/dev/r" );
262 strcat( new_path
, path
+ strlen( "/dev/" ) );
268 dvd_reader_t
*DVDOpen( const char *path
)
270 struct stat fileinfo
;
274 if( !path
) return 0;
276 ret
= stat( path
, &fileinfo
);
278 /* If we can't stat the file, give up */
279 fprintf( stderr
, "libdvdread: Can't stat %s\n", path
);
284 /* Try to open libdvdcss or fall back to standard functions */
285 have_css
= DVDInputSetup();
287 /* First check if this is a block/char device or a file*/
288 if( S_ISBLK( fileinfo
.st_mode
) ||
289 S_ISCHR( fileinfo
.st_mode
) ||
290 S_ISREG( fileinfo
.st_mode
) ) {
293 * Block devices and regular files are assumed to be DVD-Video images.
296 return DVDOpenImageFile( sun_block2char( path
), have_css
);
297 #elif defined(SYS_BSD)
298 return DVDOpenImageFile( bsd_block2char( path
), have_css
);
300 return DVDOpenImageFile( path
, have_css
);
303 } else if( S_ISDIR( fileinfo
.st_mode
) ) {
304 dvd_reader_t
*auth_drive
= 0;
308 #elif defined(__sun) || defined(__linux__)
312 /* XXX: We should scream real loud here. */
313 if( !(path_copy
= strdup( path
) ) ) return 0;
315 /* Resolve any symlinks and get the absolut dir name. */
318 int cdir
= open( ".", O_RDONLY
);
322 new_path
= getcwd( NULL
, PATH_MAX
);
329 path_copy
= new_path
;
335 * If we're being asked to open a directory, check if that directory
336 * is the mountpoint for a DVD-ROM which we can use instead.
339 if( strlen( path_copy
) > 1 ) {
340 if( path_copy
[ strlen( path_copy
) - 1 ] == '/' )
341 path_copy
[ strlen( path_copy
) - 1 ] = '\0';
344 if( strlen( path_copy
) > 9 ) {
345 if( !strcasecmp( &(path_copy
[ strlen( path_copy
) - 9 ]),
347 path_copy
[ strlen( path_copy
) - 9 ] = '\0';
352 if( ( fe
= getfsfile( path_copy
) ) ) {
353 dev_name
= bsd_block2char( fe
->fs_spec
);
355 "libdvdread: Attempting to use device %s"
356 " mounted on %s for CSS authentication\n",
359 auth_drive
= DVDOpenImageFile( dev_name
, have_css
);
362 mntfile
= fopen( MNTTAB
, "r" );
367 while( ( res
= getmntent( mntfile
, &mp
) ) != -1 ) {
368 if( res
== 0 && !strcmp( mp
.mnt_mountp
, path_copy
) ) {
369 dev_name
= sun_block2char( mp
.mnt_special
);
371 "libdvdread: Attempting to use device %s"
372 " mounted on %s for CSS authentication\n",
375 auth_drive
= DVDOpenImageFile( dev_name
, have_css
);
381 #elif defined(__linux__)
382 mntfile
= fopen( MOUNTED
, "r" );
386 while( ( me
= getmntent( mntfile
) ) ) {
387 if( !strcmp( me
->mnt_dir
, path_copy
) ) {
389 "libdvdread: Attempting to use device %s"
390 " mounted on %s for CSS authentication\n",
393 auth_drive
= DVDOpenImageFile( me
->mnt_fsname
, have_css
);
394 dev_name
= strdup(me
->mnt_fsname
);
401 dev_name
= strdup(path
);
402 auth_drive
= DVDOpenImageFile( path
, have_css
);
405 fprintf( stderr
, "libdvdread: Couldn't find device name.\n" );
406 } else if( !auth_drive
) {
407 fprintf( stderr
, "libdvdread: Device %s inaccessible, "
408 "CSS authentication not available.\n", dev_name
);
415 * If we've opened a drive, just use that.
417 if( auth_drive
) return auth_drive
;
420 * Otherwise, we now try to open the directory tree instead.
422 return DVDOpenPath( path
);
425 /* If it's none of the above, screw it. */
426 fprintf( stderr
, "libdvdread: Could not open %s\n", path
);
430 void DVDClose( dvd_reader_t
*dvd
)
433 if( dvd
->dev
) DVDinput_close( dvd
->dev
);
434 if( dvd
->path_root
) free( dvd
->path_root
);
441 * Open an unencrypted file on a DVD image file.
443 static dvd_file_t
*DVDOpenFileUDF( dvd_reader_t
*dvd
, char *filename
)
446 dvd_file_t
*dvd_file
;
448 start
= UDFFindFile( dvd
, filename
, &len
);
449 if( !start
) return 0;
451 dvd_file
= (dvd_file_t
*) malloc( sizeof( dvd_file_t
) );
452 if( !dvd_file
) return 0;
454 dvd_file
->lb_start
= start
;
455 dvd_file
->seek_pos
= 0;
456 memset( dvd_file
->title_sizes
, 0, sizeof( dvd_file
->title_sizes
) );
457 memset( dvd_file
->title_devs
, 0, sizeof( dvd_file
->title_devs
) );
458 dvd_file
->filesize
= len
/ DVD_VIDEO_LB_LEN
;
464 * Searches for <file> in directory <path>, ignoring case.
465 * Returns 0 and full filename in <filename>.
466 * or -1 on file not found.
467 * or -2 on path not found.
469 static int findDirFile( const char *path
, const char *file
, char *filename
)
474 dir
= opendir( path
);
475 if( !dir
) return -2;
477 while( ( ent
= readdir( dir
) ) != NULL
) {
478 if( !strcasecmp( ent
->d_name
, file
) ) {
479 sprintf( filename
, "%s%s%s", path
,
480 ( ( path
[ strlen( path
) - 1 ] == '/' ) ? "" : "/" ),
489 static int findDVDFile( dvd_reader_t
*dvd
, const char *file
, char *filename
)
491 char video_path
[ PATH_MAX
+ 1 ];
492 const char *nodirfile
;
495 /* Strip off the directory for our search */
496 if( !strncasecmp( "/VIDEO_TS/", file
, 10 ) ) {
497 nodirfile
= &(file
[ 10 ]);
502 ret
= findDirFile( dvd
->path_root
, nodirfile
, filename
);
504 /* Try also with adding the path, just in case. */
505 sprintf( video_path
, "%s/VIDEO_TS/", dvd
->path_root
);
506 ret
= findDirFile( video_path
, nodirfile
, filename
);
508 /* Try with the path, but in lower case. */
509 sprintf( video_path
, "%s/video_ts/", dvd
->path_root
);
510 ret
= findDirFile( video_path
, nodirfile
, filename
);
521 * Open an unencrypted file from a DVD directory tree.
523 static dvd_file_t
*DVDOpenFilePath( dvd_reader_t
*dvd
, char *filename
)
525 char full_path
[ PATH_MAX
+ 1 ];
526 dvd_file_t
*dvd_file
;
527 struct stat fileinfo
;
530 /* Get the full path of the file. */
531 if( !findDVDFile( dvd
, filename
, full_path
) ) return 0;
533 dev
= DVDinput_open( full_path
);
536 dvd_file
= (dvd_file_t
*) malloc( sizeof( dvd_file_t
) );
537 if( !dvd_file
) return 0;
539 dvd_file
->lb_start
= 0;
540 dvd_file
->seek_pos
= 0;
541 memset( dvd_file
->title_sizes
, 0, sizeof( dvd_file
->title_sizes
) );
542 memset( dvd_file
->title_devs
, 0, sizeof( dvd_file
->title_devs
) );
543 dvd_file
->filesize
= 0;
545 if( stat( full_path
, &fileinfo
) < 0 ) {
546 fprintf( stderr
, "libdvdread: Can't stat() %s.\n", filename
);
550 dvd_file
->title_sizes
[ 0 ] = fileinfo
.st_size
/ DVD_VIDEO_LB_LEN
;
551 dvd_file
->title_devs
[ 0 ] = dev
;
552 dvd_file
->filesize
= dvd_file
->title_sizes
[ 0 ];
557 static dvd_file_t
*DVDOpenVOBUDF( dvd_reader_t
*dvd
, int title
, int menu
)
559 char filename
[ MAX_UDF_FILE_NAME_LEN
];
561 dvd_file_t
*dvd_file
;
564 sprintf( filename
, "/VIDEO_TS/VIDEO_TS.VOB" );
566 sprintf( filename
, "/VIDEO_TS/VTS_%02d_%d.VOB", title
, menu
? 0 : 1 );
568 start
= UDFFindFile( dvd
, filename
, &len
);
569 if( start
== 0 ) return 0;
571 dvd_file
= (dvd_file_t
*) malloc( sizeof( dvd_file_t
) );
572 if( !dvd_file
) return 0;
574 /*Hack*/ dvd_file
->css_title
= title
<< 1 | menu
;
575 dvd_file
->lb_start
= start
;
576 dvd_file
->seek_pos
= 0;
577 memset( dvd_file
->title_sizes
, 0, sizeof( dvd_file
->title_sizes
) );
578 memset( dvd_file
->title_devs
, 0, sizeof( dvd_file
->title_devs
) );
579 dvd_file
->filesize
= len
/ DVD_VIDEO_LB_LEN
;
581 /* Calculate the complete file size for every file in the VOBS */
585 for( cur
= 2; cur
< 10; cur
++ ) {
586 sprintf( filename
, "/VIDEO_TS/VTS_%02d_%d.VOB", title
, cur
);
587 if( !UDFFindFile( dvd
, filename
, &len
) ) break;
588 dvd_file
->filesize
+= len
/ DVD_VIDEO_LB_LEN
;
592 if( dvd
->css_state
== 1 /* Need key init */ ) {
593 // initAllCSSKeys( dvd );
594 // dvd->css_state = 2;
597 if( DVDinput_seek( dvd_file->dvd->dev,
598 (int)start, DVDINPUT_SEEK_KEY ) < 0 ) {
599 fprintf( stderr, "libdvdread: Error cracking CSS key for %s\n",
607 static dvd_file_t
*DVDOpenVOBPath( dvd_reader_t
*dvd
, int title
, int menu
)
609 char filename
[ MAX_UDF_FILE_NAME_LEN
];
610 char full_path
[ PATH_MAX
+ 1 ];
611 struct stat fileinfo
;
612 dvd_file_t
*dvd_file
;
615 dvd_file
= (dvd_file_t
*) malloc( sizeof( dvd_file_t
) );
616 if( !dvd_file
) return 0;
618 /*Hack*/ dvd_file
->css_title
= title
<< 1 | menu
;
619 dvd_file
->lb_start
= 0;
620 dvd_file
->seek_pos
= 0;
621 memset( dvd_file
->title_sizes
, 0, sizeof( dvd_file
->title_sizes
) );
622 memset( dvd_file
->title_devs
, 0, sizeof( dvd_file
->title_devs
) );
623 dvd_file
->filesize
= 0;
629 sprintf( filename
, "VIDEO_TS.VOB" );
631 sprintf( filename
, "VTS_%02i_0.VOB", title
);
633 if( !findDVDFile( dvd
, filename
, full_path
) ) {
638 dev
= DVDinput_open( full_path
);
644 if( stat( full_path
, &fileinfo
) < 0 ) {
645 fprintf( stderr
, "libdvdread: Can't stat() %s.\n", filename
);
649 dvd_file
->title_sizes
[ 0 ] = fileinfo
.st_size
/ DVD_VIDEO_LB_LEN
;
650 dvd_file
->title_devs
[ 0 ] = dev
;
651 DVDinput_seek( dvd_file
->title_devs
[0], 0, DVDINPUT_SEEK_KEY
);
652 dvd_file
->filesize
= dvd_file
->title_sizes
[ 0 ];
655 for( i
= 0; i
< 9; ++i
) {
657 sprintf( filename
, "VTS_%02i_%i.VOB", title
, i
+ 1 );
658 if( !findDVDFile( dvd
, filename
, full_path
) ) {
662 if( stat( full_path
, &fileinfo
) < 0 ) {
663 fprintf( stderr
, "libdvdread: Can't stat() %s.\n", filename
);
667 dvd_file
->title_sizes
[ i
] = fileinfo
.st_size
/ DVD_VIDEO_LB_LEN
;
668 dvd_file
->title_devs
[ i
] = DVDinput_open( full_path
);
669 dvd_file
->filesize
+= dvd_file
->title_sizes
[ i
];
670 DVDinput_seek( dvd_file
->title_devs
[ i
], 0, DVDINPUT_SEEK_KEY
);
672 if( !dvd_file
->title_devs
[ 0 ] ) {
681 dvd_file_t
*DVDOpenFile( dvd_reader_t
*dvd
, int titlenum
,
682 dvd_read_domain_t domain
)
684 char filename
[ MAX_UDF_FILE_NAME_LEN
];
687 case DVD_READ_INFO_FILE
:
688 if( titlenum
== 0 ) {
689 sprintf( filename
, "/VIDEO_TS/VIDEO_TS.IFO" );
691 sprintf( filename
, "/VIDEO_TS/VTS_%02i_0.IFO", titlenum
);
694 case DVD_READ_INFO_BACKUP_FILE
:
695 if( titlenum
== 0 ) {
696 sprintf( filename
, "/VIDEO_TS/VIDEO_TS.BUP" );
698 sprintf( filename
, "/VIDEO_TS/VTS_%02i_0.BUP", titlenum
);
701 case DVD_READ_MENU_VOBS
:
702 if( dvd
->isImageFile
) {
703 return DVDOpenVOBUDF( dvd
, titlenum
, 1 );
705 return DVDOpenVOBPath( dvd
, titlenum
, 1 );
708 case DVD_READ_TITLE_VOBS
:
709 if( titlenum
== 0 ) return 0;
710 if( dvd
->isImageFile
) {
711 return DVDOpenVOBUDF( dvd
, titlenum
, 0 );
713 return DVDOpenVOBPath( dvd
, titlenum
, 0 );
717 fprintf( stderr
, "libdvdread: Invalid domain for file open.\n" );
721 if( dvd
->isImageFile
) {
722 return DVDOpenFileUDF( dvd
, filename
);
724 return DVDOpenFilePath( dvd
, filename
);
728 void DVDCloseFile( dvd_file_t
*dvd_file
)
733 if( dvd_file
->dvd
->isImageFile
) {
736 for( i
= 0; i
< 9; ++i
) {
737 if( dvd_file
->title_devs
[ i
] ) {
738 DVDinput_close( dvd_file
->title_devs
[i
] );
748 /* Internal, but used from dvd_udf.c */
749 int DVDReadBlocksUDFRaw( dvd_reader_t
*device
, uint32_t lb_number
,
750 size_t block_count
, unsigned char *data
,
756 fprintf( stderr
, "libdvdread: Fatal error in block read.\n" );
760 ret
= DVDinput_seek( device
->dev
, (int) lb_number
, DVDINPUT_NOFLAGS
);
761 if( ret
!= (int) lb_number
) {
762 fprintf( stderr
, "libdvdread: Can't seek to block %u\n", lb_number
);
766 return DVDinput_read( device
->dev
, (char *) data
,
767 (int) block_count
, encrypted
);
770 /* This is using a single input and starting from 'dvd_file->lb_start' offset.
772 * Reads 'block_count' blocks from 'dvd_file' at block offset 'offset'
773 * into the buffer located at 'data' and if 'encrypted' is set
774 * descramble the data if it's encrypted. Returning either an
775 * negative error or the number of blocks read. */
776 static int DVDReadBlocksUDF( dvd_file_t
*dvd_file
, uint32_t offset
,
777 size_t block_count
, unsigned char *data
,
780 return DVDReadBlocksUDFRaw( dvd_file
->dvd
, dvd_file
->lb_start
+ offset
,
781 block_count
, data
, encrypted
);
784 /* This is using possibly several inputs and starting from an offset of '0'.
786 * Reads 'block_count' blocks from 'dvd_file' at block offset 'offset'
787 * into the buffer located at 'data' and if 'encrypted' is set
788 * descramble the data if it's encrypted. Returning either an
789 * negative error or the number of blocks read. */
790 static int DVDReadBlocksPath( dvd_file_t
*dvd_file
, unsigned int offset
,
791 size_t block_count
, unsigned char *data
,
799 for( i
= 0; i
< 9; ++i
) {
800 if( !dvd_file
->title_sizes
[ i
] ) return 0; /* Past end of file */
802 if( offset
< dvd_file
->title_sizes
[ i
] ) {
803 if( ( offset
+ block_count
) <= dvd_file
->title_sizes
[ i
] ) {
804 off
= DVDinput_seek( dvd_file
->title_devs
[ i
],
805 (int)offset
, DVDINPUT_NOFLAGS
);
806 if( off
< 0 || off
!= (int)offset
) {
807 fprintf( stderr
, "libdvdread: Can't seek to block %d\n",
809 return off
< 0 ? off
: 0;
811 ret
= DVDinput_read( dvd_file
->title_devs
[ i
], data
,
812 (int)block_count
, encrypted
);
815 size_t part1_size
= dvd_file
->title_sizes
[ i
] - offset
;
816 /* FIXME: Really needs to be a while loop.
817 * (This is only true if you try and read >1GB at a time) */
820 off
= DVDinput_seek( dvd_file
->title_devs
[ i
],
821 (int)offset
, DVDINPUT_NOFLAGS
);
822 if( off
< 0 || off
!= (int)offset
) {
823 fprintf( stderr
, "libdvdread: Can't seek to block %d\n",
825 return off
< 0 ? off
: 0;
827 ret
= DVDinput_read( dvd_file
->title_devs
[ i
], data
,
828 (int)part1_size
, encrypted
);
829 if( ret
< 0 ) return ret
;
830 /* FIXME: This is wrong if i is the last file in the set.
831 * also error from this read will not show in ret. */
833 /* Does the next part exist? If not then return now. */
834 if( !dvd_file
->title_devs
[ i
+ 1 ] ) return ret
;
837 off
= DVDinput_seek( dvd_file
->title_devs
[ i
+ 1 ],
838 0, DVDINPUT_NOFLAGS
);
839 if( off
< 0 || off
!= 0 ) {
840 fprintf( stderr
, "libdvdread: Can't seek to block %d\n",
842 return off
< 0 ? off
: 0;
844 ret2
= DVDinput_read( dvd_file
->title_devs
[ i
+ 1 ],
846 * (int64_t)DVD_VIDEO_LB_LEN
),
847 (int)(block_count
- part1_size
),
849 if( ret2
< 0 ) return ret2
;
853 offset
-= dvd_file
->title_sizes
[ i
];
860 /* This is broken reading more than 2Gb at a time is ssize_t is 32-bit. */
861 ssize_t
DVDReadBlocks( dvd_file_t
*dvd_file
, int offset
,
862 size_t block_count
, unsigned char *data
)
866 /* Hack, and it will still fail for multiple opens in a threaded app ! */
867 if( dvd_file
->dvd
->css_title
!= dvd_file
->css_title
) {
868 dvd_file
->dvd
->css_title
= dvd_file
->css_title
;
869 if( dvd_file
->dvd
->isImageFile
) {
870 DVDinput_title( dvd_file
->dvd
->dev
, (int)dvd_file
->lb_start
);
872 DVDinput_title( dvd_file
->title_devs
[ 0 ], (int)dvd_file
->lb_start
);
876 if( dvd_file
->dvd
->isImageFile
) {
877 ret
= DVDReadBlocksUDF( dvd_file
, (uint32_t)offset
,
878 block_count
, data
, DVDINPUT_READ_DECRYPT
);
880 ret
= DVDReadBlocksPath( dvd_file
, (unsigned int)offset
,
881 block_count
, data
, DVDINPUT_READ_DECRYPT
);
887 int DVDFileSeek( dvd_file_t
*dvd_file
, int offset
)
889 if( offset
> dvd_file
->filesize
* DVD_VIDEO_LB_LEN
) {
892 dvd_file
->seek_pos
= (uint32_t) offset
;
896 ssize_t
DVDReadBytes( dvd_file_t
*dvd_file
, void *data
, size_t byte_size
)
898 unsigned char *secbuf
;
899 unsigned int numsec
, seek_sector
, seek_byte
;
902 seek_sector
= dvd_file
->seek_pos
/ DVD_VIDEO_LB_LEN
;
903 seek_byte
= dvd_file
->seek_pos
% DVD_VIDEO_LB_LEN
;
905 numsec
= ( ( seek_byte
+ byte_size
) / DVD_VIDEO_LB_LEN
) + 1;
906 secbuf
= (unsigned char *) malloc( numsec
* DVD_VIDEO_LB_LEN
);
908 fprintf( stderr
, "libdvdread: Can't allocate memory "
909 "for file read!\n" );
913 if( dvd_file
->dvd
->isImageFile
) {
914 ret
= DVDReadBlocksUDF( dvd_file
, (uint32_t) seek_sector
,
915 (size_t) numsec
, secbuf
, DVDINPUT_NOFLAGS
);
917 ret
= DVDReadBlocksPath( dvd_file
, seek_sector
,
918 (size_t) numsec
, secbuf
, DVDINPUT_NOFLAGS
);
921 if( ret
!= (int) numsec
) {
923 return ret
< 0 ? ret
: 0;
926 memcpy( data
, &(secbuf
[ seek_byte
]), byte_size
);
929 dvd_file
->seek_pos
+= byte_size
;
933 ssize_t
DVDFileSize( dvd_file_t
*dvd_file
)
935 return dvd_file
->filesize
;