This patch adds the ability to search any UDF filesystem by regular names and methods. It introduces POSIX style opendir()/readdir()/closedir() methods to iterate directory contents. This allows for complete navigation of UDF filesystem.

This is required to be able to read UDF2.50 file systems, to read files in say STREAM/00001.m2ts

Example output:

./disc_info example-bd5.iso
libdvdread: Encrypted DVD support unavailable.
/BDMV: . (type 3) size 152
/BDMV: AUXDATA (type 3) size 40
/BDMV: BACKUP (type 3) size 332
/BDMV: BDJO (type 3) size 40
/BDMV: CLIPINF (type 3) size 100
/BDMV: index.bdmv (type 5) size 526
/BDMV: JAR (type 3) size 40
/BDMV: META (type 3) size 40
/BDMV: MovieObject.bdmv (type 5) size 278
/BDMV: PLAYLIST (type 3) size 100
/BDMV: STREAM (type 3) size 100
/BDMV/STREAM: 00001.m2ts (type 4)
Openfile said 0x1004d0
Size 4691957760

Lund

--
Jorgen Lundman       | <[EMAIL PROTECTED]>
Unix Administrator   | +81 (0)3 -5456-2687 ext 1017 (work)
Shibuya-ku, Tokyo    | +81 (0)90-5578-8500          (cell)
Japan                | +81 (0)3 -3375-1767          (home)
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,
_______________________________________________
DVDnav-discuss mailing list
[email protected]
https://lists.mplayerhq.hu/mailman/listinfo/dvdnav-discuss

Reply via email to