Since we are re-considering patches, I can resend my first suggested patch for convenience.

Other patches are:

1: Proper AD chain functionality: this one.
   (improves UDF compliance, should be considered)

2: Add ExtFileInfo (262) support.
(Bring us to UDF2.50 compliance, not directly interesting to DVD reading, but assists with general UDF reading. /Should be considered).

3: Add FileType (250) re-direct support.
   (Used with UDF2.50, BD-ISO file types. /Should be considered)

4: DVDFileStat
   (Already accepted by other patchers)

5: 32bit to 64bit fixes.
(Current dvdread reads only last 4 bytes of UDF 8 byte file length, and truncate all sizes to 32bit. There is no reason for this hackery, and proper 64bit values should be maintained in API. /Should be considered)

6: Extend dvd_input's API
(dvd_input can handle 2 inputs, dvdcss or posix IO. Added API call to set own set of IO functions [open,seek,read,close) to allow API callers to define external IO. Good for Windows overlapping IO, streaming from containers like RAR, other transports etc. /API extension, possibly undesirable by general population.)

7: Extend dvdread with UDF2.50/POSIX IO functions.
(Add API calls to dvdread to be a generic UDF library as well. For UDF2.50 ISOs, add opendir/readdir/closedir and open() by filename. API extension, probably undesired if blurays are not considered.)



------------------------------------------------------------------------

The problem:

dvdread currently assumes that "file" in UDF have a starting block, and a length. The data is then contiguous from "start" until the final block.

In reality, UDF is split up into "AD chains" of contiguous segments, generally in increasing order. This is true from UDF 1.02 and up. However, it is unknown if there are DVDs that would have non-contiguous AD ordering, and only few have 'gap blocks' so far.


   (reality)        (dvdread's image)
UDF Spec File:      Current dvdread file:
 chain 0 start          file start
       |                    |
 chain 0 end                |
       |                    |
      gap                   |
       |                    |
 chain 1 start              |
       |                    |
 chain 1 end            file end
       |


This means that dvdread will incorrectly send the "gap blocks", as well as reach the "end" of the file sooner than it should. (Since gap blocks are counted).

This patch removes the view that a UDF file is start "starting block, and length" (known in the sources as 'lbnum'), and creates a new "udf_file_t" structure to hold the number of AD chains, the AD chains and a few useful bits of information.

A new function has been written to convert the wanted block number inside the UDF file. Previously it was always "start_block + offset_block". Now it scans the AD chain for the chain in which "offset_block" is contained, and returns the correct RAW block offset from that AD chain's starting block.

UDF AD chains do not HAVE to be in incrementing order either, and you will find that some ARCcoS DVDs have the chains backwards. This patch will also fix this situation.

This patch mostly changes dvd_udf.c internally, with changes to dvd_reader.c to use the new udf_file_t instead of "lbnum". The patch should be transparent to software using dvdread. (Apart from no longer receiving GAP blocks, and receiving the full end blocks of VOBs larger than 1 AD chain).

This patch is required to allow larger files in UDF format, as the number of AD chains increases with filesize. For example, a 4GB file will use 5 AD chains.


--
Jorgen Lundman       | <lund...@lundman.net>
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)
Index: src/dvd_reader.c
===================================================================
--- src/dvd_reader.c    (revision 1181)
+++ src/dvd_reader.c    (working copy)
@@ -100,7 +100,7 @@
   int css_title;
 
   /* Information required for an image file. */
-  uint32_t lb_start;
+  udf_file_t *udf_file;
   uint32_t seek_pos;
 
   /* Information required for a directory path drive. */
@@ -163,7 +163,8 @@
   struct timeval all_s, all_e;
   struct timeval t_s, t_e;
   char filename[ MAX_UDF_FILE_NAME_LEN ];
-  uint32_t start, len;
+  uint32_t len;
+  udf_file_t *udf_file;
   int title;
 
   char *nokeys_str = getenv("DVDREAD_NOKEYS");
