From 80dee3f8ac591919a1f78724d31049f5b4472f42 Mon Sep 17 00:00:00 2001 From: diego Date: Wed, 15 Aug 2007 11:47:22 +0000 Subject: Sync libdvdread with version 0.9.5 (functional changes). git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@24067 b3059339-0415-0410-9bf9-f77b7e298cf2 --- Changelog | 1 + Copyright | 2 +- configure | 3 + dvdread/Makefile | 1 + dvdread/bswap.h | 14 +- dvdread/dvd_input.c | 104 ++++++++--- dvdread/dvd_input.h | 7 + dvdread/dvd_reader.c | 436 +++++++++++++++++++++++++++++++++++++-------- dvdread/dvd_reader.h | 44 ++++- dvdread/dvd_udf.c | 282 +++++++++++++++++++++++++---- dvdread/dvd_udf.h | 6 +- dvdread/dvdread_internal.h | 4 + dvdread/ifo_print.c | 91 +++++++--- dvdread/ifo_read.c | 246 ++++++++++++++++++++----- dvdread/ifo_types.h | 62 ++++--- dvdread/nav_print.c | 8 +- dvdread/nav_read.c | 4 + dvdread/nav_types.h | 3 +- stream/stream_dvd_common.c | 1 + 19 files changed, 1086 insertions(+), 233 deletions(-) diff --git a/Changelog b/Changelog index ce5f0319b1..2359e96e8d 100644 --- a/Changelog +++ b/Changelog @@ -112,6 +112,7 @@ MPlayer (1.0) * ability to change subtitle size during playback * ability to turn loop on/off during playback * Apple Remote support + * libdvdread updated to 0.9.5 rc1: "Codename intentionally left blank" October 22, 2006 diff --git a/Copyright b/Copyright index eb235db438..4ca0aba441 100644 --- a/Copyright +++ b/Copyright @@ -49,7 +49,7 @@ Copyright: 1998-2006 VideoLAN License: GNU General Public License Name: libdvdread -Version: 0.9.4 + patches +Version: 0.9.5 + patches Homepage: http://www.dtek.chalmers.se/groups/dvd/development.shtml Directory: dvdread Copyright: 1998, 1999 Eric Smith diff --git a/configure b/configure index 5935be5d2e..4e37e6814b 100755 --- a/configure +++ b/configure @@ -7744,6 +7744,9 @@ $_def_fast_inttypes #define HAVE_MEMCPY 1 #define HAVE_STRCHR 1 +/* libdvdread */ +#define HAVE_UINTPTR_T 1 + /* name of messages charset */ $_def_charset diff --git a/dvdread/Makefile b/dvdread/Makefile index 77f2e1c2ee..c79375e755 100644 --- a/dvdread/Makefile +++ b/dvdread/Makefile @@ -10,6 +10,7 @@ SRCS_COMMON = dvd_input.c \ nav_print.c \ nav_read.c \ md5.c \ + cmd_print.c \ CFLAGS = -D__USE_UNIX98 -D_GNU_SOURCE diff --git a/dvdread/bswap.h b/dvdread/bswap.h index c612025b31..a5296b82cd 100644 --- a/dvdread/bswap.h +++ b/dvdread/bswap.h @@ -61,7 +61,19 @@ #include #define B2N_16(x) x = be16toh(x) #define B2N_32(x) x = be32toh(x) +#if __FreeBSD_version >= 500000 #define B2N_64(x) x = be64toh(x) +#else +#define B2N_64(x) \ + x = ((((x) & 0xff00000000000000) >> 56) | \ + (((x) & 0x00ff000000000000) >> 40) | \ + (((x) & 0x0000ff0000000000) >> 24) | \ + (((x) & 0x000000ff00000000) >> 8) | \ + (((x) & 0x00000000ff000000) << 8) | \ + (((x) & 0x0000000000ff0000) << 24) | \ + (((x) & 0x000000000000ff00) << 40) | \ + (((x) & 0x00000000000000ff) << 56)) +#endif /* _FreeBSD_version >= 500000 */ #elif defined(__DragonFly__) #include @@ -113,7 +125,7 @@ inline static unsigned long long int bswap_64(unsigned long long int x) * functionality! */ -#elif defined(__FreeBSD__) || defined(__sun) || defined(__bsdi__) || defined(__CYGWIN__) +#elif defined(__FreeBSD__) || defined(__sun) || defined(__bsdi__) || defined(WIN32) || defined(__BEOS__) || defined(__INTERIX) || defined(__CYGWIN__) #define B2N_16(x) \ x = ((((x) & 0xff00) >> 8) | \ (((x) & 0x00ff) << 8)) diff --git a/dvdread/dvd_input.c b/dvdread/dvd_input.c index 341c9882d4..dcd5307862 100644 --- a/dvdread/dvd_input.c +++ b/dvdread/dvd_input.c @@ -25,18 +25,26 @@ #include #include +#define __USE_GNU /* to get O_DIRECT in linux */ #include #include #include "dvd_reader.h" #include "dvd_input.h" +#include "dvdread_internal.h" + /* The function pointers that is the exported interface of this file. */ dvd_input_t (*dvdinput_open) (const char *); int (*dvdinput_close) (dvd_input_t); int (*dvdinput_seek) (dvd_input_t, int); int (*dvdinput_title) (dvd_input_t, int); +/** + * pointer must be aligned to 2048 bytes + * if reading from a raw/O_DIRECT file + */ int (*dvdinput_read) (dvd_input_t, void *, int, int); + char * (*dvdinput_error) (dvd_input_t); #ifdef HAVE_DVDCSS_DVDCSS_H @@ -80,16 +88,15 @@ static dvd_input_t css_open(const char *target) /* Allocate the handle structure */ dev = (dvd_input_t) malloc(sizeof(struct dvd_input_s)); if(dev == NULL) { - fprintf(stderr, "libdvdread: Could not allocate memory.\n"); + /* malloc has set errno to ENOMEM */ return NULL; } /* Really open it with libdvdcss */ dev->dvdcss = DVDcss_open(target); if(dev->dvdcss == 0) { - fprintf(stderr, "libdvdread: Could not open %s with libdvdcss.\n", target); free(dev); - return NULL; + dev = NULL; } return dev; @@ -145,10 +152,14 @@ static int css_close(dvd_input_t dev) return 0; } - - - - +/* Need to use O_BINARY for WIN32 */ +#ifndef O_BINARY +#ifdef _O_BINARY +#define O_BINARY _O_BINARY +#else +#define O_BINARY 0 +#endif +#endif /** * initialize and open a DVD device or file. @@ -156,18 +167,26 @@ static int css_close(dvd_input_t dev) static dvd_input_t file_open(const char *target) { dvd_input_t dev; + char *use_odirect; + int oflags; + oflags = O_RDONLY | O_BINARY; + use_odirect = getenv("DVDREAD_USE_DIRECT"); + if(use_odirect) { +#ifndef O_DIRECT +#define O_DIRECT 0 +#endif + oflags |= O_DIRECT; + } /* Allocate the library structure */ dev = (dvd_input_t) malloc(sizeof(struct dvd_input_s)); if(dev == NULL) { - fprintf(stderr, "libdvdread: Could not allocate memory.\n"); return NULL; } /* Open the device */ - dev->fd = open(target, O_RDONLY); + dev->fd = open(target, oflags); if(dev->fd < 0) { - perror("libdvdread: Could not open input"); free(dev); return NULL; } @@ -189,9 +208,9 @@ static char *file_error(dvd_input_t dev) */ static int file_seek(dvd_input_t dev, int blocks) { - off_t pos; + off_t pos = (off_t)blocks * (off_t)DVD_VIDEO_LB_LEN; - pos = lseek(dev->fd, (off_t)blocks * (off_t)DVD_VIDEO_LB_LEN, SEEK_SET); + pos = lseek(dev->fd, pos, SEEK_SET); if(pos < 0) { return pos; } @@ -214,12 +233,13 @@ static int file_read(dvd_input_t dev, void *buffer, int blocks, int flags) { size_t len; ssize_t ret; + unsigned char *buf = buffer; len = (size_t)blocks * DVD_VIDEO_LB_LEN; while(len > 0) { - ret = read(dev->fd, buffer, len); + ret = read(dev->fd, buf, len); if(ret < 0) { /* One of the reads failed, too bad. We won't even bother @@ -238,6 +258,7 @@ static int file_read(dvd_input_t dev, void *buffer, int blocks, int flags) return (int) (bytes / DVD_VIDEO_LB_LEN); } + buf+=ret; len -= ret; } @@ -262,13 +283,49 @@ static int file_close(dvd_input_t dev) } +static void *dvdcss_library = NULL; +static int dvdcss_library_init = 0; + +/** + * Free any objects allocated by dvdinput_setup. + * Should only be called when libdvdread is not to be used any more. + * Closes dlopened libraries. + */ +void dvdinput_free(void) +{ +#ifdef HAVE_DVDCSS_DVDCSS_H + /* linked statically, nothing to free */ + return; +#else + if(dvdcss_library) { + dlclose(dvdcss_library); + dvdcss_library = NULL; + } + dvdcss_library_init = 0; + return; +#endif +} + + /** * Setup read functions with either libdvdcss or minimal DVD access. */ int dvdinput_setup(void) { - void *dvdcss_library = NULL; char **dvdcss_version = NULL; + int verbose; + + /* dlopening libdvdcss */ + if(dvdcss_library_init) { + /* libdvdcss is already dlopened, function ptrs set */ + if(dvdcss_library) { + return 1; /* css available */ + } else { + return 0; /* css not available */ + } + } + + verbose = get_verbose(); #ifdef HAVE_DVDCSS_DVDCSS_H /* linking to libdvdcss */ @@ -277,7 +334,7 @@ int dvdinput_setup(void) dvdcss_version = &dvdcss_interface_2; #else - /* dlopening libdvdcss */ + dvdcss_library = dlopen("libdvdcss.so.2", RTLD_LAZY); if(dvdcss_library != NULL) { @@ -302,33 +359,39 @@ int dvdinput_setup(void) dvdcss_version = (char **)dlsym(dvdcss_library, U_S "dvdcss_interface_2"); if(dlsym(dvdcss_library, U_S "dvdcss_crack")) { + if(verbose >= 0) { fprintf(stderr, "libdvdread: Old (pre-0.0.2) version of libdvdcss found.\n" "libdvdread: You should get the latest version from " "http://www.videolan.org/\n" ); + } dlclose(dvdcss_library); dvdcss_library = NULL; } else if(!DVDcss_open || !DVDcss_close || !DVDcss_title || !DVDcss_seek || !DVDcss_read || !DVDcss_error || !dvdcss_version) { + if(verbose >= 0) { fprintf(stderr, "libdvdread: Missing symbols in libdvdcss.so.2, " "this shouldn't happen !\n"); + } dlclose(dvdcss_library); + dvdcss_library = NULL; } } #endif /* HAVE_DVDCSS_DVDCSS_H */ - if(dvdcss_library != NULL) { + dvdcss_library_init = 1; + + if(dvdcss_library) { /* char *psz_method = getenv( "DVDCSS_METHOD" ); char *psz_verbose = getenv( "DVDCSS_VERBOSE" ); fprintf(stderr, "DVDCSS_METHOD %s\n", psz_method); fprintf(stderr, "DVDCSS_VERBOSE %s\n", psz_verbose); */ - /* + if(verbose >= 1) { fprintf(stderr, "libdvdread: Using libdvdcss version %s for DVD access\n", *dvdcss_version); - */ - + } /* libdvdcss wrapper functions */ dvdinput_open = css_open; dvdinput_close = css_close; @@ -339,8 +402,9 @@ int dvdinput_setup(void) return 1; } else { + if(verbose >= 1) { fprintf(stderr, "libdvdread: Encrypted DVD support unavailable.\n"); - + } /* libdvdcss replacement functions */ dvdinput_open = file_open; dvdinput_close = file_close; diff --git a/dvdread/dvd_input.h b/dvdread/dvd_input.h index e9e84917ea..0f05c97952 100644 --- a/dvdread/dvd_input.h +++ b/dvdread/dvd_input.h @@ -39,6 +39,13 @@ extern int (*dvdinput_title) (dvd_input_t, int); extern int (*dvdinput_read) (dvd_input_t, void *, int, int); extern char * (*dvdinput_error) (dvd_input_t); +/** + * Free any objects allocated by dvdinput_setup. + * Should only be called when libdvdread is not to be used any more. + * Closes dlopened libraries. + */ +void dvdinput_free(void); + /** * Setup function accessed by dvd_reader.c. Returns 1 if there is CSS support. */ diff --git a/dvdread/dvd_reader.c b/dvdread/dvd_reader.c index d944696c15..92d202b8d9 100644 --- a/dvdread/dvd_reader.c +++ b/dvdread/dvd_reader.c @@ -60,11 +60,13 @@ static void gettimeofday(struct timeval* t,void* timezone){ } #endif -#include "dvd_udf.h" -#include "dvd_input.h" #include "dvd_reader.h" +#include "dvd_input.h" +#include "dvd_udf.h" #include "md5.h" +#include "dvdread_internal.h" + #define DEFAULT_UDF_CACHE_LEVEL 0 struct dvd_reader_s { @@ -85,6 +87,12 @@ struct dvd_reader_s { /* Filesystem cache */ int udfcache_level; /* 0 - turned off, 1 - on */ void *udfcache; + + /* block aligned malloc */ + void *align; + + /* error message verbosity level */ + int verbose; }; struct dvd_file_s { @@ -106,6 +114,42 @@ struct dvd_file_s { ssize_t filesize; }; + +#define DVDREAD_VERBOSE_DEFAULT 0 + +int get_verbose(void) +{ + char *dvdread_verbose; + int verbose; + + dvdread_verbose = getenv("DVDREAD_VERBOSE"); + if(dvdread_verbose) { + verbose = (int)strtol(dvdread_verbose, NULL, 0); + } else { + verbose = DVDREAD_VERBOSE_DEFAULT; + } + return verbose; +} + +int dvdread_verbose(dvd_reader_t *dvd) +{ + return dvd->verbose; +} + +dvd_reader_t *device_of_file(dvd_file_t *file) +{ + return file->dvd; +} + +/** + * Returns the compiled version. (DVDREAD_VERSION as an int) + */ +int DVDVersion(void) +{ + return DVDREAD_VERSION; +} + + /** * Set the level of caching on udf * level = 0 (no caching) @@ -140,6 +184,31 @@ void SetUDFCacheHandle(dvd_reader_t *device, void *cache) dev->udfcache = cache; } +void *GetAlignHandle(dvd_reader_t *device) +{ + struct dvd_reader_s *dev = (struct dvd_reader_s *)device; + + return dev->align; +} + +void SetAlignHandle(dvd_reader_t *device, void *align) +{ + struct dvd_reader_s *dev = (struct dvd_reader_s *)device; + + dev->align = align; +} + +#ifdef WIN32 /* replacement gettimeofday implementation */ +#include +static int gettimeofday( struct timeval *tv, void *tz ) +{ + struct timeb t; + ftime( &t ); + tv->tv_sec = t.time; + tv->tv_usec = t.millitm * 1000; + return 0; +} +#endif /* Loop over all titles and call dvdcss_title to crack the keys. */ @@ -155,11 +224,12 @@ static int initAllCSSKeys( dvd_reader_t *dvd ) if(nokeys_str != NULL) return 0; + if(dvd->verbose >= 1) { fprintf( stderr, "\n" ); fprintf( stderr, "libdvdread: Attempting to retrieve all CSS keys\n" ); fprintf( stderr, "libdvdread: This can take a _long_ time, " "please be patient\n\n" ); - + } gettimeofday(&all_s, NULL); for( title = 0; title < 100; title++ ) { @@ -172,15 +242,21 @@ static int initAllCSSKeys( dvd_reader_t *dvd ) start = UDFFindFile( dvd, filename, &len ); if( start != 0 && len != 0 ) { /* Perform CSS key cracking for this title. */ + if(dvd->verbose >= 1) { fprintf( stderr, "libdvdread: Get key for %s at 0x%08x\n", filename, start ); + } if( dvdinput_title( dvd->dev, (int)start ) < 0 ) { + if(dvd->verbose >= 0) { fprintf( stderr, "libdvdread: Error cracking CSS key for %s (0x%08x)\n", filename, start); } + } gettimeofday( &t_e, NULL ); + if(dvd->verbose >= 1) { fprintf( stderr, "libdvdread: Elapsed time %ld\n", (long int) t_e.tv_sec - t_s.tv_sec ); } + } if( title == 0 ) continue; @@ -190,22 +266,31 @@ static int initAllCSSKeys( dvd_reader_t *dvd ) if( start == 0 || len == 0 ) break; /* Perform CSS key cracking for this title. */ + if(dvd->verbose >= 1) { fprintf( stderr, "libdvdread: Get key for %s at 0x%08x\n", filename, start ); + } if( dvdinput_title( dvd->dev, (int)start ) < 0 ) { + if(dvd->verbose >= 0) { fprintf( stderr, "libdvdread: Error cracking CSS key for %s (0x%08x)!!\n", filename, start); } + } gettimeofday( &t_e, NULL ); + if(dvd->verbose >= 1) { fprintf( stderr, "libdvdread: Elapsed time %ld\n", (long int) t_e.tv_sec - t_s.tv_sec ); } + } title--; + if(dvd->verbose >= 1) { fprintf( stderr, "libdvdread: Found %d VTS's\n", title ); + } gettimeofday(&all_e, NULL); + if(dvd->verbose >= 1) { fprintf( stderr, "libdvdread: Elapsed time %ld\n", (long int) all_e.tv_sec - all_s.tv_sec ); - + } return 0; } @@ -213,27 +298,43 @@ static int initAllCSSKeys( dvd_reader_t *dvd ) /** * Open a DVD image or block device file. + * Checks if the root directory in the udf image file can be found. + * If not it assumes this isn't a valid udf image and returns NULL */ static dvd_reader_t *DVDOpenImageFile( const char *location, int have_css ) { dvd_reader_t *dvd; dvd_input_t dev; + int verbose; + + verbose = get_verbose(); dev = dvdinput_open( location ); if( !dev ) { - fprintf( stderr, "libdvdread: Can't open %s for reading\n", location ); - return 0; + if(verbose >= 1) { + fprintf( stderr, "libdvdread: Can't open '%s' for reading: %s\n", + location, strerror(errno)); + } + return NULL; } dvd = (dvd_reader_t *) malloc( sizeof( dvd_reader_t ) ); - if( !dvd ) return 0; + if( !dvd ) { + int tmp_errno = errno; + dvdinput_close(dev); + errno = tmp_errno; + return NULL; + } + dvd->verbose = verbose; dvd->isImageFile = 1; dvd->dev = dev; - dvd->path_root = 0; + dvd->path_root = NULL; dvd->udfcache_level = DEFAULT_UDF_CACHE_LEVEL; dvd->udfcache = NULL; + dvd->align = NULL; + if( have_css ) { /* Only if DVDCSS_METHOD = title, a bit if it's disc or if * DVDCSS_METHOD = key but region missmatch. Unfortunaly we @@ -243,6 +344,20 @@ static dvd_reader_t *DVDOpenImageFile( const char *location, int have_css ) } dvd->css_title = 0; + /* sanity check, is it a valid UDF image, can we find the root dir */ + if(!UDFFindFile(dvd, "/", NULL)) { + dvdinput_close(dvd->dev); + if(dvd->udfcache) { + FreeUDFCache(dvd, dvd->udfcache); + } + if(dvd->align) { + if(dvd->verbose >= 0) { + fprintf(stderr, "libdvdread: DVDOpenImageFile(): Memory leak in align functions 1\n"); + } + } + free(dvd); + return NULL; + } return dvd; } @@ -251,14 +366,22 @@ static dvd_reader_t *DVDOpenPath( const char *path_root ) dvd_reader_t *dvd; dvd = (dvd_reader_t *) malloc( sizeof( dvd_reader_t ) ); - if( !dvd ) return 0; + if( !dvd ) { + return NULL; + } + dvd->verbose = get_verbose(); dvd->isImageFile = 0; dvd->dev = 0; dvd->path_root = strdup( path_root ); - + if(!dvd->path_root) { + free(dvd); + return 0; + } dvd->udfcache_level = DEFAULT_UDF_CACHE_LEVEL; dvd->udfcache = NULL; + dvd->align = NULL; + dvd->css_state = 0; /* Only used in the UDF path */ dvd->css_title = 0; /* Only matters in the UDF path */ @@ -320,10 +443,16 @@ dvd_reader_t *DVDOpen( const char *path ) { struct stat fileinfo; int ret, have_css; - char *dev_name = 0; + char *dev_name = NULL; + int internal_errno = 0; + int verbose; - if( path == NULL ) - return 0; + if( path == NULL ) { + errno = EINVAL; + return NULL; + } + + verbose = get_verbose(); #ifdef WIN32 /* Stat doesn't work on devices under mingwin/cygwin. */ @@ -337,10 +466,14 @@ dvd_reader_t *DVDOpen( const char *path ) { ret = stat( path, &fileinfo ); if( ret < 0 ) { + int tmp_errno = errno; /* If we can't stat the file, give up */ - fprintf( stderr, "libdvdread: Can't stat %s\n", path ); - perror(""); - return 0; + if(verbose >= 1) { + fprintf( stderr, "libdvdread: Can't stat '%s': %s\n", + path, strerror(errno)); + } + errno = tmp_errno; + return NULL; } } @@ -375,24 +508,38 @@ dvd_reader_t *DVDOpen( const char *path ) /* XXX: We should scream real loud here. */ if( !(path_copy = strdup( path ) ) ) return 0; +#ifndef WIN32 /* don't have fchdir, and getcwd( NULL, ... ) is strange */ /* Resolve any symlinks and get the absolut dir name. */ { char *new_path; - int cdir = open( ".", O_RDONLY ); + char *current_path; - if( cdir >= 0 ) { + current_path = malloc(PATH_MAX); + if(current_path) { + if(!getcwd(current_path, PATH_MAX)) { + free(current_path); + current_path = NULL; + } + } + if(current_path) { chdir( path_copy ); - new_path = getcwd( NULL, PATH_MAX ); -#ifndef __MINGW32__ - fchdir( cdir ); -#endif - close( cdir ); + new_path = malloc(PATH_MAX); + if(new_path) { + if(!getcwd(new_path, PATH_MAX )) { + free(new_path); + new_path = NULL; + } + } + + chdir(current_path); + free(current_path); if( new_path ) { free( path_copy ); path_copy = new_path; } } } +#endif /** * If we're being asked to open a directory, check if that directory @@ -400,26 +547,37 @@ dvd_reader_t *DVDOpen( const char *path ) */ if( strlen( path_copy ) > 1 ) { - if( path_copy[ strlen( path_copy ) - 1 ] == '/' ) + if( path_copy[ strlen( path_copy ) - 1 ] == '/' ) { path_copy[ strlen( path_copy ) - 1 ] = '\0'; } + } - if( strlen( path_copy ) > 9 ) { + if( strlen( path_copy ) >= 9 ) { if( !strcasecmp( &(path_copy[ strlen( path_copy ) - 9 ]), "/video_ts" ) ) { path_copy[ strlen( path_copy ) - 9 ] = '\0'; + if(path_copy[0] == '\0') { + path_copy[0] = '/'; + path_copy[1] = '\0'; + } } } #if defined(SYS_BSD) if( ( fe = getfsfile( path_copy ) ) ) { dev_name = bsd_block2char( fe->fs_spec ); + if(verbose >= 1) { fprintf( stderr, "libdvdread: Attempting to use device %s" - " mounted on %s for CSS authentication\n", + " mounted on %s%s\n", dev_name, - fe->fs_file ); + fe->fs_file, + have_css ? " for CSS authentication" : ""); + } auth_drive = DVDOpenImageFile( dev_name, have_css ); + if(!auth_drive) { + internal_errno = errno; + } } #elif defined(__sun) mntfile = fopen( MNTTAB, "r" ); @@ -430,12 +588,18 @@ dvd_reader_t *DVDOpen( const char *path ) while( ( res = getmntent( mntfile, &mp ) ) != -1 ) { if( res == 0 && !strcmp( mp.mnt_mountp, path_copy ) ) { dev_name = sun_block2char( mp.mnt_special ); + if(verbose >= 1) { fprintf( stderr, "libdvdread: Attempting to use device %s" - " mounted on %s for CSS authentication\n", + " mounted on %s%s\n", dev_name, - mp.mnt_mountp ); + mp.mnt_mountp, + have_css ? " for CSS authentication" : ""); + } auth_drive = DVDOpenImageFile( dev_name, have_css ); + if(!auth_drive) { + internal_errno = errno; + } break; } } @@ -448,12 +612,18 @@ dvd_reader_t *DVDOpen( const char *path ) while( ( me = getmntent( mntfile ) ) ) { if( !strcmp( me->mnt_dir, path_copy ) ) { + if(verbose >= 1) { fprintf( stderr, "libdvdread: Attempting to use device %s" - " mounted on %s for CSS authentication\n", + " mounted on %s%s\n", me->mnt_fsname, - me->mnt_dir ); + me->mnt_dir, + have_css ? " for CSS authentication" : ""); + } auth_drive = DVDOpenImageFile( me->mnt_fsname, have_css ); + if(!auth_drive) { + internal_errno = errno; + } dev_name = strdup(me->mnt_fsname); break; } @@ -465,10 +635,16 @@ dvd_reader_t *DVDOpen( const char *path ) auth_drive = DVDOpenImageFile( path, have_css ); #endif if( !dev_name ) { + if(verbose >= 1) { fprintf( stderr, "libdvdread: Couldn't find device name.\n" ); + } } else if( !auth_drive ) { - fprintf( stderr, "libdvdread: Device %s inaccessible, " - "CSS authentication not available.\n", dev_name ); + if(verbose >= 1) { + fprintf( stderr, "libdvdread: Device %s inaccessible%s: %s\n", + dev_name, + have_css ? ", CSS authentication not available" : "", + strerror(internal_errno)); + } } free( dev_name ); @@ -477,8 +653,9 @@ dvd_reader_t *DVDOpen( const char *path ) /** * If we've opened a drive, just use that. */ - if( auth_drive ) return auth_drive; - + if( auth_drive ) { + return auth_drive; + } /** * Otherwise, we now try to open the directory tree instead. */ @@ -486,7 +663,9 @@ dvd_reader_t *DVDOpen( const char *path ) } /* If it's none of the above, screw it. */ + if(verbose >= 1) { fprintf( stderr, "libdvdread: Could not open %s\n", path ); + } return 0; } @@ -495,11 +674,27 @@ void DVDClose( dvd_reader_t *dvd ) if( dvd ) { if( dvd->dev ) dvdinput_close( dvd->dev ); if( dvd->path_root ) free( dvd->path_root ); - if( dvd->udfcache ) FreeUDFCache( dvd->udfcache ); + if( dvd->udfcache ) FreeUDFCache( dvd, dvd->udfcache ); + if(dvd->align) { + if(dvd->verbose >= 0) { + fprintf(stderr, "libdvdread: DVDClose(): Memory leak in align functions\n"); + } + } + dvdinput_free(); free( dvd ); } } +void DVDInit(void) +{ + dvdinput_setup(); +} + +void DVDFinish(void) +{ + dvdinput_free(); +} + /** * Open an unencrypted file on a DVD image file. */ @@ -542,10 +737,11 @@ static int findDirFile( const char *path, const char *file, char *filename ) sprintf( filename, "%s%s%s", path, ( ( path[ strlen( path ) - 1 ] == '/' ) ? "" : "/" ), ent->d_name ); + closedir(dir); return 0; } } - + closedir(dir); return -1; } @@ -606,7 +802,9 @@ static dvd_file_t *DVDOpenFilePath( dvd_reader_t *dvd, char *filename ) dvd_file->filesize = 0; if( stat( full_path, &fileinfo ) < 0 ) { + if(dvd->verbose >= 1) { fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename ); + } free( dvd_file ); return 0; } @@ -704,7 +902,9 @@ static dvd_file_t *DVDOpenVOBPath( dvd_reader_t *dvd, int title, int menu ) } if( stat( full_path, &fileinfo ) < 0 ) { + if(dvd->verbose >= 1) { fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename ); + } free( dvd_file ); return 0; } @@ -722,7 +922,9 @@ static dvd_file_t *DVDOpenVOBPath( dvd_reader_t *dvd, int title, int menu ) } if( stat( full_path, &fileinfo ) < 0 ) { + if(dvd->verbose >= 1) { fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename ); + } break; } @@ -746,8 +948,10 @@ dvd_file_t *DVDOpenFile( dvd_reader_t *dvd, int titlenum, char filename[ MAX_UDF_FILE_NAME_LEN ]; /* Check arguments. */ - if( dvd == NULL || titlenum < 0 ) + if( dvd == NULL || titlenum < 0 ) { + errno = EINVAL; return NULL; + } switch( domain ) { case DVD_READ_INFO_FILE: @@ -780,7 +984,10 @@ dvd_file_t *DVDOpenFile( dvd_reader_t *dvd, int titlenum, } break; default: + if(dvd->verbose >= 1) { fprintf( stderr, "libdvdread: Invalid domain for file open.\n" ); + } + errno = EINVAL; return NULL; } @@ -811,7 +1018,20 @@ void DVDCloseFile( dvd_file_t *dvd_file ) } } -/* Internal, but used from dvd_udf.c */ +/** + * Internal, but used from dvd_udf.c + * + * @param device A read handle. + * @param lb_number Logical block number to start read from. + * @param block_count Number of logical blocks to read. + * @param data Pointer to buffer where read data should be stored. + * This buffer must be large enough to hold lb_number*2048 bytes. + * The pointer must be aligned to the logical block size when + * reading from a raw/O_DIRECT device. + * @param encrypted 0 if no decryption shall be performed, + * 1 if decryption shall be performed + * @param return Returns number of blocks read on success, negative on error + */ int UDFReadBlocksRaw( dvd_reader_t *device, uint32_t lb_number, size_t block_count, unsigned char *data, int encrypted ) @@ -819,13 +1039,19 @@ int UDFReadBlocksRaw( dvd_reader_t *device, uint32_t lb_number, int ret; if( !device->dev ) { + if(device->verbose >= 1) { fprintf( stderr, "libdvdread: Fatal error in block read.\n" ); + } return 0; } ret = dvdinput_seek( device->dev, (int) lb_number ); if( ret != (int) lb_number ) { - fprintf( stderr, "libdvdread: Can't seek to block %u\n", lb_number ); + if(device->verbose >= 1) { + fprintf( stderr, + "libdvdread: UDFReadBlocksRaw: Can't seek to block %u\n", + lb_number ); + } return 0; } @@ -833,12 +1059,20 @@ int UDFReadBlocksRaw( dvd_reader_t *device, uint32_t lb_number, (int) block_count, encrypted ); } -/* This is using a single input and starting from 'dvd_file->lb_start' offset. +/** + * This is using a single input and starting from 'dvd_file->lb_start' offset. * * Reads 'block_count' blocks from 'dvd_file' at block offset 'offset' * into the buffer located at 'data' and if 'encrypted' is set * descramble the data if it's encrypted. Returning either an - * negative error or the number of blocks read. */ + * negative error or the number of blocks read. + * + * @param data Pointer to buffer where read data should be placed. + * This buffer must be large enough to hold block_count*2048 bytes. + * The pointer must be aligned to 2048 bytes when reading from + * a raw/O_DIRECT device. + * @return Returns the number of blocks read on success or a negative error. + */ static int DVDReadBlocksUDF( dvd_file_t *dvd_file, uint32_t offset, size_t block_count, unsigned char *data, int encrypted ) @@ -847,12 +1081,19 @@ static int DVDReadBlocksUDF( dvd_file_t *dvd_file, uint32_t offset, block_count, data, encrypted ); } -/* This is using possibly several inputs and starting from an offset of '0'. - * +/** + * This is using possibly several inputs and starting from an offset of '0'. + * data must be aligned to logical block size (2048 bytes) of the device + * for raw/O_DIRECT devices to work * Reads 'block_count' blocks from 'dvd_file' at block offset 'offset' * into the buffer located at 'data' and if 'encrypted' is set * descramble the data if it's encrypted. Returning either an - * negative error or the number of blocks read. */ + * negative error or the number of blocks read. + * + * @param dvd_file A file read handle. + * @param offset Block offset from start of file. + * @return Returns number of blocks read on success, negative on error. + */ static int DVDReadBlocksPath( dvd_file_t *dvd_file, unsigned int offset, size_t block_count, unsigned char *data, int encrypted ) @@ -869,8 +1110,10 @@ static int DVDReadBlocksPath( dvd_file_t *dvd_file, unsigned int offset, if( ( offset + block_count ) <= dvd_file->title_sizes[ i ] ) { off = dvdinput_seek( dvd_file->title_devs[ i ], (int)offset ); if( off < 0 || off != (int)offset ) { - fprintf( stderr, "libdvdread: Can't seek to block %d\n", + if(dvd_file->dvd->verbose >= 1) { + fprintf( stderr, "libdvdread: DVDReadBlocksPath1: Can't seek to block %d\n", offset ); + } return off < 0 ? off : 0; } ret = dvdinput_read( dvd_file->title_devs[ i ], data, @@ -884,8 +1127,10 @@ static int DVDReadBlocksPath( dvd_file_t *dvd_file, unsigned int offset, /* Read part 1 */ off = dvdinput_seek( dvd_file->title_devs[ i ], (int)offset ); if( off < 0 || off != (int)offset ) { - fprintf( stderr, "libdvdread: Can't seek to block %d\n", + if(dvd_file->dvd->verbose >= 1) { + fprintf( stderr, "libdvdread: DVDReadBlocksPath2: Can't seek to block %d\n", offset ); + } return off < 0 ? off : 0; } ret = dvdinput_read( dvd_file->title_devs[ i ], data, @@ -900,8 +1145,9 @@ static int DVDReadBlocksPath( dvd_file_t *dvd_file, unsigned int offset, /* Read part 2 */ off = dvdinput_seek( dvd_file->title_devs[ i + 1 ], 0 ); if( off < 0 || off != 0 ) { - fprintf( stderr, "libdvdread: Can't seek to block %d\n", - 0 ); + if(dvd_file->dvd->verbose >= 1) { + fprintf( stderr, "libdvdread: DVDReadBlocksPath3: Can't seek to block %d\n", 0 ); + } return off < 0 ? off : 0; } ret2 = dvdinput_read( dvd_file->title_devs[ i + 1 ], @@ -920,7 +1166,9 @@ static int DVDReadBlocksPath( dvd_file_t *dvd_file, unsigned int offset, return ret + ret2; } -/* This is broken reading more than 2Gb at a time is ssize_t is 32-bit. */ +/** + * This is broken reading more than 2Gb at a time if ssize_t is 32-bit. + */ ssize_t DVDReadBlocks( dvd_file_t *dvd_file, int offset, size_t block_count, unsigned char *data ) { @@ -966,29 +1214,41 @@ int DVDFileSeek( dvd_file_t *dvd_file, int offset ) return offset; } +#ifndef HAVE_UINTPTR_T +#warning "Assuming that (unsigned long) can hold (void *)" +typedef unsigned long uintptr_t; +#endif + +#define DVD_ALIGN(ptr) (void *)((((uintptr_t)(ptr)) + (DVD_VIDEO_LB_LEN-1)) \ + / DVD_VIDEO_LB_LEN * DVD_VIDEO_LB_LEN) + ssize_t DVDReadBytes( dvd_file_t *dvd_file, void *data, size_t byte_size ) { - unsigned char *secbuf; + unsigned char *secbuf_start; + unsigned char *secbuf; //must be aligned to 2048-bytes for raw/O_DIRECT unsigned int numsec, seek_sector, seek_byte; int ret; /* Check arguments. */ - if( dvd_file == NULL || data == NULL ) + if( dvd_file == NULL || data == NULL ) { + errno = EINVAL; return -1; - + } seek_sector = dvd_file->seek_pos / DVD_VIDEO_LB_LEN; seek_byte = dvd_file->seek_pos % DVD_VIDEO_LB_LEN; numsec = ( ( seek_byte + byte_size ) / DVD_VIDEO_LB_LEN ) + ( ( ( seek_byte + byte_size ) % DVD_VIDEO_LB_LEN ) ? 1 : 0 ); - secbuf = (unsigned char *) malloc( numsec * DVD_VIDEO_LB_LEN ); - if( !secbuf ) { - fprintf( stderr, "libdvdread: Can't allocate memory " - "for file read!\n" ); - return 0; + /* must align to 2048 bytes if we are reading from raw/O_DIRECT */ + secbuf_start = (unsigned char *) malloc( (numsec+1) * DVD_VIDEO_LB_LEN ); + if( !secbuf_start ) { + /* errno will be set to ENOMEM by malloc */ + return -1; } + secbuf = DVD_ALIGN(secbuf_start); + if( dvd_file->dvd->isImageFile ) { ret = DVDReadBlocksUDF( dvd_file, (uint32_t) seek_sector, (size_t) numsec, secbuf, DVDINPUT_NOFLAGS ); @@ -998,12 +1258,12 @@ ssize_t DVDReadBytes( dvd_file_t *dvd_file, void *data, size_t byte_size ) } if( ret != (int) numsec ) { - free( secbuf ); + free( secbuf_start ); return ret < 0 ? ret : 0; } memcpy( data, &(secbuf[ seek_byte ]), byte_size ); - free( secbuf ); + free( secbuf_start ); dvd_file->seek_pos += byte_size; return byte_size; @@ -1022,11 +1282,14 @@ int DVDDiscID( dvd_reader_t *dvd, unsigned char *discid ) { struct md5_ctx ctx; int title; - + int nr_of_files = 0; + int tmp_errno; + int nofiles_errno = ENOENT; /* Check arguments. */ - if( dvd == NULL || discid == NULL ) - return 0; - + if( dvd == NULL || discid == NULL ) { + errno = EINVAL; + return -1; + } /* Go through the first 10 IFO:s, in order, * and md5sum them, i.e VIDEO_TS.IFO and VTS_0?_0.IFO */ md5_init_ctx( &ctx ); @@ -1037,16 +1300,23 @@ int DVDDiscID( dvd_reader_t *dvd, unsigned char *discid ) size_t file_size = dvd_file->filesize * DVD_VIDEO_LB_LEN; char *buffer = malloc( file_size ); + nr_of_files++; + if( buffer == NULL ) { - fprintf( stderr, "libdvdread: DVDDiscId, failed to " - "allocate memory for file read!\n" ); + /* errno will be set to ENOMEM by malloc */ return -1; } + bytes_read = DVDReadBytes( dvd_file, buffer, file_size ); if( bytes_read != file_size ) { + tmp_errno = errno; + if(dvd->verbose >= 1) { fprintf( stderr, "libdvdread: DVDDiscId read returned %d bytes" - ", wanted %d\n", bytes_read, file_size ); + ", wanted %d\n", (int)bytes_read, (int)file_size ); + } + free(buffer); DVDCloseFile( dvd_file ); + errno = tmp_errno; return -1; } @@ -1054,10 +1324,17 @@ int DVDDiscID( dvd_reader_t *dvd, unsigned char *discid ) DVDCloseFile( dvd_file ); free( buffer ); + } else { + if(errno != ENOENT) { + nofiles_errno = errno; + } } } md5_finish_ctx( &ctx, discid ); - + if(nr_of_files == 0) { + errno = nofiles_errno; + return -1; + } return 0; } @@ -1066,29 +1343,36 @@ int DVDISOVolumeInfo( dvd_reader_t *dvd, char *volid, unsigned int volid_size, unsigned char *volsetid, unsigned int volsetid_size ) { - unsigned char *buffer; + unsigned char *buffer; /* must be aligned to 2048 for raw/O_DIRECT */ + unsigned char *buffer_start; int ret; /* Check arguments. */ - if( dvd == NULL ) - return 0; + if( dvd == NULL ) { + errno = EINVAL; + return -1; + } if( dvd->dev == NULL ) { /* No block access, so no ISO... */ + errno = EINVAL; return -1; } - buffer = malloc( DVD_VIDEO_LB_LEN ); - if( buffer == NULL ) { - fprintf( stderr, "libdvdread: DVDISOVolumeInfo, failed to " - "allocate memory for file read!\n" ); + buffer_start = malloc( 2 * DVD_VIDEO_LB_LEN ); + if( buffer_start == NULL ) { return -1; } + buffer = DVD_ALIGN(buffer_start); + ret = UDFReadBlocksRaw( dvd, 16, 1, buffer, 0 ); if( ret != 1 ) { + if(dvd->verbose >= 1) { fprintf( stderr, "libdvdread: DVDISOVolumeInfo, failed to " "read ISO9660 Primary Volume Descriptor!\n" ); + } + free(buffer_start); return -1; } @@ -1114,6 +1398,8 @@ int DVDISOVolumeInfo( dvd_reader_t *dvd, } memcpy(volsetid, &buffer[190], volsetid_size); } + free(buffer_start); + return 0; } diff --git a/dvdread/dvd_reader.h b/dvdread/dvd_reader.h index cc4ba54895..25b0370279 100644 --- a/dvdread/dvd_reader.h +++ b/dvdread/dvd_reader.h @@ -31,9 +31,14 @@ */ /** - * The current version. + * The current version. (0.9.4 => 904, 1.2.3 => 10203) */ -#define DVDREAD_VERSION 904 +#define DVDREAD_VERSION 905 + +/** + * Returns the compiled version. (DVDREAD_VERSION as an int) + */ +int DVDVersion(void); /** * The length of one Logical Block of a DVD. @@ -80,6 +85,10 @@ typedef struct dvd_file_s dvd_file_t; * @return If successful a a read handle is returned. Otherwise 0 is returned. * * dvd = DVDOpen(path); + * + * Threads: this function uses chdir() and getcwd(). + * The current working directory is global to all threads, + * so using chdir/getcwd in another thread could give unexpected results. */ dvd_reader_t *DVDOpen( const char * ); @@ -94,6 +103,35 @@ dvd_reader_t *DVDOpen( const char * ); */ void DVDClose( dvd_reader_t * ); +/** + * Initializes libdvdread to be used with multithreading apps. + * + * You must call this function before using any other functions of libdvdread + * if you are going to use libdvdread in multiple threads in your program. + * If you are not using threads, or using libdvdread from just one thread, + * you do not need to call this, but you are allowed to do so anyway. + * + * There are several restrictions on how you can use libdvdread in + * multithreading apps, see further documentation. + * + * If you have called DVDFinish() you need to call DVDInit again to use + * libdvdread in multiple threads. + * + * DVDInit(void); + */ +void DVDInit(void); + +/** + * frees any dlopened objects. + * + * You must DVDClose all handles opened with DVDOpen before calling this. + * Use this function if you need to close the dlopened libs and any other + * objects that have been dynamically allocated by libdvdread. + * + * DVDFinish(void); + */ +void DVDFinish(void); + /** * */ @@ -141,6 +179,8 @@ void DVDCloseFile( dvd_file_t * ); * @param offset Block offset from the start of the file to start reading at. * @param block_count Number of block to read. * @param data Pointer to a buffer to write the data into. + * It must be aligned to the logical block size of the device when + * reading from a raw/O_DIRECT device (2048 bytes for DVD) * @return Returns number of blocks read on success, -1 on error. * * blocks_read = DVDReadBlocks(dvd_file, offset, block_count, data); diff --git a/dvdread/dvd_udf.c b/dvdread/dvd_udf.c index 56682e7405..19b69560cf 100644 --- a/dvdread/dvd_udf.c +++ b/dvdread/dvd_udf.c @@ -37,23 +37,173 @@ #include #include #include -#ifndef __MINGW32__ -#include -#endif + #include #include #include +#include + +#if defined(HAVE_INTTYPES_H) #include +#elif defined(HAVE_STDINT_H) +#include +#endif #include "dvd_reader.h" #include "dvd_udf.h" +#include "dvdread_internal.h" + +#ifndef EMEDIUMTYPE +#define EMEDIUMTYPE ENOENT +#endif + +#ifndef HAVE_UINTPTR_T +#warning "Assuming that (unsigned long) can hold (void *)" +typedef unsigned long uintptr_t; +#endif + +#define DVD_ALIGN(ptr) (void *)((((uintptr_t)(ptr)) + (DVD_VIDEO_LB_LEN-1)) \ + / DVD_VIDEO_LB_LEN * DVD_VIDEO_LB_LEN) + +typedef struct { + void *start; + void *aligned; +} dvdalign_ptrs_t; + +typedef struct { + dvdalign_ptrs_t *ptrs; + uint32_t ptrs_in_use; + uint32_t ptrs_max; +} dvdalign_t; + +extern void *GetAlignHandle(dvd_reader_t *device); +extern void SetAlignHandle(dvd_reader_t *device, void *align); + +/** + * Allocates aligned memory (for use with reads from raw/O_DIRECT devices). + * This memory must be freed with dvdalign_free() + * The size of the memory that is allocate is num_lbs*2048 bytes. + * The memory will be suitably aligned for use with + * block reads from raw/O_DIRECT device. + * @param num_lbs Number of logical blocks (2048 bytes) to allocate. + * @return Returns pointer to allocated memory, or NULL on failure + * This isn't supposed to be fast/efficient, if that is needed + * this function should be rewritten to use posix_memalign or similar. + * It's just needed for aligning memory for small block reads from + * raw/O_DIRECT devices. + * We assume that 2048 is enough alignment for all systems at the moment. + * Not thread safe. Only use this from one thread. + * Depends on sizeof(unsigned long) being at least as large as sizeof(void *) + */ +static void *dvdalign_lbmalloc(dvd_reader_t *device, uint32_t num_lbs) +{ + void *m; + int n; + dvdalign_t *a; + + m = malloc((num_lbs+1)*DVD_VIDEO_LB_LEN); + if(m == NULL) { + return m; + } + a = (dvdalign_t *)GetAlignHandle(device); + if(a == NULL) { + a = malloc(sizeof(dvdalign_t)); + if(a == NULL) { + return a; + } + a->ptrs = NULL; + a->ptrs_in_use = 0; + a->ptrs_max = 0; + SetAlignHandle(device, (void *)a); + } + + if(a->ptrs_in_use >= a->ptrs_max) { + a->ptrs = realloc(a->ptrs, (a->ptrs_max+10)*sizeof(dvdalign_ptrs_t)); + if(a->ptrs == NULL) { + free(m); + return NULL; + } + a->ptrs_max+=10; + for(n = a->ptrs_in_use; n < a->ptrs_max; n++) { + a->ptrs[n].start = NULL; + a->ptrs[n].aligned = NULL; + } + n = a->ptrs_in_use; + } else { + for(n = 0; n < a->ptrs_max; n++) { + if(a->ptrs[n].start == NULL) { + break; + } + } + } + + a->ptrs[n].start = m; + a->ptrs[n].aligned = DVD_ALIGN(m); + + a->ptrs_in_use++; + + /* If this function starts to be used too much print a warning. + Either there is a memory leak somewhere or we need to rewrite this to + a more efficient version. + */ + if(a->ptrs_in_use > 50) { + if(dvdread_verbose(device) >= 0) { + fprintf(stderr, "libdvdread: dvdalign_lbmalloc(), more allocs than supposed: %u\n", a->ptrs_in_use); + } + } + + return a->ptrs[n].aligned; +} + +/** + * Frees memory allocated with dvdalign_lbmemory() + * @param ptr Pointer to memory space to free + * Not thread safe. + */ +static void dvdalign_lbfree(dvd_reader_t *device, void *ptr) +{ + int n; + dvdalign_t *a; + + a = (dvdalign_t *)GetAlignHandle(device); + if(a && a->ptrs) { + for(n = 0; n < a->ptrs_max; n++) { + if(a->ptrs[n].aligned == ptr) { + free(a->ptrs[n].start); + a->ptrs[n].start = NULL; + a->ptrs[n].aligned = NULL; + a->ptrs_in_use--; + if(a->ptrs_in_use == 0) { + free(a->ptrs); + a->ptrs = NULL; + a->ptrs_max = 0; + free(a); + a = NULL; + SetAlignHandle(device, (void *)a); + } + return; + } + } + } + if(dvdread_verbose(device) >= 0) { + fprintf(stderr, "libdvdread: dvdalign_lbfree(), error trying to free mem: %08lx (%u)\n", (unsigned long)ptr, a ? a->ptrs_in_use : 0); + } +} + /* Private but located in/shared with dvd_reader.c */ extern int UDFReadBlocksRaw( dvd_reader_t *device, uint32_t lb_number, size_t block_count, unsigned char *data, int encrypted ); -/* It's required to either fail or deliver all the blocks asked for. */ +/** @internal + * Its required to either fail or deliver all the blocks asked for. + * + * @param data Pointer to a buffer where data is returned. This must be large + * enough to hold lb_number*2048 bytes. + * It must be aligned to system specific (2048) logical blocks size when + * reading from raw/O_DIRECT device. + */ static int DVDReadLBUDF( dvd_reader_t *device, uint32_t lb_number, size_t block_count, unsigned char *data, int encrypted ) @@ -149,12 +299,24 @@ typedef enum { extern void *GetUDFCacheHandle(dvd_reader_t *device); extern void SetUDFCacheHandle(dvd_reader_t *device, void *cache); -void FreeUDFCache(void *cache) + +void FreeUDFCache(dvd_reader_t *device, void *cache) { + int n; + struct udf_cache *c = (struct udf_cache *)cache; if(c == NULL) { return; } + + for(n = 0; n < c->lb_num; n++) { + if(c->lbs[n].data) { + /* free data */ + dvdalign_lbfree(device, c->lbs[n].data); + } + } + c->lb_num = 0; + if(c->lbs) { free(c->lbs); } @@ -493,7 +655,7 @@ static int UDFFileIdentifier( uint8_t *data, uint8_t *FileCharacteristics, static int UDFMapICB( dvd_reader_t *device, struct AD ICB, uint8_t *FileType, struct Partition *partition, struct AD *File ) { - uint8_t LogBlock[DVD_VIDEO_LB_LEN]; + uint8_t *LogBlock; uint32_t lbnum; uint16_t TagID; struct icbmap tmpmap; @@ -506,6 +668,11 @@ static int UDFMapICB( dvd_reader_t *device, struct AD ICB, uint8_t *FileType, return 1; } + LogBlock = dvdalign_lbmalloc(device, 1); + if(!LogBlock) { + return 0; + } + do { if( DVDReadLBUDF( device, lbnum++, 1, LogBlock, 0 ) <= 0 ) { TagID = 0; @@ -518,11 +685,13 @@ static int UDFMapICB( dvd_reader_t *device, struct AD ICB, uint8_t *FileType, tmpmap.file = *File; tmpmap.filetype = *FileType; SetUDFCache(device, MapCache, tmpmap.lbn, &tmpmap); + dvdalign_lbfree(device, LogBlock); return 1; }; } while( ( lbnum <= partition->Start + ICB.Location + ( ICB.Length - 1 ) / DVD_VIDEO_LB_LEN ) && ( TagID != 261 ) ); + dvdalign_lbfree(device, LogBlock); return 0; } @@ -537,7 +706,7 @@ static int UDFScanDir( dvd_reader_t *device, struct AD Dir, char *FileName, int cache_file_info) { char filename[ MAX_UDF_FILE_NAME_LEN ]; - uint8_t directory[ 2 * DVD_VIDEO_LB_LEN ]; + uint8_t *directory; uint32_t lbnum; uint16_t TagID; uint8_t filechar; @@ -556,19 +725,13 @@ static int UDFScanDir( dvd_reader_t *device, struct AD Dir, char *FileName, if(!GetUDFCache(device, LBUDFCache, lbnum, &cached_dir)) { dir_lba = (Dir.Length + DVD_VIDEO_LB_LEN) / DVD_VIDEO_LB_LEN; - if((cached_dir = malloc(dir_lba * DVD_VIDEO_LB_LEN)) == NULL) { + if((cached_dir = dvdalign_lbmalloc(device, dir_lba)) == NULL) { return 0; } if( DVDReadLBUDF( device, lbnum, dir_lba, cached_dir, 0) <= 0 ) { - free(cached_dir); + dvdalign_lbfree(device, cached_dir); cached_dir = NULL; } - /* - if(cached_dir) { - fprintf(stderr, "malloc dir: %d\n", - dir_lba * DVD_VIDEO_LB_LEN); - } - */ SetUDFCache(device, LBUDFCache, lbnum, &cached_dir); } else { in_cache = 1; @@ -615,7 +778,12 @@ static int UDFScanDir( dvd_reader_t *device, struct AD Dir, char *FileName, return 0; } + directory = dvdalign_lbmalloc(device, 2); + if(!directory) { + return 0; + } if( DVDReadLBUDF( device, lbnum, 2, directory, 0 ) <= 0 ) { + dvdalign_lbfree(device, directory); return 0; } @@ -626,6 +794,7 @@ static int UDFScanDir( dvd_reader_t *device, struct AD Dir, char *FileName, p -= DVD_VIDEO_LB_LEN; Dir.Length -= DVD_VIDEO_LB_LEN; if( DVDReadLBUDF( device, lbnum, 2, directory, 0 ) <= 0 ) { + dvdalign_lbfree(device, directory); return 0; } } @@ -634,13 +803,16 @@ static int UDFScanDir( dvd_reader_t *device, struct AD Dir, char *FileName, p += UDFFileIdentifier( &directory[ p ], &filechar, filename, FileICB ); if( !strcasecmp( FileName, filename ) ) { + dvdalign_lbfree(device, directory); return 1; } } else { + dvdalign_lbfree(device, directory); return 0; } } + dvdalign_lbfree(device, directory); return 0; } @@ -648,7 +820,7 @@ static int UDFScanDir( dvd_reader_t *device, struct AD Dir, char *FileName, static int UDFGetAVDP( dvd_reader_t *device, struct avdp_t *avdp) { - uint8_t Anchor[ DVD_VIDEO_LB_LEN ]; + uint8_t *Anchor; uint32_t lbnum, MVDS_location, MVDS_length; uint16_t TagID; uint32_t lastsector; @@ -664,6 +836,10 @@ static int UDFGetAVDP( dvd_reader_t *device, lbnum = 256; /* Try #1, prime anchor */ terminate = 0; + Anchor = dvdalign_lbmalloc(device, 1); + if(!Anchor) { + return 0; + } for(;;) { if( DVDReadLBUDF( device, lbnum, 1, Anchor, 0 ) > 0 ) { UDFDescriptor( Anchor, &TagID ); @@ -672,10 +848,13 @@ static int UDFGetAVDP( dvd_reader_t *device, } if (TagID != 2) { /* Not an anchor */ - if( terminate ) return 0; /* Final try failed */ + if( terminate ) { + dvdalign_lbfree(device, Anchor); + errno = EMEDIUMTYPE; + return 0; /* Final try failed */ + } if( lastsector ) { - /* We already found the last sector. Try #3, alternative * backup anchor. If that fails, don't try again. */ @@ -688,6 +867,8 @@ static int UDFGetAVDP( dvd_reader_t *device, lbnum = lastsector - 256; } else { /* Unable to find last sector */ + dvdalign_lbfree(device, Anchor); + errno = EMEDIUMTYPE; return 0; } } @@ -708,6 +889,7 @@ static int UDFGetAVDP( dvd_reader_t *device, SetUDFCache(device, AVDPCache, 0, avdp); + dvdalign_lbfree(device, Anchor); return 1; } @@ -719,7 +901,7 @@ static int UDFGetAVDP( dvd_reader_t *device, static int UDFFindPartition( dvd_reader_t *device, int partnum, struct Partition *part ) { - uint8_t LogBlock[ DVD_VIDEO_LB_LEN ]; + uint8_t *LogBlock; uint32_t lbnum, MVDS_location, MVDS_length; uint16_t TagID; int i, volvalid; @@ -730,6 +912,10 @@ static int UDFFindPartition( dvd_reader_t *device, int partnum, return 0; } + LogBlock = dvdalign_lbmalloc(device, 1); + if(!LogBlock) { + return 0; + } /* Main volume descriptor */ MVDS_location = avdp.mvds.location; MVDS_length = avdp.mvds.length; @@ -774,6 +960,7 @@ static int UDFFindPartition( dvd_reader_t *device, int partnum, } } while( i-- && ( ( !part->valid ) || ( !volvalid ) ) ); + dvdalign_lbfree(device, LogBlock); /* We only care for the partition, not the volume */ return part->valid; } @@ -781,7 +968,7 @@ static int UDFFindPartition( dvd_reader_t *device, int partnum, uint32_t UDFFindFile( dvd_reader_t *device, char *filename, uint32_t *filesize ) { - uint8_t LogBlock[ DVD_VIDEO_LB_LEN ]; + uint8_t *LogBlock; uint32_t lbnum; uint16_t TagID; struct Partition partition; @@ -790,7 +977,9 @@ uint32_t UDFFindFile( dvd_reader_t *device, char *filename, char *token; uint8_t filetype; + if(filesize) { *filesize = 0; + } tokenline[0] = '\0'; strcat( tokenline, filename ); @@ -798,9 +987,15 @@ uint32_t UDFFindFile( dvd_reader_t *device, char *filename, if(!(GetUDFCache(device, PartitionCache, 0, &partition) && GetUDFCache(device, RootICBCache, 0, &RootICB))) { /* Find partition, 0 is the standard location for DVD Video.*/ - if( !UDFFindPartition( device, 0, &partition ) ) return 0; + if( !UDFFindPartition( device, 0, &partition ) ) { + return 0; + } SetUDFCache(device, PartitionCache, 0, &partition); + LogBlock = dvdalign_lbmalloc(device, 1); + if(!LogBlock) { + return 0; + } /* Find root dir ICB */ lbnum = partition.Start; do { @@ -817,16 +1012,25 @@ uint32_t UDFFindFile( dvd_reader_t *device, char *filename, } while( ( lbnum < partition.Start + partition.Length ) && ( TagID != 8 ) && ( TagID != 256 ) ); + dvdalign_lbfree(device, LogBlock); + /* Sanity checks. */ - if( TagID != 256 ) return 0; - if( RootICB.Partition != 0 ) return 0; + if( TagID != 256 ) { + return 0; + } + if( RootICB.Partition != 0 ) { + return 0; + } SetUDFCache(device, RootICBCache, 0, &RootICB); } /* Find root dir */ - if( !UDFMapICB( device, RootICB, &filetype, &partition, &File ) ) return 0; - if( filetype != 4 ) return 0; /* Root dir should be dir */ - + if( !UDFMapICB( device, RootICB, &filetype, &partition, &File ) ) { + return 0; + } + if( filetype != 4 ) { + return 0; /* Root dir should be dir */ + } { int cache_file_info = 0; /* Tokenize filepath */ @@ -849,15 +1053,20 @@ uint32_t UDFFindFile( dvd_reader_t *device, char *filename, } /* Sanity check. */ - if( File.Partition != 0 ) return 0; + if( File.Partition != 0 ) { + return 0; + } + if(filesize) { *filesize = File.Length; + } /* Hack to not return partition.Start for empty files. */ - if( !File.Location ) + if( !File.Location ) { return 0; - else + } else { return partition.Start + File.Location; } +} @@ -865,7 +1074,8 @@ uint32_t UDFFindFile( dvd_reader_t *device, char *filename, * Gets a Descriptor . * Returns 1 if descriptor found, 0 on error. * id, tagid of descriptor - * bufsize, size of BlockBuf (must be >= DVD_VIDEO_LB_LEN). + * bufsize, size of BlockBuf (must be >= DVD_VIDEO_LB_LEN) + * and aligned for raw/O_DIRECT read. */ static int UDFGetDescriptor( dvd_reader_t *device, int id, uint8_t *descriptor, int bufsize) @@ -919,19 +1129,25 @@ static int UDFGetDescriptor( dvd_reader_t *device, int id, } } while( i-- && ( !desc_found ) ); + return desc_found; } static int UDFGetPVD(dvd_reader_t *device, struct pvd_t *pvd) { - uint8_t pvd_buf[DVD_VIDEO_LB_LEN]; + uint8_t *pvd_buf; if(GetUDFCache(device, PVDCache, 0, pvd)) { return 1; } - if(!UDFGetDescriptor( device, 1, pvd_buf, sizeof(pvd_buf))) { + pvd_buf = dvdalign_lbmalloc(device, 1); + if(!pvd_buf) { + return 0; + } + if(!UDFGetDescriptor( device, 1, pvd_buf, 1*DVD_VIDEO_LB_LEN)) { + dvdalign_lbfree(device, pvd_buf); return 0; } @@ -939,6 +1155,8 @@ static int UDFGetPVD(dvd_reader_t *device, struct pvd_t *pvd) memcpy(pvd->VolumeSetIdentifier, &pvd_buf[72], 128); SetUDFCache(device, PVDCache, 0, pvd); + dvdalign_lbfree(device, pvd_buf); + return 1; } diff --git a/dvdread/dvd_udf.h b/dvdread/dvd_udf.h index b600983d9a..0e2e8b0df4 100644 --- a/dvdread/dvd_udf.h +++ b/dvdread/dvd_udf.h @@ -31,7 +31,11 @@ * http://www.gnu.org/copyleft/gpl.html */ +#if defined(HAVE_INTTYPES_H) #include +#elif defined(HAVE_STDINT_H) +#include +#endif #include "dvd_reader.h" @@ -48,7 +52,7 @@ extern "C" { */ uint32_t UDFFindFile( dvd_reader_t *device, char *filename, uint32_t *size ); -void FreeUDFCache(void *cache); +void FreeUDFCache(dvd_reader_t *device, void *cache); int UDFGetVolumeIdentifier(dvd_reader_t *device, char *volid, unsigned int volid_size); int UDFGetVolumeSetIdentifier(dvd_reader_t *device, diff --git a/dvdread/dvdread_internal.h b/dvdread/dvdread_internal.h index 5c8a535cc0..fbd87b48ce 100644 --- a/dvdread/dvdread_internal.h +++ b/dvdread/dvdread_internal.h @@ -5,4 +5,8 @@ #define CHECK_VALUE(arg) +int get_verbose(void); +int dvdread_verbose(dvd_reader_t *dvd); +dvd_reader_t *device_of_file(dvd_file_t *file); + #endif /* DVDREAD_INTERNAL_H */ diff --git a/dvdread/ifo_print.c b/dvdread/ifo_print.c index 17820c77a4..47938f6aba 100644 --- a/dvdread/ifo_print.c +++ b/dvdread/ifo_print.c @@ -27,13 +27,19 @@ #include #include #include -#include #include #include +#if defined(HAVE_INTTYPES_H) +#include +#elif defined(HAVE_STDINT_H) +#include +#endif + #include "ifo_types.h" #include "ifo_read.h" #include "ifo_print.h" +#include "cmd_print.h" #include "dvdread_internal.h" /* Put this in some other file / package? It's used in nav_print too. */ @@ -67,20 +73,6 @@ static void ifoPrint_time(dvd_time_t *dtime) { printf(" @ %s fps", rate); } -/* Put this in some other file / package? It's used in nav_print too. - Possibly also by the vm / navigator. */ -static void ifoPrint_CMD(int row, vm_cmd_t *command) { - int i; - - printf("(%03d) ", row + 1); - for(i=0;i<8;i++) - printf("%02x ", command->bytes[i]); - printf("| "); - - //vmcmd(command); - printf("\n"); -} - static void ifoPrint_video_attributes(video_attr_t *attr) { /* The following test is shorter but not correct ISO C, @@ -261,6 +253,9 @@ static void ifoPrint_audio_attributes(audio_attr_t *attr) { case 1: printf("%c%c (%c) ", attr->lang_code>>8, attr->lang_code & 0xff, attr->lang_extension ? attr->lang_extension : ' '); + if(attr->lang_extension) { + printf("(please send a bug report) lang_extension != 0"); + } break; default: printf("(please send a bug report) "); @@ -280,6 +275,29 @@ static void ifoPrint_audio_attributes(audio_attr_t *attr) { printf("(please send a bug report) "); } + switch(attr->audio_format) { + case 0: //ac3 + if(attr->quantization != 3) { + printf("(please send a bug report) ac3 quant/drc not 3 (%d)", + attr->quantization); + } + break; + case 2: //mpeg 1 or mpeg 2 without extension stream + case 3: //mpeg 2 with extension stream + switch(attr->quantization) { + case 0: //no drc + printf("no drc "); + break; + case 1: + printf("drc "); + break; + default: + printf("(please send a bug report) mpeg reserved quant/drc (%d)", + attr->quantization); + break; + } + break; + case 4: switch(attr->quantization) { case 0: printf("16bit "); @@ -291,10 +309,19 @@ static void ifoPrint_audio_attributes(audio_attr_t *attr) { printf("24bit "); break; case 3: - printf("drc "); + printf("(please send a bug report) lpcm reserved quant/drc (%d)", + attr->quantization); + break; + } + break; + case 6: //dts + if(attr->quantization != 3) { + printf("(please send a bug report) dts quant/drc not 3 (%d)", + attr->quantization); + } break; default: - printf("(please send a bug report) "); + break; } switch(attr->sample_frequency) { @@ -302,7 +329,7 @@ static void ifoPrint_audio_attributes(audio_attr_t *attr) { printf("48kHz "); break; case 1: - printf("??kHz "); + printf("96kHz "); break; default: printf("sample_frequency %i (please send a bug report) ", @@ -387,10 +414,9 @@ static void ifoPrint_subp_attributes(subp_attr_t *attr) { printf("%d ", attr->zero1); printf("%d ", attr->zero2); - printf("%d ", attr->code_extension); + printf("%d ", attr->lang_extension); - /* Is this correct? should it not be subp_code_ext here instead? */ - switch(attr->lang_extension) { + switch(attr->code_extension) { case 0: printf("Not specified "); break; @@ -640,17 +666,17 @@ static void ifoPrint_PGC_COMMAND_TBL(pgc_command_tbl_t *cmd_tbl) { printf("Number of Pre commands: %i\n", cmd_tbl->nr_of_pre); for(i = 0; i < cmd_tbl->nr_of_pre; i++) { - ifoPrint_CMD(i, &cmd_tbl->pre_cmds[i]); + cmdPrint_CMD(i, &cmd_tbl->pre_cmds[i]); } printf("Number of Post commands: %i\n", cmd_tbl->nr_of_post); for(i = 0; i < cmd_tbl->nr_of_post; i++) { - ifoPrint_CMD(i, &cmd_tbl->post_cmds[i]); + cmdPrint_CMD(i, &cmd_tbl->post_cmds[i]); } printf("Number of Cell commands: %i\n", cmd_tbl->nr_of_cell); for(i = 0; i < cmd_tbl->nr_of_cell; i++) { - ifoPrint_CMD(i, &cmd_tbl->cell_cmds[i]); + cmdPrint_CMD(i, &cmd_tbl->cell_cmds[i]); } } @@ -754,6 +780,11 @@ static void ifoPrint_CELL_POSITION(cell_position_t *cell_position, int nr) { void ifoPrint_PGC(pgc_t *pgc) { int i; + if(pgc == NULL) { + printf("Error: No PGC present\n"); + return; + } + printf("Number of Programs: %i\n", pgc->nr_of_programs); printf("Number of Cells: %i\n", pgc->nr_of_cells); /* Check that time is 0:0:0:0 also if nr_of_programs==0 */ @@ -765,14 +796,14 @@ void ifoPrint_PGC(pgc_t *pgc) { ifoPrint_USER_OPS(&pgc->prohibited_ops); for(i = 0; i < 8; i++) { - if(pgc->audio_control[i].present) { + if(pgc->audio_control[i].present) { /* The 'is present' bit */ printf("Audio stream %i control: %04x\n", i, pgc->audio_control[i]); } } for(i = 0; i < 32; i++) { - if(pgc->subp_control[i].present) { + if(pgc->subp_control[i].present) { /* The 'is present' bit */ printf("Subpicture stream %2i control: %08x\n", i, pgc->subp_control[i]); } @@ -918,7 +949,7 @@ void ifoPrint_C_ADT(c_adt_t *c_adt) { printf("Number of VOBs in this VOBS: %i\n", c_adt->nr_of_vobs); //entries = c_adt->nr_of_vobs; - entries = (c_adt->last_byte + 1 - C_ADT_SIZE)/sizeof(c_adt_t); + entries = (c_adt->last_byte + 1 - C_ADT_SIZE)/sizeof(cell_adr_t); for(i = 0; i < entries; i++) { printf("VOB ID: %3i, Cell ID: %3i ", @@ -1030,7 +1061,9 @@ void ifoPrint(dvd_reader_t *dvd, int title) { ifohandle = ifoOpen(dvd, title); if(!ifohandle) { + if(dvdread_verbose(dvd) >= 0) { fprintf(stderr, "Can't open info file for title %d\n", title); + } return; } @@ -1041,7 +1074,11 @@ void ifoPrint(dvd_reader_t *dvd, int title) { ifoPrint_VMGI_MAT(ifohandle->vmgi_mat); printf("\nFirst Play PGC\n--------------\n"); + if(ifohandle->first_play_pgc) { ifoPrint_PGC(ifohandle->first_play_pgc); + } else { + printf("No First Play PGC present\n"); + } printf("\nTitle Track search pointer table\n"); printf( "------------------------------------------------\n"); diff --git a/dvdread/ifo_read.c b/dvdread/ifo_read.c index 8ad7baeea1..34ce32f41e 100644 --- a/dvdread/ifo_read.c +++ b/dvdread/ifo_read.c @@ -26,8 +26,15 @@ #include #include + +#if defined(HAVE_INTTYPES_H) #include +#elif defined(HAVE_STDINT_H) +#include +#endif + #include +#include #include "bswap.h" #include "ifo_types.h" @@ -92,6 +99,11 @@ static void ifoFree_PGC(pgc_t *pgc); static void ifoFree_PGC_COMMAND_TBL(pgc_command_tbl_t *cmd_tbl); static void ifoFree_PGCIT_internal(pgcit_t *pgcit); +static ifo_handle_t *ifoOpen_File(ifo_handle_t *ifofile, int title, + char *suffix); +static ifo_handle_t *ifoOpenVMGI_File(ifo_handle_t *ifofile, char *suffix); +static ifo_handle_t *ifoOpenVTSI_File(ifo_handle_t *ifofile, int title, + char *suffix); static inline int DVDFileSeek_( dvd_file_t *dvd_file, uint32_t offset ) { return (DVDFileSeek(dvd_file, (int)offset) == (int)offset); @@ -103,21 +115,52 @@ ifo_handle_t *ifoOpen(dvd_reader_t *dvd, int title) { ifofile = malloc(sizeof(ifo_handle_t)); if(!ifofile) - return 0; + return NULL; memset(ifofile, 0, sizeof(ifo_handle_t)); ifofile->file = DVDOpenFile(dvd, title, DVD_READ_INFO_FILE); - if(!ifofile->file) /* Should really catch any error and try to fallback */ + if(!ifoOpen_File(ifofile, title, "IFO")) { + if(title) { + if(dvdread_verbose(dvd) >= 1) { + fprintf(stderr, "libdvdread: