diff -ruib ../../versions/libdvdread_patch3/libdvdread/src/dvd_reader.c ./dvd_reader.c --- ../../versions/libdvdread_patch3/libdvdread/src/dvd_reader.c 2008-10-10 17:20:20.000000000 +0900 +++ ./dvd_reader.c 2008-10-10 17:32:13.000000000 +0900 @@ -592,6 +592,7 @@ dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) ); if( !dvd_file ) { fprintf( stderr, "libdvdnav:DVDOpenFileUDF:malloc failed\n" ); + UDFFreeFile(dvd, udf_file); return NULL; } dvd_file->dvd = dvd; @@ -1356,6 +1357,8 @@ char *buffer_base = malloc( file_size + 2048 ); char *buffer = (char *)(((uintptr_t)buffer_base & ~((uintptr_t)2047)) + 2048); + dvd_file->udf_file = NULL; + if( buffer_base == NULL ) { DVDCloseFile( dvd_file ); fprintf( stderr, "libdvdread: DVDDiscId, failed to " @@ -1476,3 +1479,102 @@ return 0; } + +/** + * opendir(3)-like function for traversing a UDF image. + * + * dvd_dir_t *DVDOpenDir( dvd_reader_t *dvd, char *subdir ) + * + * Opens "subdir" directory for traversal. Returns NULL for failure + * or a valid dvd_dir_t * otherwise. + * + * This function differs from POSIX in that it must also be passed + * the dvd_reader_t *. + * + */ +dvd_dir_t *DVDOpenDir( dvd_reader_t *dvd, char *subdir ) +{ + UDF_FILE udf_file; + uint64_t filesize; + dvd_dir_t *result; + + udf_file = UDFFindFile( dvd, subdir, &filesize ); + + if (!udf_file) return NULL; + +#ifdef DEBUG + fprintf(stdout, "Found '%s' at %d (size %"PRIu64")\n", subdir, + UDFFileBlockPos(udf_file, 0), filesize); +#endif + + result = (dvd_dir_t *)malloc(sizeof(*result)); + if (!result) { + UDFFreeFile(dvd, udf_file); + return NULL; + } + + memset(result, 0, sizeof(*result)); + + result->dir_location = UDFFileBlockPos(udf_file, 0); + result->dir_current = UDFFileBlockPos(udf_file, 0); + result->dir_length = filesize; + UDFFreeFile(dvd, udf_file); + + return result; +} + + +/** + * readdir(3)-like function for traversing a UDF image. + * + * This function differs from POSIX in that it must also be passed + * the dvd_reader_t *. + * + */ +dvd_dirent_t *DVDReadDir( dvd_reader_t *dvd, dvd_dir_t *dirp ) +{ + + if (!UDFScanDirX(dvd, dirp)) { + dirp->current_p = 0; + dirp->dir_current = dirp->dir_location; // this is a rewind, wanted? + return NULL; + } + +#ifdef DEBUG + fprintf(stderr, "DVDReadDir(%s)\r\n", dirp->entry.d_name); +#endif + + return &dirp->entry; + +} + +/** + * closedir(3)-like function for traversing a UDF image. + * + * This function differs from POSIX in that it must also be passed + * the dvd_reader_t *. + * + */ + +int DVDCloseDir( dvd_reader_t *dvd, dvd_dir_t *dirp ) +{ + if (!dirp) return 0; + + free(dirp); + + return 0; + +} + +/** + * Nearly identical function to DVDOpenFile, but instead of mapping + * DVD domain and title, this takes an actual filename to open. + */ +dvd_file_t *DVDOpenFilename( dvd_reader_t *dvd, char *filename) +{ + if( dvd->isImageFile ) { + return DVDOpenFileUDF( dvd, filename ); + } else { + return DVDOpenFilePath( dvd, filename ); + } +} diff -ruib ../../versions/libdvdread_patch3/libdvdread/src/dvd_reader.h ./dvd_reader.h --- ../../versions/libdvdread_patch3/libdvdread/src/dvd_reader.h 2008-10-10 17:19:36.000000000 +0900 +++ ./dvd_reader.h 2008-10-10 17:23:46.000000000 +0900 @@ -125,6 +125,47 @@ off_t parts_size[9]; /**< Size of each part in bytes */ } dvd_stat_t; +/* + * DVDReaddir entry types. + */ +typedef enum { + DVD_DT_UNKNOWN = 0, + DVD_DT_FIFO, + DVD_DT_CHR, + DVD_DT_DIR, + DVD_DT_BLK, + DVD_DT_REG, + DVD_DT_LNK, + DVD_DT_SOCK, + DVD_DT_WHT +} dvd_dir_type_t; + +/* + * DVDReaddir structure. + * Extended a little from POSIX to also return filesize. + */ +typedef struct { + unsigned char d_name[MAX_UDF_FILE_NAME_LEN]; + // "Shall not exceed 1023; Ecma-167 page 123" + dvd_dir_type_t d_type; // DT_REG, DT_DIR + unsigned int d_namlen; + uint64_t d_filesize; +} dvd_dirent_t; + + +/* + * DVDOpendir DIR* structure + */ +typedef struct { + uint32_t dir_location; + uint32_t dir_length; + uint32_t dir_current; // Separate to _location should we one day want to + // implement dir_rewind() + unsigned int current_p; // Internal implementation specific. UDFScanDirX + dvd_dirent_t entry; +} dvd_dir_t; + + /** * Stats a file on the DVD given the title number and domain. * The information about the file is stored in a dvd_stat_t @@ -312,6 +353,24 @@ */ int DVDUDFCacheLevel( dvd_reader_t *, int ); + + +/* + * Directory iterator functions to mimick POSIX's opendir/readdir/closedir + */ +dvd_dir_t *DVDOpenDir ( dvd_reader_t *, char *); + +dvd_dirent_t *DVDReadDir ( dvd_reader_t *, dvd_dir_t *); + +int DVDCloseDir ( dvd_reader_t *, dvd_dir_t *); + +/* + * Open a file based on filename. Usually used after opendir()/readdir(). + */ +dvd_file_t *DVDOpenFilename( dvd_reader_t *, char * ); + + + #ifdef __cplusplus }; #endif diff -ruib ../../versions/libdvdread_patch3/libdvdread/src/dvd_udf.c ./dvd_udf.c --- ../../versions/libdvdread_patch3/libdvdread/src/dvd_udf.c 2008-10-10 17:16:50.000000000 +0900 +++ ./dvd_udf.c 2008-10-10 17:26:20.000000000 +0900 @@ -820,6 +820,103 @@ return 0; } +/** + * Low-level function used by DVDReadDir to simulate readdir(). + * Dir: Location of directory to scan + * FileName: Name of file to look for + * FileICB: Location of ICB of the found file + * return 1 on success, 0 on error; + * + * Perhaps a better name is more appropriate, it also does no longer use + * memory cache. FIXME. -Lund + */ +int UDFScanDirX( dvd_reader_t *device, + dvd_dir_t *dirp ) +{ + char filename[ MAX_UDF_FILE_NAME_LEN ]; + uint8_t directory_base[ 2 * DVD_VIDEO_LB_LEN + 2048]; + uint8_t *directory = (uint8_t *)(((uintptr_t)directory_base & ~((uintptr_t)2047)) + 2048); + uint32_t lbnum; + uint16_t TagID; + uint8_t filechar; + unsigned int p; + struct AD FileICB; + struct FileAD File; + struct Partition partition; + uint8_t filetype; + + if(!(GetUDFCache(device, PartitionCache, 0, &partition))) + return 0; + + /* Scan dir for ICB of file */ + lbnum = dirp->dir_current; + + // I have cut out the caching part of the original UDFScanDir() function + // one day we should probably bring it back. + memset(&File, 0, sizeof(File)); + + if( DVDReadLBUDF( device, lbnum, 2, directory, 0 ) <= 0 ) { + return 0; + } + + + p = dirp->current_p; + while( p < dirp->dir_length ) { + if( p > DVD_VIDEO_LB_LEN ) { + ++lbnum; + p -= DVD_VIDEO_LB_LEN; + + //Dir.Length -= DVD_VIDEO_LB_LEN; + if (dirp->dir_length >= DVD_VIDEO_LB_LEN) + dirp->dir_length -= DVD_VIDEO_LB_LEN; + else + dirp->dir_length = 0; + + if( DVDReadLBUDF( device, lbnum, 2, directory, 0 ) <= 0 ) { + return 0; + } + } + UDFDescriptor( &directory[ p ], &TagID ); + + if( TagID == 257 ) { + + p += UDFFileIdentifier( &directory[ p ], &filechar, + filename, &FileICB ); + + dirp->current_p = p; + dirp->dir_current = lbnum; + + if (!*filename) // No filename, simulate "." dirname + strcpy((char *)dirp->entry.d_name, "."); + else { + // Bah, MSVC don't have strlcpy() + strncpy((char *)dirp->entry.d_name, filename, + sizeof(dirp->entry.d_name)-1); + dirp->entry.d_name[ sizeof(dirp->entry.d_name) - 1 ] = 0; + } + + + // Look up the Filedata + if( !UDFMapICB( device, FileICB, &filetype, &partition, &File)) + return 0; + if (filetype == 4) + dirp->entry.d_type = DVD_DT_DIR; + else + dirp->entry.d_type = DVD_DT_REG; // Add more types? + + dirp->entry.d_filesize = File.Length; + + return 1; + + } else { + // Not TagID 257 + return 0; + } + } + // End of DIR + return 0; +} + static int UDFGetAVDP( dvd_reader_t *device, struct avdp_t *avdp) diff -ruib ../../versions/libdvdread_patch3/libdvdread/src/dvd_udf.h ./dvd_udf.h --- ../../versions/libdvdread_patch3/libdvdread/src/dvd_udf.h 2008-10-10 15:40:13.000000000 +0900 +++ ./dvd_udf.h 2008-10-10 17:25:20.000000000 +0900 @@ -51,6 +51,7 @@ UDF_FILE UDFFindFile( dvd_reader_t *device, char *filename, uint64_t *size ); void UDFFreeFile ( dvd_reader_t *device, UDF_FILE ); uint32_t UDFFileBlockPos( UDF_FILE, uint32_t file_block); +int UDFScanDirX ( dvd_reader_t *device, dvd_dir_t *dirp ); void FreeUDFCache(void *cache); int UDFGetVolumeIdentifier(dvd_reader_t *device,