@@ -183,31 +184,33 @@
     } else {
       sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, 0 );
     }
-    start = UDFFindFile( dvd, filename, &len );
-    if( start != 0 && len != 0 ) {
+    udf_file = UDFFindFile( dvd, filename, &len );
+    if( udf_file != NULL && len != 0 ) {
       /* Perform CSS key cracking for this title. */
       fprintf( stderr, "libdvdread: Get key for %s at 0x%08x\n",
-               filename, start );
-      if( dvdinput_title( dvd->dev, (int)start ) < 0 ) {
-        fprintf( stderr, "libdvdread: Error cracking CSS key for %s 
(0x%08x)\n", filename, start);
+               filename,  UDFFileBlockPos(udf_file, 0) );
+      if( dvdinput_title( dvd->dev, (int)UDFFileBlockPos(udf_file, 0) ) < 0 ) {
+        fprintf( stderr, "libdvdread: Error cracking CSS key for %s 
(0x%08x)\n", filename, UDFFileBlockPos(udf_file, 0));
       }
       gettimeofday( &t_e, NULL );
       fprintf( stderr, "libdvdread: Elapsed time %ld\n",
                (long int) t_e.tv_sec - t_s.tv_sec );
     }
 
+    UDFFreeFile(dvd, udf_file); udf_file = NULL;
+
     if( title == 0 ) continue;
 
     gettimeofday( &t_s, NULL );
     sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, 1 );
-    start = UDFFindFile( dvd, filename, &len );
-    if( start == 0 || len == 0 ) break;
+    udf_file = UDFFindFile( dvd, filename, &len );
+    if( udf_file == NULL || len == 0 ) break;
 
     /* Perform CSS key cracking for this title. */
     fprintf( stderr, "libdvdread: Get key for %s at 0x%08x\n",
-             filename, start );
-    if( dvdinput_title( dvd->dev, (int)start ) < 0 ) {
-      fprintf( stderr, "libdvdread: Error cracking CSS key for %s 
(0x%08x)!!\n", filename, start);
+             filename, UDFFileBlockPos(udf_file, 0) );
+    if( dvdinput_title( dvd->dev, (int)UDFFileBlockPos(udf_file, 0) ) < 0 ) {
+      fprintf( stderr, "libdvdread: Error cracking CSS key for %s 
(0x%08x)!!\n", filename, UDFFileBlockPos(udf_file, 0));
     }
     gettimeofday( &t_e, NULL );
     fprintf( stderr, "libdvdread: Elapsed time %ld\n",
@@ -220,6 +223,8 @@
   fprintf( stderr, "libdvdread: Elapsed time %ld\n",
            (long int) all_e.tv_sec - all_s.tv_sec );
 
+  UDFFreeFile(dvd, udf_file); udf_file = NULL;
+
   return 0;
 }
 
@@ -587,22 +592,24 @@
  */
 static dvd_file_t *DVDOpenFileUDF( dvd_reader_t *dvd, char *filename )
 {
-  uint32_t start, len;
+  uint32_t len;
+  udf_file_t *udf_file;
   dvd_file_t *dvd_file;
 
-  start = UDFFindFile( dvd, filename, &len );
-  if( !start ) {
+  udf_file = UDFFindFile( dvd, filename, &len );
+  if( !udf_file ) {
     fprintf( stderr, "libdvdnav:DVDOpenFileUDF:UDFFindFile %s failed\n", 
filename );
     return NULL;
   }
 
   dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) );
   if( !dvd_file ) {
+    UDFFreeFile(dvd, udf_file);
     fprintf( stderr, "libdvdnav:DVDOpenFileUDF:malloc failed\n" );
     return NULL;
   }
   dvd_file->dvd = dvd;
-  dvd_file->lb_start = start;
+  dvd_file->udf_file = udf_file;
   dvd_file->seek_pos = 0;
   memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) );
   memset( dvd_file->title_devs, 0, sizeof( dvd_file->title_devs ) );
@@ -698,7 +705,7 @@
     return NULL;
   }
   dvd_file->dvd = dvd;
-  dvd_file->lb_start = 0;
+  dvd_file->udf_file = NULL;
   dvd_file->seek_pos = 0;
   memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) );
   memset( dvd_file->title_devs, 0, sizeof( dvd_file->title_devs ) );
