[DVDnav-discuss] [PATCH] Patch 1/5: Resend

Dominik 'Rathann' Mierzejewski dominik at greysector.net
Thu Oct 6 17:51:06 CEST 2011


On Thursday, 06 October 2011 at 17:10, John Stebbins wrote:
> On 10/06/2011 07:11 AM, Dominik 'Rathann' Mierzejewski wrote:
> > On Sunday, 26 October 2008 at 23:21, Diego Biurrun wrote:
> >> On Tue, Oct 21, 2008 at 09:43:05AM +0200, Nico Sabbi wrote:
> >>> On Tuesday 21 October 2008 09:31:12 Diego Biurrun wrote:
> >>>> cosmetics
> >>>>
> >>>> Nico, do you want these committed separately or not at all?
> >>> separately, but I have to test the actual working of the code before
> >>> committing.
> >>> Don't bother resending
> >> I committed the cosmetics separately, here is the updated patch.
> > Could someone review? Nico, Erik, John ...?
> >
> I have no idea what this is referencing.  I can't find any relevant messages in a search through my email history.

It's almost one year old. Reattaching. If you need me to resend other patches
I bumped up, just say a word.

Regards,
Dominik

-- 
Fedora http://fedoraproject.org/wiki/User:Rathann
RPMFusion http://rpmfusion.org | MPlayer http://mplayerhq.hu
"Faith manages."
        -- Delenn to Lennier in Babylon 5:"Confessions and Lamentations"
-------------- next part --------------
Index: src/dvd_reader.c
===================================================================
--- src/dvd_reader.c	(revision 1158)
+++ src/dvd_reader.c	(working copy)
@@ -102,7 +102,7 @@
   int css_title;
 
   /* Information required for an image file. */
-  uint32_t lb_start;
+  UDF_FILE udf_file;
   uint32_t seek_pos;
 
   /* Information required for a directory path drive. */
@@ -111,6 +111,10 @@
 
   /* Calculated at open-time, size in blocks. */
   ssize_t filesize;
+
+  /* Size of file in bytes. */
+  uint64_t filebytes;
+
 };
 
 int UDFReadBlocksRaw( dvd_reader_t *device, uint32_t lb_number,
@@ -159,7 +163,9 @@
   struct timeval all_s, all_e;
   struct timeval t_s, t_e;
   char filename[ MAX_UDF_FILE_NAME_LEN ];
-  uint32_t start, len;
+  UDF_FILE udf_file;
+  uint32_t start;
+  uint64_t len;
   int title;
 
   char *nokeys_str = getenv("DVDREAD_NOKEYS");
@@ -179,9 +185,10 @@
     } 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. */
+      start = UDFFileBlockPos(udf_file, 0);
       fprintf( stderr, "libdvdread: Get key for %s at 0x%08x\n",
                filename, start );
       if( dvdinput_title( dvd->dev, (int)start ) < 0 ) {
@@ -192,14 +199,18 @@
                (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 == 0 || len == 0 ) break;
 
     /* Perform CSS key cracking for this title. */
+    start = UDFFileBlockPos(udf_file, 0);
     fprintf( stderr, "libdvdread: Get key for %s at 0x%08x\n",
              filename, start );
     if( dvdinput_title( dvd->dev, (int)start ) < 0 ) {
@@ -216,6 +227,9 @@
   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;
 }
 
@@ -565,11 +579,12 @@
  */
 static dvd_file_t *DVDOpenFileUDF( dvd_reader_t *dvd, char *filename )
 {
-  uint32_t start, len;
+  UDF_FILE udf_file;
+  uint64_t len;
   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;
   }
@@ -580,11 +595,12 @@
     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 ) );
   dvd_file->filesize = len / DVD_VIDEO_LB_LEN;
+  dvd_file->filebytes = len;
 
   return dvd_file;
 }
@@ -676,7 +692,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 ) );
@@ -690,6 +706,7 @@
   dvd_file->title_sizes[ 0 ] = fileinfo.st_size / DVD_VIDEO_LB_LEN;
   dvd_file->title_devs[ 0 ] = dev;
   dvd_file->filesize = dvd_file->title_sizes[ 0 ];
+  dvd_file->filebytes = fileinfo.st_size;
 
   return dvd_file;
 }
@@ -697,7 +714,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;
+  UDF_FILE udf_file;
+  uint64_t len;
   dvd_file_t *dvd_file;
 
   if( title == 0 ) {
@@ -705,18 +723,19 @@
   } 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;
   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;
