Mercurial > libdvdread4.hg
annotate dvd_reader.c @ 22:447c5319a522 src
Convert all ISO8859-1 sequences to proper UTF-8.
author | diego |
---|---|
date | Sun, 14 Sep 2008 16:00:48 +0000 |
parents | 4aa618ae094f |
children | 0d82d0f30c98 |
rev | line source |
---|---|
3 | 1 /* |
2 * Copyright (C) 2001-2004 Billy Biggs <vektor@dumbterm.net>, | |
22 | 3 * Håkan Hjort <d95hjort@dtek.chalmers.se>, |
4 * Björn Englund <d4bjorn@dtek.chalmers.se> | |
3 | 5 * |
21
4aa618ae094f
Use consistent license headers everywhere: Fix FSF address and boilerplate.
diego
parents:
20
diff
changeset
|
6 * This file is part of libdvdread. |
4aa618ae094f
Use consistent license headers everywhere: Fix FSF address and boilerplate.
diego
parents:
20
diff
changeset
|
7 * |
4aa618ae094f
Use consistent license headers everywhere: Fix FSF address and boilerplate.
diego
parents:
20
diff
changeset
|
8 * libdvdread is free software; you can redistribute it and/or modify |
3 | 9 * it under the terms of the GNU General Public License as published by |
21
4aa618ae094f
Use consistent license headers everywhere: Fix FSF address and boilerplate.
diego
parents:
20
diff
changeset
|
10 * the Free Software Foundation; either version 2 of the License, or |
4aa618ae094f
Use consistent license headers everywhere: Fix FSF address and boilerplate.
diego
parents:
20
diff
changeset
|
11 * (at your option) any later version. |
3 | 12 * |
21
4aa618ae094f
Use consistent license headers everywhere: Fix FSF address and boilerplate.
diego
parents:
20
diff
changeset
|
13 * libdvdread is distributed in the hope that it will be useful, |
4aa618ae094f
Use consistent license headers everywhere: Fix FSF address and boilerplate.
diego
parents:
20
diff
changeset
|
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
4aa618ae094f
Use consistent license headers everywhere: Fix FSF address and boilerplate.
diego
parents:
20
diff
changeset
|
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4aa618ae094f
Use consistent license headers everywhere: Fix FSF address and boilerplate.
diego
parents:
20
diff
changeset
|
16 * GNU General Public License for more details. |
3 | 17 * |
21
4aa618ae094f
Use consistent license headers everywhere: Fix FSF address and boilerplate.
diego
parents:
20
diff
changeset
|
18 * You should have received a copy of the GNU General Public License along |
4aa618ae094f
Use consistent license headers everywhere: Fix FSF address and boilerplate.
diego
parents:
20
diff
changeset
|
19 * with libdvdread; if not, write to the Free Software Foundation, Inc., |
4aa618ae094f
Use consistent license headers everywhere: Fix FSF address and boilerplate.
diego
parents:
20
diff
changeset
|
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
3 | 21 */ |
22 | |
23 #include "config.h" | |
24 | |
25 #include <sys/types.h> | |
26 #include <sys/stat.h> | |
27 #include <sys/time.h> /* For the timing of dvdcss_title crack. */ | |
28 #include <fcntl.h> | |
29 #include <stdlib.h> | |
30 #include <stdio.h> | |
31 #include <errno.h> | |
32 #include <string.h> | |
33 #include <unistd.h> | |
34 #include <limits.h> | |
35 #include <dirent.h> | |
36 | |
37 /* misc win32 helpers */ | |
38 #ifdef WIN32 | |
6
e5663591d13c
gettimeofday() doesn't exist in windows, but recent mingw32 runtime
nicodvb
parents:
3
diff
changeset
|
39 #ifndef HAVE_GETTIMEOFDAY |
3 | 40 /* replacement gettimeofday implementation */ |
41 #include <sys/timeb.h> | |
42 static inline int _private_gettimeofday( struct timeval *tv, void *tz ) | |
43 { | |
44 struct timeb t; | |
45 ftime( &t ); | |
46 tv->tv_sec = t.time; | |
47 tv->tv_usec = t.millitm * 1000; | |
48 return 0; | |
49 } | |
50 #define gettimeofday(TV, TZ) _private_gettimeofday((TV), (TZ)) | |
6
e5663591d13c
gettimeofday() doesn't exist in windows, but recent mingw32 runtime
nicodvb
parents:
3
diff
changeset
|
51 #endif |
3 | 52 #include <io.h> /* read() */ |
53 #define lseek64 _lseeki64 | |
54 #endif | |
20 | 55 |
3 | 56 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__bsdi__)|| defined(__DARWIN__) |
57 #define SYS_BSD 1 | |
58 #endif | |
59 | |
60 #if defined(__sun) | |
61 #include <sys/mnttab.h> | |
62 #elif defined(SYS_BSD) | |
63 #include <fstab.h> | |
64 #elif defined(__linux__) | |
65 #include <mntent.h> | |
66 #endif | |
67 | |
68 #include "dvd_udf.h" | |
69 #include "dvd_input.h" | |
70 #include "dvd_reader.h" | |
71 #include "md5.h" | |
72 | |
73 #define DEFAULT_UDF_CACHE_LEVEL 1 | |
74 | |
75 struct dvd_reader_s { | |
76 /* Basic information. */ | |
77 int isImageFile; | |
20 | 78 |
79 /* Hack for keeping track of the css status. | |
3 | 80 * 0: no css, 1: perhaps (need init of keys), 2: have done init */ |
81 int css_state; | |
82 int css_title; /* Last title that we have called dvdinpute_title for. */ | |
83 | |
84 /* Information required for an image file. */ | |
85 dvd_input_t dev; | |
86 | |
87 /* Information required for a directory path drive. */ | |
88 char *path_root; | |
20 | 89 |
3 | 90 /* Filesystem cache */ |
91 int udfcache_level; /* 0 - turned off, 1 - on */ | |
92 void *udfcache; | |
93 }; | |
94 | |
95 #define TITLES_MAX 9 | |
96 | |
97 struct dvd_file_s { | |
98 /* Basic information. */ | |
99 dvd_reader_t *dvd; | |
20 | 100 |
3 | 101 /* Hack for selecting the right css title. */ |
102 int css_title; | |
103 | |
104 /* Information required for an image file. */ | |
105 uint32_t lb_start; | |
106 uint32_t seek_pos; | |
107 | |
108 /* Information required for a directory path drive. */ | |
109 size_t title_sizes[ TITLES_MAX ]; | |
110 dvd_input_t title_devs[ TITLES_MAX ]; | |
111 | |
112 /* Calculated at open-time, size in blocks. */ | |
113 ssize_t filesize; | |
114 }; | |
115 | |
116 int UDFReadBlocksRaw( dvd_reader_t *device, uint32_t lb_number, | |
20 | 117 size_t block_count, unsigned char *data, |
3 | 118 int encrypted ); |
119 | |
120 /** | |
121 * Set the level of caching on udf | |
122 * level = 0 (no caching) | |
123 * level = 1 (caching filesystem info) | |
124 */ | |
125 int DVDUDFCacheLevel(dvd_reader_t *device, int level) | |
126 { | |
127 struct dvd_reader_s *dev = (struct dvd_reader_s *)device; | |
20 | 128 |
3 | 129 if(level > 0) { |
130 level = 1; | |
131 } else if(level < 0) { | |
132 return dev->udfcache_level; | |
133 } | |
134 | |
135 dev->udfcache_level = level; | |
20 | 136 |
3 | 137 return level; |
138 } | |
139 | |
140 void *GetUDFCacheHandle(dvd_reader_t *device) | |
141 { | |
142 struct dvd_reader_s *dev = (struct dvd_reader_s *)device; | |
20 | 143 |
3 | 144 return dev->udfcache; |
145 } | |
146 | |
147 void SetUDFCacheHandle(dvd_reader_t *device, void *cache) | |
148 { | |
149 struct dvd_reader_s *dev = (struct dvd_reader_s *)device; | |
150 | |
151 dev->udfcache = cache; | |
152 } | |
153 | |
154 | |
155 | |
156 /* Loop over all titles and call dvdcss_title to crack the keys. */ | |
157 static int initAllCSSKeys( dvd_reader_t *dvd ) | |
158 { | |
159 struct timeval all_s, all_e; | |
160 struct timeval t_s, t_e; | |
161 char filename[ MAX_UDF_FILE_NAME_LEN ]; | |
162 uint32_t start, len; | |
163 int title; | |
20 | 164 |
3 | 165 char *nokeys_str = getenv("DVDREAD_NOKEYS"); |
166 if(nokeys_str != NULL) | |
167 return 0; | |
20 | 168 |
3 | 169 fprintf( stderr, "\n" ); |
170 fprintf( stderr, "libdvdread: Attempting to retrieve all CSS keys\n" ); | |
171 fprintf( stderr, "libdvdread: This can take a _long_ time, " | |
172 "please be patient\n\n" ); | |
20 | 173 |
3 | 174 gettimeofday(&all_s, NULL); |
20 | 175 |
3 | 176 for( title = 0; title < 100; title++ ) { |
177 gettimeofday( &t_s, NULL ); | |
178 if( title == 0 ) { | |
179 sprintf( filename, "/VIDEO_TS/VIDEO_TS.VOB" ); | |
180 } else { | |
181 sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, 0 ); | |
182 } | |
183 start = UDFFindFile( dvd, filename, &len ); | |
184 if( start != 0 && len != 0 ) { | |
185 /* Perform CSS key cracking for this title. */ | |
20 | 186 fprintf( stderr, "libdvdread: Get key for %s at 0x%08x\n", |
3 | 187 filename, start ); |
188 if( dvdinput_title( dvd->dev, (int)start ) < 0 ) { | |
189 fprintf( stderr, "libdvdread: Error cracking CSS key for %s (0x%08x)\n", filename, start); | |
190 } | |
191 gettimeofday( &t_e, NULL ); | |
20 | 192 fprintf( stderr, "libdvdread: Elapsed time %ld\n", |
3 | 193 (long int) t_e.tv_sec - t_s.tv_sec ); |
194 } | |
20 | 195 |
3 | 196 if( title == 0 ) continue; |
20 | 197 |
3 | 198 gettimeofday( &t_s, NULL ); |
199 sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, 1 ); | |
200 start = UDFFindFile( dvd, filename, &len ); | |
201 if( start == 0 || len == 0 ) break; | |
20 | 202 |
3 | 203 /* Perform CSS key cracking for this title. */ |
20 | 204 fprintf( stderr, "libdvdread: Get key for %s at 0x%08x\n", |
3 | 205 filename, start ); |
206 if( dvdinput_title( dvd->dev, (int)start ) < 0 ) { | |
207 fprintf( stderr, "libdvdread: Error cracking CSS key for %s (0x%08x)!!\n", filename, start); | |
208 } | |
209 gettimeofday( &t_e, NULL ); | |
20 | 210 fprintf( stderr, "libdvdread: Elapsed time %ld\n", |
3 | 211 (long int) t_e.tv_sec - t_s.tv_sec ); |
212 } | |
213 title--; | |
20 | 214 |
3 | 215 fprintf( stderr, "libdvdread: Found %d VTS's\n", title ); |
216 gettimeofday(&all_e, NULL); | |
20 | 217 fprintf( stderr, "libdvdread: Elapsed time %ld\n", |
3 | 218 (long int) all_e.tv_sec - all_s.tv_sec ); |
20 | 219 |
3 | 220 return 0; |
221 } | |
222 | |
223 | |
224 | |
225 /** | |
226 * Open a DVD image or block device file. | |
227 */ | |
228 static dvd_reader_t *DVDOpenImageFile( const char *location, int have_css ) | |
229 { | |
230 dvd_reader_t *dvd; | |
231 dvd_input_t dev; | |
20 | 232 |
3 | 233 dev = dvdinput_open( location ); |
234 if( !dev ) { | |
235 fprintf( stderr, "libdvdread: Can't open %s for reading\n", location ); | |
236 return NULL; | |
237 } | |
238 | |
239 dvd = (dvd_reader_t *) malloc( sizeof( dvd_reader_t ) ); | |
240 if( !dvd ) { | |
241 dvdinput_close(dev); | |
242 return NULL; | |
243 } | |
244 dvd->isImageFile = 1; | |
245 dvd->dev = dev; | |
246 dvd->path_root = NULL; | |
20 | 247 |
3 | 248 dvd->udfcache_level = DEFAULT_UDF_CACHE_LEVEL; |
249 dvd->udfcache = NULL; | |
250 | |
251 if( have_css ) { | |
252 /* Only if DVDCSS_METHOD = title, a bit if it's disc or if | |
253 * DVDCSS_METHOD = key but region missmatch. Unfortunaly we | |
254 * don't have that information. */ | |
20 | 255 |
3 | 256 dvd->css_state = 1; /* Need key init. */ |
257 } | |
258 dvd->css_title = 0; | |
20 | 259 |
3 | 260 return dvd; |
261 } | |
262 | |
263 static dvd_reader_t *DVDOpenPath( const char *path_root ) | |
264 { | |
265 dvd_reader_t *dvd; | |
266 | |
267 dvd = (dvd_reader_t *) malloc( sizeof( dvd_reader_t ) ); | |
268 if( !dvd ) return NULL; | |
269 dvd->isImageFile = 0; | |
270 dvd->dev = 0; | |
271 dvd->path_root = strdup( path_root ); | |
272 if(!dvd->path_root) { | |
273 free(dvd); | |
274 return 0; | |
275 } | |
276 | |
277 dvd->udfcache_level = DEFAULT_UDF_CACHE_LEVEL; | |
278 dvd->udfcache = NULL; | |
20 | 279 |
3 | 280 dvd->css_state = 0; /* Only used in the UDF path */ |
281 dvd->css_title = 0; /* Only matters in the UDF path */ | |
282 | |
283 return dvd; | |
284 } | |
285 | |
286 #if defined(__sun) | |
287 /* /dev/rdsk/c0t6d0s0 (link to /devices/...) | |
288 /vol/dev/rdsk/c0t6d0/?? | |
289 /vol/rdsk/<name> */ | |
290 static char *sun_block2char( const char *path ) | |
291 { | |
292 char *new_path; | |
293 | |
20 | 294 /* Must contain "/dsk/" */ |
3 | 295 if( !strstr( path, "/dsk/" ) ) return (char *) strdup( path ); |
296 | |
297 /* Replace "/dsk/" with "/rdsk/" */ | |
298 new_path = malloc( strlen(path) + 2 ); | |
299 strcpy( new_path, path ); | |
300 strcpy( strstr( new_path, "/dsk/" ), "" ); | |
301 strcat( new_path, "/rdsk/" ); | |
302 strcat( new_path, strstr( path, "/dsk/" ) + strlen( "/dsk/" ) ); | |
303 | |
304 return new_path; | |
305 } | |
306 #endif | |
307 | |
308 #if defined(SYS_BSD) | |
309 /* FreeBSD /dev/(r)(a)cd0c (a is for atapi), recomended to _not_ use r | |
310 OpenBSD /dev/rcd0c, it needs to be the raw device | |
311 NetBSD /dev/rcd0[d|c|..] d for x86, c (for non x86), perhaps others | |
312 Darwin /dev/rdisk0, it needs to be the raw device | |
313 BSD/OS /dev/sr0c (if not mounted) or /dev/rsr0c ('c' any letter will do) */ | |
314 static char *bsd_block2char( const char *path ) | |
315 { | |
316 char *new_path; | |
317 | |
20 | 318 /* If it doesn't start with "/dev/" or does start with "/dev/r" exit */ |
319 if( !strncmp( path, "/dev/", 5 ) || strncmp( path, "/dev/r", 6 ) ) | |
3 | 320 return (char *) strdup( path ); |
321 | |
322 /* Replace "/dev/" with "/dev/r" */ | |
323 new_path = malloc( strlen(path) + 2 ); | |
324 strcpy( new_path, "/dev/r" ); | |
325 strcat( new_path, path + strlen( "/dev/" ) ); | |
326 | |
327 return new_path; | |
328 } | |
329 #endif | |
330 | |
331 dvd_reader_t *DVDOpen( const char *ppath ) | |
332 { | |
333 struct stat fileinfo; | |
334 int ret; | |
335 int have_css; | |
336 dvd_reader_t *ret_val = NULL; | |
337 char *dev_name = NULL; | |
338 char *path; | |
339 | |
340 #ifdef _MSC_VER | |
341 int len; | |
342 #endif | |
343 | |
344 if( ppath == NULL ) | |
345 return 0; | |
346 | |
347 path = strdup(ppath); | |
348 if( path == NULL ) | |
349 return 0; | |
20 | 350 |
3 | 351 /* Try to open libdvdcss or fall back to standard functions */ |
352 have_css = dvdinput_setup(); | |
353 | |
354 #ifdef _MSC_VER | |
355 /* Strip off the trailing \ if it is not a drive */ | |
356 len = strlen(path); | |
20 | 357 if ((len > 1) && |
358 (path[len - 1] == '\\') && | |
3 | 359 (path[len - 2] != ':')) |
360 { | |
361 path[len-1] = '\0'; | |
362 } | |
363 #endif | |
20 | 364 |
3 | 365 ret = stat( path, &fileinfo ); |
366 | |
367 if( ret < 0 ) { | |
368 | |
369 /* maybe "host:port" url? try opening it with acCeSS library */ | |
370 if( strchr(path,':') ) { | |
371 ret_val = DVDOpenImageFile( path, have_css ); | |
372 free(path); | |
373 return ret_val; | |
374 } | |
20 | 375 |
3 | 376 /* If we can't stat the file, give up */ |
377 fprintf( stderr, "libdvdread: Can't stat %s\n", path ); | |
378 perror(""); | |
379 free(path); | |
380 return NULL; | |
381 } | |
382 | |
383 /* First check if this is a block/char device or a file*/ | |
20 | 384 if( S_ISBLK( fileinfo.st_mode ) || |
385 S_ISCHR( fileinfo.st_mode ) || | |
3 | 386 S_ISREG( fileinfo.st_mode ) ) { |
387 | |
388 /** | |
389 * Block devices and regular files are assumed to be DVD-Video images. | |
390 */ | |
391 #if defined(__sun) | |
392 ret_val = DVDOpenImageFile( sun_block2char( path ), have_css ); | |
393 #elif defined(SYS_BSD) | |
394 ret_val = DVDOpenImageFile( bsd_block2char( path ), have_css ); | |
395 #else | |
396 ret_val = DVDOpenImageFile( path, have_css ); | |
397 #endif | |
398 | |
399 free(path); | |
400 return ret_val; | |
401 | |
402 } else if( S_ISDIR( fileinfo.st_mode ) ) { | |
403 dvd_reader_t *auth_drive = 0; | |
404 char *path_copy; | |
405 #if defined(SYS_BSD) | |
406 struct fstab* fe; | |
407 #elif defined(__sun) || defined(__linux__) | |
408 FILE *mntfile; | |
409 #endif | |
410 | |
411 /* XXX: We should scream real loud here. */ | |
412 if( !(path_copy = strdup( path ) ) ) { | |
20 | 413 free(path); |
3 | 414 return NULL; |
415 } | |
416 | |
417 #ifndef WIN32 /* don't have fchdir, and getcwd( NULL, ... ) is strange */ | |
418 /* Also WIN32 does not have symlinks, so we don't need this bit of code. */ | |
419 | |
420 /* Resolve any symlinks and get the absolut dir name. */ | |
421 { | |
422 char *new_path; | |
423 int cdir = open( ".", O_RDONLY ); | |
20 | 424 |
3 | 425 if( cdir >= 0 ) { |
426 chdir( path_copy ); | |
427 new_path = malloc(PATH_MAX+1); | |
428 if(!new_path) { | |
429 free(path); | |
430 return NULL; | |
431 } | |
432 getcwd(new_path, PATH_MAX ); | |
433 fchdir( cdir ); | |
434 close( cdir ); | |
435 free( path_copy ); | |
436 path_copy = new_path; | |
437 } | |
438 } | |
20 | 439 #endif |
3 | 440 /** |
441 * If we're being asked to open a directory, check if that directory | |
442 * is the mountpoint for a DVD-ROM which we can use instead. | |
443 */ | |
444 | |
445 if( strlen( path_copy ) > 1 ) { | |
20 | 446 if( path_copy[ strlen( path_copy ) - 1 ] == '/' ) |
3 | 447 path_copy[ strlen( path_copy ) - 1 ] = '\0'; |
448 } | |
449 | |
450 if( strlen( path_copy ) > TITLES_MAX ) { | |
20 | 451 if( !strcasecmp( &(path_copy[ strlen( path_copy ) - TITLES_MAX ]), |
3 | 452 "/video_ts" ) ) { |
453 path_copy[ strlen( path_copy ) - TITLES_MAX ] = '\0'; | |
454 } | |
455 } | |
20 | 456 |
3 | 457 if(path_copy[0] == '\0') { |
458 path_copy[0] = '/'; | |
459 path_copy[1] = '\0'; | |
460 } | |
461 | |
462 #if defined(SYS_BSD) | |
463 if( ( fe = getfsfile( path_copy ) ) ) { | |
464 dev_name = bsd_block2char( fe->fs_spec ); | |
465 fprintf( stderr, | |
466 "libdvdread: Attempting to use device %s" | |
467 " mounted on %s for CSS authentication\n", | |
468 dev_name, | |
469 fe->fs_file ); | |
470 auth_drive = DVDOpenImageFile( dev_name, have_css ); | |
471 } | |
472 #elif defined(__sun) | |
473 mntfile = fopen( MNTTAB, "r" ); | |
474 if( mntfile ) { | |
475 struct mnttab mp; | |
476 int res; | |
477 | |
478 while( ( res = getmntent( mntfile, &mp ) ) != -1 ) { | |
479 if( res == 0 && !strcmp( mp.mnt_mountp, path_copy ) ) { | |
480 dev_name = sun_block2char( mp.mnt_special ); | |
20 | 481 fprintf( stderr, |
3 | 482 "libdvdread: Attempting to use device %s" |
483 " mounted on %s for CSS authentication\n", | |
484 dev_name, | |
485 mp.mnt_mountp ); | |
486 auth_drive = DVDOpenImageFile( dev_name, have_css ); | |
487 break; | |
488 } | |
489 } | |
490 fclose( mntfile ); | |
491 } | |
492 #elif defined(__linux__) | |
493 mntfile = fopen( MOUNTED, "r" ); | |
494 if( mntfile ) { | |
495 struct mntent *me; | |
20 | 496 |
3 | 497 while( ( me = getmntent( mntfile ) ) ) { |
498 if( !strcmp( me->mnt_dir, path_copy ) ) { | |
20 | 499 fprintf( stderr, |
3 | 500 "libdvdread: Attempting to use device %s" |
501 " mounted on %s for CSS authentication\n", | |
502 me->mnt_fsname, | |
503 me->mnt_dir ); | |
504 auth_drive = DVDOpenImageFile( me->mnt_fsname, have_css ); | |
505 dev_name = strdup(me->mnt_fsname); | |
506 break; | |
507 } | |
508 } | |
509 fclose( mntfile ); | |
510 } | |
511 #elif defined(_MSC_VER) | |
512 auth_drive = DVDOpenImageFile( path, have_css ); | |
513 #endif | |
514 | |
515 #ifndef _MSC_VER | |
516 if( !dev_name ) { | |
517 fprintf( stderr, "libdvdread: Couldn't find device name.\n" ); | |
518 } else if( !auth_drive ) { | |
519 fprintf( stderr, "libdvdread: Device %s inaccessible, " | |
520 "CSS authentication not available.\n", dev_name ); | |
521 } | |
522 #else | |
523 if( !auth_drive ) { | |
524 fprintf( stderr, "libdvdread: Device %s inaccessible, " | |
525 "CSS authentication not available.\n", dev_name ); | |
526 } | |
527 #endif | |
528 | |
529 free( dev_name ); | |
530 free( path_copy ); | |
531 | |
532 /** | |
533 * If we've opened a drive, just use that. | |
534 */ | |
535 if( auth_drive ) { | |
536 free(path); | |
537 return auth_drive; | |
538 } | |
539 | |
540 /** | |
541 * Otherwise, we now try to open the directory tree instead. | |
542 */ | |
543 ret_val = DVDOpenPath( path ); | |
544 free( path ); | |
545 return ret_val; | |
546 } | |
547 | |
548 /* If it's none of the above, screw it. */ | |
549 fprintf( stderr, "libdvdread: Could not open %s\n", path ); | |
550 free( path ); | |
551 return NULL; | |
552 } | |
553 | |
554 void DVDClose( dvd_reader_t *dvd ) | |
555 { | |
556 if( dvd ) { | |
557 if( dvd->dev ) dvdinput_close( dvd->dev ); | |
558 if( dvd->path_root ) free( dvd->path_root ); | |
559 if( dvd->udfcache ) FreeUDFCache( dvd->udfcache ); | |
560 free( dvd ); | |
561 } | |
562 } | |
563 | |
564 /** | |
565 * Open an unencrypted file on a DVD image file. | |
566 */ | |
567 static dvd_file_t *DVDOpenFileUDF( dvd_reader_t *dvd, char *filename ) | |
568 { | |
569 uint32_t start, len; | |
570 dvd_file_t *dvd_file; | |
571 | |
572 start = UDFFindFile( dvd, filename, &len ); | |
573 if( !start ) { | |
574 fprintf( stderr, "libdvdnav:DVDOpenFileUDF:UDFFindFile %s failed\n", filename ); | |
575 return NULL; | |
576 } | |
577 | |
578 dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) ); | |
579 if( !dvd_file ) { | |
580 fprintf( stderr, "libdvdnav:DVDOpenFileUDF:malloc failed\n" ); | |
581 return NULL; | |
582 } | |
583 dvd_file->dvd = dvd; | |
584 dvd_file->lb_start = start; | |
585 dvd_file->seek_pos = 0; | |
586 memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) ); | |
587 memset( dvd_file->title_devs, 0, sizeof( dvd_file->title_devs ) ); | |
588 dvd_file->filesize = len / DVD_VIDEO_LB_LEN; | |
589 | |
590 return dvd_file; | |
591 } | |
592 | |
593 /** | |
594 * Searches for <file> in directory <path>, ignoring case. | |
595 * Returns 0 and full filename in <filename>. | |
596 * or -1 on file not found. | |
597 * or -2 on path not found. | |
598 */ | |
20 | 599 static int findDirFile( const char *path, const char *file, char *filename ) |
3 | 600 { |
601 DIR *dir; | |
602 struct dirent *ent; | |
603 | |
604 dir = opendir( path ); | |
605 if( !dir ) return -2; | |
606 | |
607 while( ( ent = readdir( dir ) ) != NULL ) { | |
608 if( !strcasecmp( ent->d_name, file ) ) { | |
609 sprintf( filename, "%s%s%s", path, | |
610 ( ( path[ strlen( path ) - 1 ] == '/' ) ? "" : "/" ), | |
611 ent->d_name ); | |
612 closedir( dir ); | |
613 return 0; | |
614 } | |
615 } | |
616 | |
617 closedir( dir ); | |
618 return -1; | |
619 } | |
620 | |
621 static int findDVDFile( dvd_reader_t *dvd, const char *file, char *filename ) | |
622 { | |
623 char video_path[ PATH_MAX + 1 ]; | |
624 const char *nodirfile; | |
625 int ret; | |
626 | |
627 /* Strip off the directory for our search */ | |
628 if( !strncasecmp( "/VIDEO_TS/", file, 10 ) ) { | |
629 nodirfile = &(file[ 10 ]); | |
630 } else { | |
631 nodirfile = file; | |
632 } | |
633 | |
634 ret = findDirFile( dvd->path_root, nodirfile, filename ); | |
635 if( ret < 0 ) { | |
636 /* Try also with adding the path, just in case. */ | |
637 sprintf( video_path, "%s/VIDEO_TS/", dvd->path_root ); | |
638 ret = findDirFile( video_path, nodirfile, filename ); | |
639 if( ret < 0 ) { | |
640 /* Try with the path, but in lower case. */ | |
641 sprintf( video_path, "%s/video_ts/", dvd->path_root ); | |
642 ret = findDirFile( video_path, nodirfile, filename ); | |
643 if( ret < 0 ) { | |
644 return 0; | |
645 } | |
646 } | |
647 } | |
648 | |
649 return 1; | |
650 } | |
651 | |
652 /** | |
653 * Open an unencrypted file from a DVD directory tree. | |
654 */ | |
655 static dvd_file_t *DVDOpenFilePath( dvd_reader_t *dvd, char *filename ) | |
656 { | |
657 char full_path[ PATH_MAX + 1 ]; | |
658 dvd_file_t *dvd_file; | |
659 struct stat fileinfo; | |
660 dvd_input_t dev; | |
661 | |
662 /* Get the full path of the file. */ | |
663 if( !findDVDFile( dvd, filename, full_path ) ) { | |
664 fprintf( stderr, "libdvdnav:DVDOpenFilePath:findDVDFile %s failed\n", filename ); | |
665 return NULL; | |
666 } | |
667 | |
668 dev = dvdinput_open( full_path ); | |
669 if( !dev ) { | |
670 fprintf( stderr, "libdvdnav:DVDOpenFilePath:dvdinput_open %s failed\n", full_path ); | |
671 return NULL; | |
672 } | |
673 | |
674 dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) ); | |
675 if( !dvd_file ) { | |
676 fprintf( stderr, "libdvdnav:DVDOpenFilePath:dvd_file malloc failed\n" ); | |
677 dvdinput_close(dev); | |
678 return NULL; | |
679 } | |
680 dvd_file->dvd = dvd; | |
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; | |
686 | |
687 if( stat( full_path, &fileinfo ) < 0 ) { | |
688 fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename ); | |
689 free( dvd_file ); | |
690 return NULL; | |
691 } | |
692 dvd_file->title_sizes[ 0 ] = fileinfo.st_size / DVD_VIDEO_LB_LEN; | |
693 dvd_file->title_devs[ 0 ] = dev; | |
694 dvd_file->filesize = dvd_file->title_sizes[ 0 ]; | |
695 | |
696 return dvd_file; | |
697 } | |
698 | |
699 static dvd_file_t *DVDOpenVOBUDF( dvd_reader_t *dvd, int title, int menu ) | |
700 { | |
701 char filename[ MAX_UDF_FILE_NAME_LEN ]; | |
702 uint32_t start, len; | |
703 dvd_file_t *dvd_file; | |
704 | |
705 if( title == 0 ) { | |
706 sprintf( filename, "/VIDEO_TS/VIDEO_TS.VOB" ); | |
707 } else { | |
708 sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, menu ? 0 : 1 ); | |
709 } | |
710 start = UDFFindFile( dvd, filename, &len ); | |
711 if( start == 0 ) return NULL; | |
712 | |
713 dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) ); | |
714 if( !dvd_file ) return NULL; | |
715 dvd_file->dvd = dvd; | |
716 /*Hack*/ dvd_file->css_title = title << 1 | menu; | |
717 dvd_file->lb_start = start; | |
718 dvd_file->seek_pos = 0; | |
719 memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) ); | |
720 memset( dvd_file->title_devs, 0, sizeof( dvd_file->title_devs ) ); | |
721 dvd_file->filesize = len / DVD_VIDEO_LB_LEN; | |
722 | |
723 /* Calculate the complete file size for every file in the VOBS */ | |
724 if( !menu ) { | |
725 int cur; | |
726 | |
727 for( cur = 2; cur < 10; cur++ ) { | |
728 sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, cur ); | |
729 if( !UDFFindFile( dvd, filename, &len ) ) break; | |
730 dvd_file->filesize += len / DVD_VIDEO_LB_LEN; | |
731 } | |
732 } | |
20 | 733 |
3 | 734 if( dvd->css_state == 1 /* Need key init */ ) { |
735 initAllCSSKeys( dvd ); | |
736 dvd->css_state = 2; | |
737 } | |
20 | 738 /* |
3 | 739 if( dvdinput_title( dvd_file->dvd->dev, (int)start ) < 0 ) { |
740 fprintf( stderr, "libdvdread: Error cracking CSS key for %s\n", | |
741 filename ); | |
742 } | |
743 */ | |
20 | 744 |
3 | 745 return dvd_file; |
746 } | |
747 | |
748 static dvd_file_t *DVDOpenVOBPath( dvd_reader_t *dvd, int title, int menu ) | |
749 { | |
750 char filename[ MAX_UDF_FILE_NAME_LEN ]; | |
751 char full_path[ PATH_MAX + 1 ]; | |
752 struct stat fileinfo; | |
753 dvd_file_t *dvd_file; | |
754 int i; | |
755 | |
756 dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) ); | |
757 if( !dvd_file ) return NULL; | |
758 dvd_file->dvd = dvd; | |
759 /*Hack*/ dvd_file->css_title = title << 1 | menu; | |
760 dvd_file->lb_start = 0; | |
761 dvd_file->seek_pos = 0; | |
762 memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) ); | |
763 memset( dvd_file->title_devs, 0, sizeof( dvd_file->title_devs ) ); | |
764 dvd_file->filesize = 0; | |
20 | 765 |
3 | 766 if( menu ) { |
767 dvd_input_t dev; | |
768 | |
769 if( title == 0 ) { | |
770 sprintf( filename, "VIDEO_TS.VOB" ); | |
771 } else { | |
772 sprintf( filename, "VTS_%02i_0.VOB", title ); | |
773 } | |
774 if( !findDVDFile( dvd, filename, full_path ) ) { | |
775 free( dvd_file ); | |
776 return NULL; | |
777 } | |
778 | |
779 dev = dvdinput_open( full_path ); | |
780 if( dev == NULL ) { | |
781 free( dvd_file ); | |
782 return NULL; | |
783 } | |
784 | |
785 if( stat( full_path, &fileinfo ) < 0 ) { | |
786 fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename ); | |
787 dvdinput_close(dev); | |
788 free( dvd_file ); | |
789 return NULL; | |
790 } | |
791 dvd_file->title_sizes[ 0 ] = fileinfo.st_size / DVD_VIDEO_LB_LEN; | |
792 dvd_file->title_devs[ 0 ] = dev; | |
793 dvdinput_title( dvd_file->title_devs[0], 0); | |
794 dvd_file->filesize = dvd_file->title_sizes[ 0 ]; | |
795 | |
796 } else { | |
797 for( i = 0; i < TITLES_MAX; ++i ) { | |
798 | |
799 sprintf( filename, "VTS_%02i_%i.VOB", title, i + 1 ); | |
800 if( !findDVDFile( dvd, filename, full_path ) ) { | |
801 break; | |
802 } | |
803 | |
804 if( stat( full_path, &fileinfo ) < 0 ) { | |
805 fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename ); | |
806 break; | |
807 } | |
808 | |
809 dvd_file->title_sizes[ i ] = fileinfo.st_size / DVD_VIDEO_LB_LEN; | |
810 dvd_file->title_devs[ i ] = dvdinput_open( full_path ); | |
811 dvdinput_title( dvd_file->title_devs[ i ], 0 ); | |
812 dvd_file->filesize += dvd_file->title_sizes[ i ]; | |
813 } | |
814 if( !dvd_file->title_devs[ 0 ] ) { | |
815 free( dvd_file ); | |
816 return NULL; | |
817 } | |
818 } | |
819 | |
820 return dvd_file; | |
821 } | |
822 | |
20 | 823 dvd_file_t *DVDOpenFile( dvd_reader_t *dvd, int titlenum, |
3 | 824 dvd_read_domain_t domain ) |
825 { | |
826 char filename[ MAX_UDF_FILE_NAME_LEN ]; | |
20 | 827 |
3 | 828 /* Check arguments. */ |
829 if( dvd == NULL || titlenum < 0 ) | |
830 return NULL; | |
831 | |
832 switch( domain ) { | |
833 case DVD_READ_INFO_FILE: | |
834 if( titlenum == 0 ) { | |
835 sprintf( filename, "/VIDEO_TS/VIDEO_TS.IFO" ); | |
836 } else { | |
837 sprintf( filename, "/VIDEO_TS/VTS_%02i_0.IFO", titlenum ); | |
838 } | |
839 break; | |
840 case DVD_READ_INFO_BACKUP_FILE: | |
841 if( titlenum == 0 ) { | |
842 sprintf( filename, "/VIDEO_TS/VIDEO_TS.BUP" ); | |
843 } else { | |
844 sprintf( filename, "/VIDEO_TS/VTS_%02i_0.BUP", titlenum ); | |
845 } | |
846 break; | |
847 case DVD_READ_MENU_VOBS: | |
848 if( dvd->isImageFile ) { | |
849 return DVDOpenVOBUDF( dvd, titlenum, 1 ); | |
850 } else { | |
851 return DVDOpenVOBPath( dvd, titlenum, 1 ); | |
852 } | |
853 break; | |
854 case DVD_READ_TITLE_VOBS: | |
855 if( titlenum == 0 ) return 0; | |
856 if( dvd->isImageFile ) { | |
857 return DVDOpenVOBUDF( dvd, titlenum, 0 ); | |
858 } else { | |
859 return DVDOpenVOBPath( dvd, titlenum, 0 ); | |
860 } | |
861 break; | |
862 default: | |
863 fprintf( stderr, "libdvdread: Invalid domain for file open.\n" ); | |
864 return NULL; | |
865 } | |
20 | 866 |
3 | 867 if( dvd->isImageFile ) { |
868 return DVDOpenFileUDF( dvd, filename ); | |
869 } else { | |
870 return DVDOpenFilePath( dvd, filename ); | |
871 } | |
872 } | |
873 | |
874 void DVDCloseFile( dvd_file_t *dvd_file ) | |
875 { | |
876 int i; | |
877 | |
878 if( dvd_file ) { | |
879 if( dvd_file->dvd->isImageFile ) { | |
880 ; | |
881 } else { | |
882 for( i = 0; i < TITLES_MAX; ++i ) { | |
883 if( dvd_file->title_devs[ i ] ) { | |
884 dvdinput_close( dvd_file->title_devs[i] ); | |
885 } | |
886 } | |
887 } | |
888 | |
889 free( dvd_file ); | |
890 dvd_file = 0; | |
891 } | |
892 } | |
893 | |
894 /* Internal, but used from dvd_udf.c */ | |
895 int UDFReadBlocksRaw( dvd_reader_t *device, uint32_t lb_number, | |
20 | 896 size_t block_count, unsigned char *data, |
3 | 897 int encrypted ) |
898 { | |
899 int ret; | |
900 if( !device->dev ) { | |
901 fprintf( stderr, "libdvdread: Fatal error in block read.\n" ); | |
902 return 0; | |
903 } | |
904 | |
905 ret = dvdinput_seek( device->dev, (int) lb_number ); | |
906 if( ret != (int) lb_number ) { | |
907 fprintf( stderr, "libdvdread: Can't seek to block %u\n", lb_number ); | |
908 return 0; | |
909 } | |
910 | |
20 | 911 ret = dvdinput_read( device->dev, (char *) data, |
3 | 912 (int) block_count, encrypted ); |
913 return ret; | |
914 } | |
915 | |
916 /* This is using a single input and starting from 'dvd_file->lb_start' offset. | |
917 * | |
918 * Reads 'block_count' blocks from 'dvd_file' at block offset 'offset' | |
919 * into the buffer located at 'data' and if 'encrypted' is set | |
920 * descramble the data if it's encrypted. Returning either an | |
921 * negative error or the number of blocks read. */ | |
922 static int DVDReadBlocksUDF( dvd_file_t *dvd_file, uint32_t offset, | |
923 size_t block_count, unsigned char *data, | |
924 int encrypted ) | |
925 { | |
926 return UDFReadBlocksRaw( dvd_file->dvd, dvd_file->lb_start + offset, | |
927 block_count, data, encrypted ); | |
928 } | |
929 | |
930 /* This is using possibly several inputs and starting from an offset of '0'. | |
931 * | |
932 * Reads 'block_count' blocks from 'dvd_file' at block offset 'offset' | |
933 * into the buffer located at 'data' and if 'encrypted' is set | |
934 * descramble the data if it's encrypted. Returning either an | |
935 * negative error or the number of blocks read. */ | |
936 static int DVDReadBlocksPath( dvd_file_t *dvd_file, unsigned int offset, | |
937 size_t block_count, unsigned char *data, | |
938 int encrypted ) | |
939 { | |
940 int i; | |
941 int ret, ret2, off; | |
942 | |
943 ret = 0; | |
944 ret2 = 0; | |
945 for( i = 0; i < TITLES_MAX; ++i ) { | |
946 if( !dvd_file->title_sizes[ i ] ) return 0; /* Past end of file */ | |
947 | |
948 if( offset < dvd_file->title_sizes[ i ] ) { | |
949 if( ( offset + block_count ) <= dvd_file->title_sizes[ i ] ) { | |
950 off = dvdinput_seek( dvd_file->title_devs[ i ], (int)offset ); | |
951 if( off < 0 || off != (int)offset ) { | |
20 | 952 fprintf( stderr, "libdvdread: Can't seek to block %d\n", |
3 | 953 offset ); |
954 return off < 0 ? off : 0; | |
955 } | |
956 ret = dvdinput_read( dvd_file->title_devs[ i ], data, | |
957 (int)block_count, encrypted ); | |
958 break; | |
959 } else { | |
960 size_t part1_size = dvd_file->title_sizes[ i ] - offset; | |
961 /* FIXME: Really needs to be a while loop. | |
962 * (This is only true if you try and read >1GB at a time) */ | |
20 | 963 |
3 | 964 /* Read part 1 */ |
965 off = dvdinput_seek( dvd_file->title_devs[ i ], (int)offset ); | |
966 if( off < 0 || off != (int)offset ) { | |
20 | 967 fprintf( stderr, "libdvdread: Can't seek to block %d\n", |
3 | 968 offset ); |
969 return off < 0 ? off : 0; | |
970 } | |
971 ret = dvdinput_read( dvd_file->title_devs[ i ], data, | |
972 (int)part1_size, encrypted ); | |
973 if( ret < 0 ) return ret; | |
20 | 974 /* FIXME: This is wrong if i is the last file in the set. |
3 | 975 * also error from this read will not show in ret. */ |
20 | 976 |
3 | 977 /* Does the next part exist? If not then return now. */ |
978 if( i + 1 >= TITLES_MAX || !dvd_file->title_devs[ i + 1 ] ) | |
979 return ret; | |
980 | |
981 /* Read part 2 */ | |
982 off = dvdinput_seek( dvd_file->title_devs[ i + 1 ], 0 ); | |
983 if( off < 0 || off != 0 ) { | |
20 | 984 fprintf( stderr, "libdvdread: Can't seek to block %d\n", |
3 | 985 0 ); |
986 return off < 0 ? off : 0; | |
987 } | |
20 | 988 ret2 = dvdinput_read( dvd_file->title_devs[ i + 1 ], |
3 | 989 data + ( part1_size |
990 * (int64_t)DVD_VIDEO_LB_LEN ), | |
991 (int)(block_count - part1_size), | |
992 encrypted ); | |
993 if( ret2 < 0 ) return ret2; | |
994 break; | |
995 } | |
996 } else { | |
997 offset -= dvd_file->title_sizes[ i ]; | |
998 } | |
999 } | |
1000 | |
1001 return ret + ret2; | |
1002 } | |
1003 | |
1004 /* This is broken reading more than 2Gb at a time is ssize_t is 32-bit. */ | |
20 | 1005 ssize_t DVDReadBlocks( dvd_file_t *dvd_file, int offset, |
3 | 1006 size_t block_count, unsigned char *data ) |
1007 { | |
1008 int ret; | |
1009 /* Check arguments. */ | |
1010 if( dvd_file == NULL || offset < 0 || data == NULL ) | |
1011 return -1; | |
20 | 1012 |
3 | 1013 /* Hack, and it will still fail for multiple opens in a threaded app ! */ |
1014 if( dvd_file->dvd->css_title != dvd_file->css_title ) { | |
1015 dvd_file->dvd->css_title = dvd_file->css_title; | |
1016 if( dvd_file->dvd->isImageFile ) { | |
1017 dvdinput_title( dvd_file->dvd->dev, (int)dvd_file->lb_start ); | |
20 | 1018 } |
1019 /* Here each vobu has it's own dvdcss handle, so no need to update | |
3 | 1020 else { |
1021 dvdinput_title( dvd_file->title_devs[ 0 ], (int)dvd_file->lb_start ); | |
1022 }*/ | |
1023 } | |
20 | 1024 |
3 | 1025 if( dvd_file->dvd->isImageFile ) { |
20 | 1026 ret = DVDReadBlocksUDF( dvd_file, (uint32_t)offset, |
3 | 1027 block_count, data, DVDINPUT_READ_DECRYPT ); |
1028 } else { | |
20 | 1029 ret = DVDReadBlocksPath( dvd_file, (unsigned int)offset, |
3 | 1030 block_count, data, DVDINPUT_READ_DECRYPT ); |
1031 } | |
20 | 1032 |
3 | 1033 return (ssize_t)ret; |
1034 } | |
1035 | |
1036 int32_t DVDFileSeek( dvd_file_t *dvd_file, int32_t offset ) | |
1037 { | |
1038 /* Check arguments. */ | |
1039 if( dvd_file == NULL || offset < 0 ) | |
1040 return -1; | |
20 | 1041 |
3 | 1042 if( offset > dvd_file->filesize * DVD_VIDEO_LB_LEN ) { |
1043 return -1; | |
1044 } | |
1045 dvd_file->seek_pos = (uint32_t) offset; | |
1046 return offset; | |
1047 } | |
1048 | |
1049 int DVDFileSeekForce(dvd_file_t *dvd_file, int offset, int force_size) | |
1050 { | |
1051 /* Check arguments. */ | |
1052 if( dvd_file == NULL || offset <= 0 ) | |
1053 return -1; | |
1054 | |
1055 if( dvd_file->dvd->isImageFile ) { | |
1056 if( force_size < 0 ) | |
1057 force_size = (offset - 1) / DVD_VIDEO_LB_LEN + 1; | |
1058 if( dvd_file->filesize < force_size ) { | |
1059 dvd_file->filesize = force_size; | |
1060 fprintf(stderr, "libdvdread: Ignored size of file indicated in UDF.\n"); | |
1061 } | |
1062 } | |
1063 | |
1064 if( offset > dvd_file->filesize * DVD_VIDEO_LB_LEN ) | |
1065 return -1; | |
1066 | |
1067 dvd_file->seek_pos = (uint32_t) offset; | |
1068 return offset; | |
1069 } | |
1070 | |
1071 ssize_t DVDReadBytes( dvd_file_t *dvd_file, void *data, size_t byte_size ) | |
1072 { | |
1073 unsigned char *secbuf_base, *secbuf; | |
1074 unsigned int numsec, seek_sector, seek_byte; | |
1075 int ret; | |
20 | 1076 |
3 | 1077 /* Check arguments. */ |
1078 if( dvd_file == NULL || data == NULL ) | |
1079 return -1; | |
1080 | |
1081 seek_sector = dvd_file->seek_pos / DVD_VIDEO_LB_LEN; | |
1082 seek_byte = dvd_file->seek_pos % DVD_VIDEO_LB_LEN; | |
1083 | |
1084 numsec = ( ( seek_byte + byte_size ) / DVD_VIDEO_LB_LEN ) + | |
1085 ( ( ( seek_byte + byte_size ) % DVD_VIDEO_LB_LEN ) ? 1 : 0 ); | |
20 | 1086 |
3 | 1087 secbuf_base = (unsigned char *) malloc( numsec * DVD_VIDEO_LB_LEN + 2048 ); |
1088 secbuf = (unsigned char *)(((uintptr_t)secbuf_base & ~((uintptr_t)2047)) + 2048); | |
1089 if( !secbuf_base ) { | |
20 | 1090 fprintf( stderr, "libdvdread: Can't allocate memory " |
3 | 1091 "for file read!\n" ); |
1092 return 0; | |
1093 } | |
20 | 1094 |
3 | 1095 if( dvd_file->dvd->isImageFile ) { |
20 | 1096 ret = DVDReadBlocksUDF( dvd_file, (uint32_t) seek_sector, |
3 | 1097 (size_t) numsec, secbuf, DVDINPUT_NOFLAGS ); |
1098 } else { | |
20 | 1099 ret = DVDReadBlocksPath( dvd_file, seek_sector, |
3 | 1100 (size_t) numsec, secbuf, DVDINPUT_NOFLAGS ); |
1101 } | |
1102 | |
1103 if( ret != (int) numsec ) { | |
1104 free( secbuf_base ); | |
1105 return ret < 0 ? ret : 0; | |
1106 } | |
1107 | |
1108 memcpy( data, &(secbuf[ seek_byte ]), byte_size ); | |
1109 free( secbuf_base ); | |
1110 | |
1111 DVDFileSeekForce(dvd_file, dvd_file->seek_pos + byte_size, -1); | |
1112 return byte_size; | |
1113 } | |
1114 | |
1115 ssize_t DVDFileSize( dvd_file_t *dvd_file ) | |
1116 { | |
1117 /* Check arguments. */ | |
1118 if( dvd_file == NULL ) | |
1119 return -1; | |
20 | 1120 |
3 | 1121 return dvd_file->filesize; |
1122 } | |
1123 | |
1124 int DVDDiscID( dvd_reader_t *dvd, unsigned char *discid ) | |
1125 { | |
1126 struct md5_ctx ctx; | |
1127 int title; | |
1128 int nr_of_files = 0; | |
1129 | |
1130 /* Check arguments. */ | |
1131 if( dvd == NULL || discid == NULL ) | |
1132 return 0; | |
20 | 1133 |
1134 /* Go through the first 10 IFO:s, in order, | |
3 | 1135 * and md5sum them, i.e VIDEO_TS.IFO and VTS_0?_0.IFO */ |
1136 md5_init_ctx( &ctx ); | |
1137 for( title = 0; title < 10; title++ ) { | |
1138 dvd_file_t *dvd_file = DVDOpenFile( dvd, title, DVD_READ_INFO_FILE ); | |
1139 if( dvd_file != NULL ) { | |
1140 ssize_t bytes_read; | |
1141 size_t file_size = dvd_file->filesize * DVD_VIDEO_LB_LEN; | |
1142 char *buffer_base = malloc( file_size + 2048 ); | |
7 | 1143 char *buffer = (char *)(((uintptr_t)buffer_base & ~((uintptr_t)2047)) + 2048); |
20 | 1144 |
3 | 1145 if( buffer_base == NULL ) { |
1146 DVDCloseFile( dvd_file ); | |
1147 fprintf( stderr, "libdvdread: DVDDiscId, failed to " | |
1148 "allocate memory for file read!\n" ); | |
1149 return -1; | |
1150 } | |
1151 bytes_read = DVDReadBytes( dvd_file, buffer, file_size ); | |
1152 if( bytes_read != file_size ) { | |
1153 fprintf( stderr, "libdvdread: DVDDiscId read returned %zd bytes" | |
1154 ", wanted %zd\n", bytes_read, file_size ); | |
1155 DVDCloseFile( dvd_file ); | |
1156 free( buffer_base ); | |
1157 return -1; | |
1158 } | |
20 | 1159 |
3 | 1160 md5_process_bytes( buffer, file_size, &ctx ); |
20 | 1161 |
3 | 1162 DVDCloseFile( dvd_file ); |
1163 free( buffer_base ); | |
1164 nr_of_files++; | |
1165 } | |
1166 } | |
1167 md5_finish_ctx( &ctx, discid ); | |
1168 if(!nr_of_files) | |
1169 return -1; | |
20 | 1170 |
3 | 1171 return 0; |
1172 } | |
1173 | |
1174 | |
1175 int DVDISOVolumeInfo( dvd_reader_t *dvd, | |
1176 char *volid, unsigned int volid_size, | |
1177 unsigned char *volsetid, unsigned int volsetid_size ) | |
1178 { | |
1179 unsigned char *buffer, *buffer_base; | |
1180 int ret; | |
1181 | |
1182 /* Check arguments. */ | |
1183 if( dvd == NULL ) | |
1184 return 0; | |
20 | 1185 |
3 | 1186 if( dvd->dev == NULL ) { |
1187 /* No block access, so no ISO... */ | |
1188 return -1; | |
1189 } | |
20 | 1190 |
3 | 1191 buffer_base = malloc( DVD_VIDEO_LB_LEN + 2048 ); |
1192 buffer = (unsigned char *)(((uintptr_t)buffer_base & ~((uintptr_t)2047)) + 2048); | |
1193 | |
1194 if( buffer_base == NULL ) { | |
1195 fprintf( stderr, "libdvdread: DVDISOVolumeInfo, failed to " | |
1196 "allocate memory for file read!\n" ); | |
1197 return -1; | |
1198 } | |
1199 | |
1200 ret = UDFReadBlocksRaw( dvd, 16, 1, buffer, 0 ); | |
1201 if( ret != 1 ) { | |
1202 fprintf( stderr, "libdvdread: DVDISOVolumeInfo, failed to " | |
1203 "read ISO9660 Primary Volume Descriptor!\n" ); | |
1204 free( buffer_base ); | |
1205 return -1; | |
1206 } | |
20 | 1207 |
3 | 1208 if( (volid != NULL) && (volid_size > 0) ) { |
1209 unsigned int n; | |
1210 for(n = 0; n < 32; n++) { | |
1211 if(buffer[40+n] == 0x20) { | |
1212 break; | |
1213 } | |
1214 } | |
20 | 1215 |
3 | 1216 if(volid_size > n+1) { |
1217 volid_size = n+1; | |
1218 } | |
1219 | |
1220 memcpy(volid, &buffer[40], volid_size-1); | |
1221 volid[volid_size-1] = '\0'; | |
1222 } | |
20 | 1223 |
3 | 1224 if( (volsetid != NULL) && (volsetid_size > 0) ) { |
1225 if(volsetid_size > 128) { | |
1226 volsetid_size = 128; | |
1227 } | |
1228 memcpy(volsetid, &buffer[190], volsetid_size); | |
1229 } | |
1230 free( buffer_base ); | |
1231 return 0; | |
1232 } | |
1233 | |
1234 | |
1235 int DVDUDFVolumeInfo( dvd_reader_t *dvd, | |
1236 char *volid, unsigned int volid_size, | |
1237 unsigned char *volsetid, unsigned int volsetid_size ) | |
1238 { | |
1239 int ret; | |
1240 /* Check arguments. */ | |
1241 if( dvd == NULL ) | |
1242 return -1; | |
20 | 1243 |
3 | 1244 if( dvd->dev == NULL ) { |
1245 /* No block access, so no UDF VolumeSet Identifier */ | |
1246 return -1; | |
1247 } | |
20 | 1248 |
3 | 1249 if( (volid != NULL) && (volid_size > 0) ) { |
1250 ret = UDFGetVolumeIdentifier(dvd, volid, volid_size); | |
1251 if(!ret) { | |
1252 return -1; | |
1253 } | |
1254 } | |
1255 if( (volsetid != NULL) && (volsetid_size > 0) ) { | |
1256 ret = UDFGetVolumeSetIdentifier(dvd, volsetid, volsetid_size); | |
1257 if(!ret) { | |
1258 return -1; | |
1259 } | |
1260 } | |
20 | 1261 |
1262 return 0; | |
3 | 1263 } |