@@ -719,7 +726,8 @@
 static dvd_file_t *DVDOpenVOBUDF( dvd_reader_t *dvd, int title, int menu )
 {
   char filename[ MAX_UDF_FILE_NAME_LEN ];
-  uint32_t start, len;
+  uint32_t len;
+  udf_file_t *udf_file;
   dvd_file_t *dvd_file;
 
   if( title == 0 ) {
@@ -727,18 +735,22 @@
   } else {
     sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, menu ? 0 : 1 );
   }
-  start = UDFFindFile( dvd, filename, &len );
-  if( start == 0 ) return NULL;
+  udf_file = UDFFindFile( dvd, filename, &len );
+  if( udf_file == NULL ) return NULL;
 
   dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) );
-  if( !dvd_file ) return NULL;
+  if( !dvd_file ) {
+    UDFFreeFile(dvd, udf_file);
+    return NULL;
+  }
   dvd_file->dvd = dvd;
   /*Hack*/ dvd_file->css_title = title << 1 | menu;
-  dvd_file->lb_start = start;
+  dvd_file->udf_file = udf_file;
   dvd_file->seek_pos = 0;
   memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) );
   memset( dvd_file->title_devs, 0, sizeof( dvd_file->title_devs ) );
   dvd_file->filesize = len / DVD_VIDEO_LB_LEN;
+  udf_file = NULL;
 
   /* Calculate the complete file size for every file in the VOBS */
   if( !menu ) {
@@ -746,7 +758,8 @@
 
     for( cur = 2; cur < 10; cur++ ) {
       sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, cur );
-      if( !UDFFindFile( dvd, filename, &len ) ) break;
+      if( !(udf_file = UDFFindFile( dvd, filename, &len )) ) break;
+      UDFFreeFile(dvd, udf_file);
       dvd_file->filesize += len / DVD_VIDEO_LB_LEN;
     }
   }
@@ -777,7 +790,7 @@
   if( !dvd_file ) return NULL;
   dvd_file->dvd = dvd;
   /*Hack*/ dvd_file->css_title = title << 1 | menu;
-  dvd_file->lb_start = 0;
+  dvd_file->udf_file = NULL;
   dvd_file->seek_pos = 0;
   memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) );
   memset( dvd_file->title_devs, 0, sizeof( dvd_file->title_devs ) );
@@ -904,6 +917,8 @@
       }
     }
 
+    if( dvd_file->udf_file ) UDFFreeFile( dvd_file->dvd, dvd_file->udf_file );
+
     free( dvd_file );
     dvd_file = 0;
   }
@@ -918,14 +933,16 @@
   off_t parts_size[ 9 ];
   int nr_parts = 0;
   int n;
+  udf_file_t *udf_file;
 
   if( title == 0 )
     sprintf( filename, "/VIDEO_TS/VIDEO_TS.VOB" );
   else
     sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, menu ? 0 : 1 );
 
-  if( !UDFFindFile( dvd, filename, &size ) )
+  if( !(udf_file = UDFFindFile( dvd, filename, &size ) ) )
     return -1;
+  UDFFreeFile(dvd, udf_file);
 
   tot_size = size;
   nr_parts = 1;
@@ -936,8 +953,9 @@
 
     for( cur = 2; cur < 10; cur++ ) {
       sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, cur );
-      if( !UDFFindFile( dvd, filename, &size ) )
+      if( !(udf_file = UDFFindFile( dvd, filename, &size ) ) )
         break;