+  dvd_file->filebytes = len;
 
   /* Calculate the complete file size for every file in the VOBS */
   if( !menu ) {
@@ -755,11 +774,12 @@
   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 ) );
   dvd_file->filesize = 0;
+  dvd_file->filebytes = 0;
 
   if( menu ) {
     dvd_input_t dev;
@@ -884,6 +904,9 @@
       }
     }
 
+    if (dvd_file->udf_file)
+      UDFFreeFile(NULL, dvd_file->udf_file);
+
     free( dvd_file );
     dvd_file = 0;
   }
@@ -922,7 +945,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 );
 }
 
@@ -1014,7 +1038,7 @@
   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 {
@@ -1046,6 +1070,15 @@
   return offset;
 }
 
+uint64_t DVDFileSize64( dvd_file_t *dvd_file )
+{
+  /* Check arguments. */
+  if( dvd_file == NULL )
+    return -1;
+
+  return dvd_file->filebytes;
+}
+
 int DVDFileSeekForce(dvd_file_t *dvd_file, int offset, int force_size)
 {
   /* Check arguments. */
Index: src/dvd_reader.h
===================================================================
--- src/dvd_reader.h	(revision 1158)
+++ src/dvd_reader.h	(working copy)
@@ -196,6 +196,11 @@
 ssize_t DVDFileSize( dvd_file_t * );
 
 /**
+ * Define separate 64-bit version to be back-ward compatible.
+ */
+uint64_t DVDFileSize64( dvd_file_t * );
+
+/**
  * Get a unique 128 bit disc ID.
  * This is the MD5 sum of VIDEO_TS.IFO and the VTS_0?_0.IFO files
  * in title order (those that exist).
Index: src/dvd_udf.c
===================================================================
--- src/dvd_udf.c	(revision 1158)
+++ src/dvd_udf.c	(working copy)
@@ -88,6 +88,10 @@
   uint32_t Length;
 };
 
+/* Previously, dvdread re-used AD to carry up the filesize, resulting in
+ * a 64bit->32bit problem. This is acceptable on most DVD images (1GB VOB files)
+ * but not desirable. Now it has changed to use a FileAD when it is actually
+ * used for files, and AD otherwise.   - Lund */
 struct AD {
   uint32_t Location;
   uint32_t Length;
@@ -95,6 +99,25 @@
   uint16_t Partition;
 };
 
+/* Previously dvdread would assume files only had one AD chain, and since they
+ * are 1GB or less, this is most problably true. However, now we handle chains
+ * for large files. ECMA_167 does not specify the maximum number of chains, is
+ * it as many as can fit in a 2048 block? (minus ID 266 size), or some other
+ * limit. For now, I have assumed that;
+ * a 4.4GB file uses 5 AD chains. A BluRay disk can store 50GB of data, so the
+ * largest file should be 50 GB. So the maximum number of chains should be
+ * around 62. We could also change it to be allocated as needed.
+ */
+
+#define UDF_MAX_AD_CHAINS 50
+
+struct FileAD {
+    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;
@@ -119,7 +142,7 @@
 
 struct icbmap {
   uint32_t lbn;
-  struct AD file;
+  struct FileAD file;
   uint8_t filetype;
 };
 
@@ -142,6 +165,17 @@
   PartitionCache, RootICBCache, LBUDFCache, MapCache, AVDPCache, PVDCache
 } UDFCacheType;
 
+/*
+ * Release an allocated FileAD data. Technically you can just call free()
+ * but it is clean to stay modular. (Should we one day record further data.
+ */
+void UDFFreeFile(dvd_reader_t *device, struct FileAD *File)
+{
+  free(File);
+}
+
+
+
 void FreeUDFCache(void *cache)
 {
   struct udf_cache *c = (struct udf_cache *)cache;
@@ -329,6 +363,15 @@
                   | ((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)
 
@@ -429,24 +472,35 @@
 }
 
 static int UDFFileEntry( uint8_t *data, uint8_t *FileType,
-                         struct Partition *partition, struct AD *ad )
+                         struct Partition *partition, struct FileAD *fad )
 {
   uint16_t flags;
   uint32_t L_EA, L_AD;
   unsigned int p;
+  unsigned int curr_ad;
 
   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 ); /* Was 4 bytes at 60, changed to 64-bit. */
 
   L_EA = GETN4( 168 );
   L_AD = GETN4( 172 );
   p = 176 + L_EA;
+  curr_ad = 0;
+
+  /* Function changed to record all AD chains, not just the last one! */
   while( p < 176 + L_EA + L_AD ) {
+    struct AD *ad;
+
+    if (curr_ad >= UDF_MAX_AD_CHAINS) return 0;
+
+    ad =  &fad->AD_chain[curr_ad];
+    ad->Partition = partition->Number;
+    ad->Flags = 0;
+    // Increase AD chain ptr
+    curr_ad++;
+
     switch( flags & 0x0007 ) {
     case 0:
       UDFShortAD( &data[ p ], ad, partition );
@@ -505,7 +559,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, struct FileAD *File )
 {
   uint8_t LogBlock_base[DVD_VIDEO_LB_LEN + 2048];
   uint8_t *LogBlock = (uint8_t *)(((uintptr_t)LogBlock_base & ~((uintptr_t)2047)) + 2048);
@@ -546,7 +600,7 @@
  * 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, struct FileAD Dir, char *FileName,
                        struct Partition *partition, struct AD *FileICB,
                        int cache_file_info)
 {
@@ -564,13 +618,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);
@@ -598,15 +652,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;
+          struct FileAD tmpFile;
 
+          memset(&tmpFile, 0, sizeof(tmpFile));
+
           if( !strcasecmp( FileName, filename ) ) {
             memcpy(FileICB, &tmpICB, sizeof(tmpICB));
             found = 1;
@@ -633,11 +689,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;
       }
@@ -784,23 +840,89 @@
   return part->valid;
 }
 
-uint32_t UDFFindFile( dvd_reader_t *device, char *filename,
-                      uint32_t *filesize )
+/*
+ * Translate between File logic block, and actual disk-block, taking into
+ * account for partition start, file block start, and chain position.
+ *
+ * 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
+ *
+ */
+uint32_t UDFFileBlockPos(struct FileAD *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);
+
+  }
+
+  // Beyond out chains of AD? We could return error, or just fall back to
+  // old behavior in case someone relies on the broken way.
+  if (i >= File->num_AD)
+    i = 0;
+
+  // Compute actual block number
+  result = File->Partition_Start
+    + File->AD_chain[i].Location
+    + file_block
+    - offset;
+
+
+#ifdef DEBUG
+  if (!(file_block % 10000))
+    fprintf(stderr, "libdvdread: File block %d -> %d (chain %d + offset %d : %d)\r\n",
+            file_block, result,
+            i,
+            file_block - offset,
+            (File->AD_chain[i].Length / DVD_VIDEO_LB_LEN));
+#endif
+  return result;
+
+}
+
+/*
+ * Find a File/Directory based on name.
+ *  in: DVD Device *
+ *  in: filename
+ * out: allocated UDF_FILE*, call UDFFreeFile() to release.
+ * out: Filesize. (Note: 64-bit)
+ * out: NULL to indicate error, File Not Found.
+ */
+UDF_FILE UDFFindFile( dvd_reader_t *device, char *filename,
+                      uint64_t *filesize )
+{
   uint8_t LogBlock_base[ DVD_VIDEO_LB_LEN + 2048 ];
   uint8_t *LogBlock = (uint8_t *)(((uintptr_t)LogBlock_base & ~((uintptr_t)2047)) + 2048);
   uint32_t lbnum;
   uint16_t TagID;
   struct Partition partition;
-  struct AD RootICB, File, ICB;
+  struct AD RootICB, ICB;
+  struct FileAD File;
   char tokenline[ MAX_UDF_FILE_NAME_LEN ];
   char *token;
   uint8_t filetype;
+  struct FileAD *result;
 
   *filesize = 0;
   tokenline[0] = '\0';
   strncat(tokenline, filename, MAX_UDF_FILE_NAME_LEN - 1);
   memset(&ICB, 0, sizeof(ICB));
+  memset(&File, 0, sizeof(File));
 
   if(!(GetUDFCache(device, PartitionCache, 0, &partition) &&
        GetUDFCache(device, RootICBCache, 0, &RootICB))) {
@@ -824,17 +946,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 */
@@ -853,14 +975,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 new UDF_FILE and return it. */
+  result = (struct FileAD *) malloc(sizeof(*result));
+  if (!result) return NULL;
+
+  memcpy(result, &File, sizeof(*result));
+
+  result->Partition_Start = partition.Start;
+
+  return result;
+
 }
 
 
Index: src/dvd_udf.h
===================================================================
--- src/dvd_udf.h	(revision 1158)
+++ src/dvd_udf.h	(working copy)
@@ -39,6 +39,8 @@
 extern "C" {
 #endif
 
+typedef struct FileAD *UDF_FILE;
+
 /**
  * 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,7 +48,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 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);
 
 void FreeUDFCache(void *cache);
 int UDFGetVolumeIdentifier(dvd_reader_t *device,


More information about the DVDnav-discuss mailing list