+      UDFFreeFile(dvd, udf_file);
 
       parts_size[ nr_parts ] = size;
       tot_size += size;
@@ -1016,6 +1034,7 @@
   char full_path[ PATH_MAX + 1 ];
   struct stat fileinfo;
   uint32_t size;
+  udf_file_t *udf_file;
 
   /* Check arguments. */
   if( dvd == NULL || titlenum < 0 ) {
@@ -1062,10 +1081,11 @@
   }
 
   if( dvd->isImageFile ) {
-    if( UDFFindFile( dvd, filename, &size ) ) {
+    if( (udf_file = UDFFindFile( dvd, filename, &size ) ) ) {
       statbuf->size = size;
       statbuf->nr_parts = 1;
       statbuf->parts_size[ 0 ] = size;
+      UDFFreeFile(dvd, udf_file);
       return 0;
     }
   } else {
@@ -1116,7 +1136,8 @@
                              size_t block_count, unsigned char *data,
                              int encrypted )
 {
-  return UDFReadBlocksRaw( dvd_file->dvd, dvd_file->lb_start + offset,
+  return UDFReadBlocksRaw( dvd_file->dvd,
+                           UDFFileBlockPos(dvd_file->udf_file, offset),
                            block_count, data, encrypted );
 }
 
@@ -1208,11 +1229,11 @@
   if( dvd_file->dvd->css_title != dvd_file->css_title ) {
     dvd_file->dvd->css_title = dvd_file->css_title;
     if( dvd_file->dvd->isImageFile ) {
-      dvdinput_title( dvd_file->dvd->dev, (int)dvd_file->lb_start );
+      dvdinput_title( dvd_file->dvd->dev, 
(int)UDFFileBlockPos(dvd_file->udf_file, 0) );
     }
     /* Here each vobu has it's own dvdcss handle, so no need to update
     else {
-      dvdinput_title( dvd_file->title_devs[ 0 ], (int)dvd_file->lb_start );
+      dvdinput_title( dvd_file->title_devs[ 0 ], 
(int)UDFFileBlockPos(dvd_file->udf_file, 0) );
     }*/
   }
 
Index: src/dvd_udf.c
===================================================================
--- src/dvd_udf.c       (revision 1181)
+++ src/dvd_udf.c       (working copy)
@@ -93,6 +93,13 @@
   uint16_t Partition;
 };
 
+struct UDF_FILE {
+  uint64_t Length;
+  uint32_t num_AD;
+  uint32_t Partition_Start;
+  struct AD AD_chain[UDF_MAX_AD_CHAINS];
+};
+
 struct extent_ad {
   uint32_t location;
   uint32_t length;
@@ -117,7 +124,7 @@
 
 struct icbmap {
   uint32_t lbn;
-  struct AD file;
+  udf_file_t file;
   uint8_t filetype;
 };
 
@@ -327,6 +334,14 @@
                   | ((uint32_t)data[(p) + 1] << 8)      \
                   | ((uint32_t)data[(p) + 2] << 16)     \
                   | ((uint32_t)data[(p) + 3] << 24))
+#define GETN8(p) ((uint64_t)data[p]                 \
+                  | ((uint64_t)data[(p) + 1] << 8)  \
+                  | ((uint64_t)data[(p) + 2] << 16) \
+                  | ((uint64_t)data[(p) + 3] << 24) \
+                  | ((uint64_t)data[(p) + 4] << 32) \
+                  | ((uint64_t)data[(p) + 5] << 40) \
+                  | ((uint64_t)data[(p) + 6] << 48) \
+                  | ((uint64_t)data[(p) + 7] << 56))
 /* This is wrong with regard to endianess */
 #define GETN(p, n, target) memcpy(target, &data[p], n)
 
@@ -427,7 +442,7 @@
 }
 
 static int UDFFileEntry( uint8_t *data, uint8_t *FileType,
-                         struct Partition *partition, struct AD *ad )
+                         struct Partition *partition, udf_file_t *fad )
 {
   uint16_t flags;
   uint32_t L_EA, L_AD;
@@ -436,15 +451,22 @@
   UDFICB( &data[ 16 ], FileType, &flags );
 
   /* Init ad for an empty file (i.e. there isn't a AD, L_AD == 0 ) */
-  ad->Length = GETN4( 60 ); /* Really 8 bytes a 56 */
-  ad->Flags = 0;
-  ad->Location = 0; /* what should we put here?  */
-  ad->Partition = partition->Number; /* use number of current partition */
+  fad->Length = GETN8( 56 ); /* Really 8 bytes at 56 */
 
   L_EA = GETN4( 168 );
   L_AD = GETN4( 172 );
   p = 176 + L_EA;
+  fad->num_AD = 0;
   while( p < 176 + L_EA + L_AD ) {
+    struct AD *ad;
+
+    if (fad->num_AD >= UDF_MAX_AD_CHAINS) return 0;
+
+    ad =  &fad->AD_chain[fad->num_AD];
+    ad->Partition = partition->Number;
+    ad->Flags = 0;
+    fad->num_AD++;
+
     switch( flags & 0x0007 ) {
     case 0:
       UDFShortAD( &data[ p ], ad, partition );
@@ -503,7 +525,7 @@
  * return 1 on success, 0 on error;
  */
 static int UDFMapICB( dvd_reader_t *device, struct AD ICB, uint8_t *FileType,
-                      struct Partition *partition, struct AD *File )
+                      struct Partition *partition, udf_file_t *File )
 {
   uint8_t LogBlock_base[DVD_VIDEO_LB_LEN + 2048];
   uint8_t *LogBlock = (uint8_t *)(((uintptr_t)LogBlock_base & 
~((uintptr_t)2047)) + 2048);
@@ -539,12 +561,12 @@
 }
 
 /**
- * Dir: Location of directory to scan
+ * Dir: Location of directory to scan (This is not a struct-ptr, so not ANSI C)
  * FileName: Name of file to look for
  * FileICB: Location of ICB of the found file
  * return 1 on success, 0 on error;
  */
-static int UDFScanDir( dvd_reader_t *device, struct AD Dir, char *FileName,
+static int UDFScanDir( dvd_reader_t *device, udf_file_t Dir, char *FileName,
                        struct Partition *partition, struct AD *FileICB,
                        int cache_file_info)
 {
@@ -562,13 +584,13 @@
   int in_cache = 0;
 
   /* Scan dir for ICB of file */
-  lbnum = partition->Start + Dir.Location;
+  lbnum = partition->Start + Dir.AD_chain[0].Location;
 
   if(DVDUDFCacheLevel(device, -1) > 0) {
     /* caching */
 
     if(!GetUDFCache(device, LBUDFCache, lbnum, &cached_dir)) {
-      dir_lba = (Dir.Length + DVD_VIDEO_LB_LEN) / DVD_VIDEO_LB_LEN;
+      dir_lba = (Dir.AD_chain[0].Length + DVD_VIDEO_LB_LEN) / DVD_VIDEO_LB_LEN;
       if((cached_dir_base = malloc(dir_lba * DVD_VIDEO_LB_LEN + 2048)) == NULL)
         return 0;
       cached_dir = (uint8_t *)(((uintptr_t)cached_dir_base & 
~((uintptr_t)2047)) + 2048);
@@ -596,15 +618,17 @@
 
     p = 0;
 
-    while( p < Dir.Length ) {
+    while( p < Dir.AD_chain[0].Length ) {
       UDFDescriptor( &cached_dir[ p ], &TagID );
       if( TagID == 257 ) {
         p += UDFFileIdentifier( &cached_dir[ p ], &filechar,
                                 filename, &tmpICB );
         if(cache_file_info && !in_cache) {
           uint8_t tmpFiletype;
-          struct AD tmpFile;
+          udf_file_t tmpFile;
 
+          memset(&tmpFile, 0, sizeof(tmpFile));
+
           if( !strcasecmp( FileName, filename ) ) {
             memcpy(FileICB, &tmpICB, sizeof(tmpICB));
             found = 1;
@@ -631,11 +655,11 @@
     return 0;
 
   p = 0;
-  while( p < Dir.Length ) {
+  while( p < Dir.AD_chain[0].Length ) {
     if( p > DVD_VIDEO_LB_LEN ) {
       ++lbnum;
       p -= DVD_VIDEO_LB_LEN;
-      Dir.Length -= DVD_VIDEO_LB_LEN;
+      Dir.AD_chain[0].Length -= DVD_VIDEO_LB_LEN;
       if( DVDReadLBUDF( device, lbnum, 2, directory, 0 ) <= 0 ) {
         return 0;
       }
@@ -782,7 +806,58 @@
   return part->valid;
 }
 
-uint32_t UDFFindFile( dvd_reader_t *device, char *filename,
+
+/*
+ * Release a UDF file descriptor
+ */
+void UDFFreeFile(dvd_reader_t *device, udf_file_t *File)
+{
+  free(File);
+}
+
+
+/*
+ * The API users will refer to block 0 as start of file and going up
+ * we need to convert that to actual disk block; partition_start +
+ * file_start + offset, but keep in mind that file_start is chained,
+ * and not contiguous.
+ *
+ * We return "0" as error, since a File can not start at physical block 0
+ *
+ * It is perhaps unfortunate that Location is in blocks, but Length is
+ * in bytes..? Can bytes be uneven blocksize in the middle of a chain?
+ *
+ */
+uint32_t UDFFileBlockPos(udf_file_t *File, uint32_t file_block)
+{
+  uint32_t result, i, offset;
+
+  if (!File) return 0;
+
+  /* Look through the chain to see where this block would belong. */
+  for (i = 0, offset = 0; i < File->num_AD; i++) {
+    /* Is "file_block" inside this chain? Then use this chain. */
+    if (file_block < (offset +
+                      (File->AD_chain[i].Length /  DVD_VIDEO_LB_LEN))) break;
+    offset += (File->AD_chain[i].Length /  DVD_VIDEO_LB_LEN);
+  }
+
+  /* If it is not defined in the AD chains, we should return an error, but
+   * in the interest of being backward (in)compatible with the original
+   * libdvdread, we revert back to the traditional view that UDF file are
+   * one contiguous long chain, in case some API software out there relies on
+   * this incorrect behavior.
+   */
+  if (i >= File->num_AD) i = 0;
+
+  result = File->Partition_Start + File->AD_chain[i].Location + file_block - 
offset;
+  return result;
+}
+
+
+
+
+udf_file_t *UDFFindFile( dvd_reader_t *device, char *filename,
                       uint32_t *filesize )
 {
   uint8_t LogBlock_base[ DVD_VIDEO_LB_LEN + 2048 ];
@@ -790,11 +865,12 @@
   uint32_t lbnum;
   uint16_t TagID;
   struct Partition partition;
-  struct AD RootICB, File, ICB;
+  struct AD RootICB, ICB;
+  udf_file_t File, *result;
   char tokenline[ MAX_UDF_FILE_NAME_LEN ];
   char *token;
   uint8_t filetype;
-
+  memset(&File, 0, sizeof(File));
   *filesize = 0;
   tokenline[0] = '\0';
   strncat(tokenline, filename, MAX_UDF_FILE_NAME_LEN - 1);
@@ -822,17 +898,17 @@
 
     /* Sanity checks. */
     if( TagID != 256 )
-      return 0;
+      return NULL;
     if( RootICB.Partition != 0 )
-      return 0;
+      return NULL;
     SetUDFCache(device, RootICBCache, 0, &RootICB);
   }
 
   /* Find root dir */
   if( !UDFMapICB( device, RootICB, &filetype, &partition, &File ) )
-    return 0;
+    return NULL;
   if( filetype != 4 )
-    return 0;  /* Root dir should be dir */
+    return NULL;  /* Root dir should be dir */
   {
     int cache_file_info = 0;
     /* Tokenize filepath */
@@ -841,9 +917,9 @@
     while( token != NULL ) {
       if( !UDFScanDir( device, File, token, &partition, &ICB,
                        cache_file_info))
-        return 0;
+        return NULL;
       if( !UDFMapICB( device, ICB, &filetype, &partition, &File ) )
-        return 0;
+        return NULL;
       if(!strcmp(token, "VIDEO_TS"))
         cache_file_info = 1;
       token = strtok( NULL, "/" );
@@ -851,14 +927,23 @@
   }
 
   /* Sanity check. */
-  if( File.Partition != 0 )
-    return 0;
+  if( File.AD_chain[0].Partition != 0 )
+    return NULL;
   *filesize = File.Length;
   /* Hack to not return partition.Start for empty files. */
-  if( !File.Location )
-    return 0;
-  else
-    return partition.Start + File.Location;
+  if( !File.AD_chain[0].Location )
+    return NULL;
+
+  // Allocate a UDF_FILE node for the API user
+  result = (udf_file_t *) malloc(sizeof(*result));
+  if (!result) return NULL;
+
+  // Copy over the information
+  memcpy(result, &File, sizeof(*result));
+
+  result->Partition_Start = partition.Start;
+
+  return result;
 }
 
 
Index: src/dvdread/dvd_udf.h
===================================================================
--- src/dvdread/dvd_udf.h       (revision 1181)
+++ src/dvdread/dvd_udf.h       (working copy)
@@ -39,6 +39,32 @@
 extern "C" {
 #endif
 
+
+
+/*
+ *
+ * UDF defines struct AD, which dvdread unfortunately overloads to refer to
+ * a file, creating problems with chained ADs. We need to define a generic
+ * UDF_FILE structure to hold the information required.
+ * It could be worth a separate struct for Directories, since they are 
(probably)
+ * only ever in 1 chain.
+ *
+ * Is there a real max number of chains? What can fit in 2048?
+ * My 4.4GB file example uses 5 chains. A BD ISO can store 50GB of data, so
+ * potentially we could have a 50GB file, so we would need to be able to
+ * support 62 chains.
+ *
+ */
+
+#ifndef UDF_MAX_AD_CHAINS     // Allow MAX to be increased by API.
+#define UDF_MAX_AD_CHAINS 50
+#endif
+
+
+typedef struct UDF_FILE udf_file_t;
+
+
+
 /**
  * Looks for a file on the UDF disc/imagefile and returns the block number
  * where it begins, or 0 if it is not found.  The filename should be an
@@ -46,8 +72,9 @@
  * '/VIDEO_TS/VTS_01_1.IFO'.  On success, filesize will be set to the size of
  * the file in bytes.
  */
-uint32_t UDFFindFile( dvd_reader_t *device, char *filename, uint32_t *size );
-
+udf_file_t *UDFFindFile( dvd_reader_t *device, char *filename, uint32_t *size 
);
+void        UDFFreeFile( dvd_reader_t *device, udf_file_t *udf_file );
+uint32_t    UDFFileBlockPos( udf_file_t *udf_file, uint32_t file_block);
 void FreeUDFCache(void *cache);
 int UDFGetVolumeIdentifier(dvd_reader_t *device,
                            char *volid, unsigned int volid_size);
_______________________________________________
DVDnav-discuss mailing list
DVDnav-discuss@mplayerhq.hu
https://lists.mplayerhq.hu/mailman/listinfo/dvdnav-discuss

Reply via email to