Separated RAR support, as it is the most questionble change in the old patch. Told emacs to never use tabs too, so it should be cleaner. Add UDF2.50 logic, which includes BD5ISO, and HD-DVD support. Support non-DVD style access. (File iteration, and reading). Diffed against svn 1153. This patch includes: 1. Add ExtFinfo (262) support 2. Add FileType (250) re-direct support 3. DVDOpendir/DVDReaddir/DVDClosedir/DVDOpenFile for UDF access. 4. dvdread-1.9.7 stat methods for obtaining VOB data and sizes 5. AD chaining, instead of assuming files will always fit in 1 AD group. 6. dvd_udf API uses "UDF_FILE" type instead of "starting block number". 7. Separate struct AD and struct FileAD instead of ugly 64->32 bit work. 8. Minor memory clearing problems, and memory leaks. Lund -- Jorgen Lundman | <lundman@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) -- Jorgen Lundman | <lundman@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) -- Jorgen Lundman | <lundman@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)
On Thu, Oct 09, 2008 at 08:16:08PM +0900, Jorgen Lundman wrote:
Told emacs to never use tabs too, so it should be cleaner.
You could tell emacs to M-x remove-trailing-whitespace and set show-trailing-whitespace, then you will see the places where you have added trailing whitespace, which are quite a few.
This patch includes:
1. Add ExtFinfo (262) support
2. Add FileType (250) re-direct support
3. DVDOpendir/DVDReaddir/DVDClosedir/DVDOpenFile for UDF access.
4. dvdread-1.9.7 stat methods for obtaining VOB data and sizes
5. AD chaining, instead of assuming files will always fit in 1 AD group.
6. dvd_udf API uses "UDF_FILE" type instead of "starting block number".
7. Separate struct AD and struct FileAD instead of ugly 64->32 bit work.
8. Minor memory clearing problems, and memory leaks.
These still look like 8 separate issues. Could you try to split this up into separate patches? Diego
Diego Biurrun wrote:
You could tell emacs to M-x remove-trailing-whitespace and set show-trailing-whitespace, then you will see the places where you have added trailing whitespace, which are quite a few.
Good idea. Adding the save-hook from here might even be better. http://www.emacswiki.org/cgi-bin/wiki/DeletingWhitespace
This patch includes:
1. Add ExtFinfo (262) support
2. Add FileType (250) re-direct support
3. DVDOpendir/DVDReaddir/DVDClosedir/DVDOpenFile for UDF access.
4. dvdread-1.9.7 stat methods for obtaining VOB data and sizes
5. AD chaining, instead of assuming files will always fit in 1 AD group.
6. dvd_udf API uses "UDF_FILE" type instead of "starting block number".
7. Separate struct AD and struct FileAD instead of ugly 64->32 bit work.
8. Minor memory clearing problems, and memory leaks.
These still look like 8 separate issues. Could you try to split this up into separate patches?
Some like UDF_FILE and 32bit->64bit are large sweeping changes. But I could possible do ExtFileInfo, FileType 250, opendir/readdir/closedir, and dvdread-0.9.7 stat calls as separate patches. But admittedly, I would probably just cut up the patch file into smaller bits. Lund -- Jorgen Lundman | <lundman@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)
On Fri, Oct 10, 2008 at 10:44:57AM +0900, Jorgen Lundman wrote:
Diego Biurrun wrote:
This patch includes:
1. Add ExtFinfo (262) support
2. Add FileType (250) re-direct support
3. DVDOpendir/DVDReaddir/DVDClosedir/DVDOpenFile for UDF access.
4. dvdread-1.9.7 stat methods for obtaining VOB data and sizes
5. AD chaining, instead of assuming files will always fit in 1 AD group.
6. dvd_udf API uses "UDF_FILE" type instead of "starting block number".
7. Separate struct AD and struct FileAD instead of ugly 64->32 bit work.
8. Minor memory clearing problems, and memory leaks.
These still look like 8 separate issues. Could you try to split this up into separate patches?
Some like UDF_FILE and 32bit->64bit are large sweeping changes. But I could possible do ExtFileInfo, FileType 250, opendir/readdir/closedir, and dvdread-0.9.7 stat calls as separate patches. But admittedly, I would probably just cut up the patch file into smaller bits.
That would already help. Diego
Attached patch for removing the hacky overload of "struct AD" which is also used for File operations, resulting in 64-bit to 32-bit conversions and more. Additionally, libdvdread assumed all blocks fit inside one AD chain, in contiguous order, which is generally true for all DVDs. (Since files are limited to 1GB in size). I have extended this to correctly handle the UDF AD chaining as the ECMA_167 specifications detail. All 32-bit filesize references have been changed to 64-bit. UDFFindFile() no longer return a "block number" but a reference to a "UDF_FILE". This should be freed by calling UDFFileFree(). All calls from dvd_reader.c have been updated. An additional function UDFFileBlockPos() has added to translate between a file's block offset, into correct disk block. (Walking the AD chains to find correct block, as well as, File start block and partition block number). Tested only against title_info.c since I need all patches for complete testing. -- Jorgen Lundman | <lundman@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: dvd_reader.c =================================================================== --- dvd_reader.c (revision 1157) +++ 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: dvd_reader.h =================================================================== --- dvd_reader.h (revision 1157) +++ 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: dvd_udf.c =================================================================== --- dvd_udf.c (revision 1157) +++ 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,38 +472,65 @@ } 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 = GETN4( 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 ); p += 8; break; - case 1: UDFLongAD( &data[ p ], ad ); p += 16; break; - case 2: UDFExtAD( &data[ p ], ad ); p += 20; break; + case 0: + UDFShortAD( &data[ p ], ad, partition ); + p += 8; + break; + case 1: + UDFLongAD( &data[ p ], ad ); + p += 16; + break; + case 2: + UDFExtAD( &data[ p ], ad ); + p += 20; + break; case 3: switch( L_AD ) { - case 8: UDFShortAD( &data[ p ], ad, partition ); break; - case 16: UDFLongAD( &data[ p ], ad ); break; - case 20: UDFExtAD( &data[ p ], ad ); break; + case 8: + UDFShortAD( &data[ p ], ad, partition ); + break; + case 16: + UDFLongAD( &data[ p ], ad ); + break; + case 20: + UDFExtAD( &data[ p ], ad ); + break; } p += L_AD; break; default: - p += L_AD; break; + p += L_AD; + break; } } return 0; @@ -489,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); @@ -530,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) { @@ -548,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); @@ -582,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; @@ -617,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; } @@ -768,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))) { @@ -808,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 */ @@ -837,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: dvd_udf.h =================================================================== --- dvd_udf.h (revision 1157) +++ 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,
I'm going out drinking in a bit, so rather than wait, I will just send the patches, then deal with whatever problem there may be. This patch adds support to handle ExtendedFileInfo (TagID 262) for UDF 2.50 formats. It also includes EXTFINFO with FileType of 250, which acts as a redirect block. This enables dvdread to handle UDF2.50 filesystems. The patch also includes minor fix to patch1. Lund -- Jorgen Lundman | <lundman@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) diff -ruib ../../../../versions/libdvdread_patch1/libdvdread/src/dvd_udf.c ./dvd_udf.c --- ../../../../versions/libdvdread_patch1/libdvdread/src/dvd_udf.c 2008-10-10 16:01:11.000000000 +0900 +++ ./dvd_udf.c 2008-10-10 16:20:12.000000000 +0900 @@ -536,6 +536,104 @@ return 0; } +/* TagID 266 + * The differences in ExtFile are indicated below: + * struct extfile_entry { + * struct desc_tag tag; + * struct icb_tag icbtag; + * uint32_t uid; + * uint32_t gid; + * uint32_t perm; + * uint16_t link_cnt; + * uint8_t rec_format; + * uint8_t rec_disp_attr; + * uint32_t rec_len; + * uint64_t inf_len; + * uint64_t obj_size; // NEW + * uint64_t logblks_rec; + * struct timestamp atime; + * struct timestamp mtime; + * struct timestamp ctime; // NEW + * struct timestamp attrtime; + * uint32_t ckpoint; + * uint32_t reserved1; // NEW + * struct long_ad ex_attr_icb; + * struct long_ad streamdir_icb; // NEW + * struct regid imp_id; + * uint64_t unique_id; + * uint32_t l_ea; + * uint32_t l_ad; + * uint8_t data[1]; + * } __packed; + * + * So old "l_ea" is now +216 + * + * Lund + */ +static int UDFExtFileEntry( uint8_t *data, uint8_t *FileType, + 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 ) */ + fad->Length = GETN8(56); // 64-bit. + + L_EA = GETN4( 208); + L_AD = GETN4( 212); + p = 216 + L_EA; + curr_ad = 0; + while( p < 216 + L_EA + L_AD ) { + struct AD *ad; + + if (curr_ad >= UDF_MAX_AD_CHAINS) return 0; +#ifdef DEBUG + fprintf(stderr, "libdvdread: reading AD chain %d\r\n", curr_ad); +#endif + ad = &fad->AD_chain[curr_ad]; + ad->Partition = partition->Number; + ad->Flags = 0; + curr_ad++; + + switch( flags & 0x0007 ) { + case 0: + UDFShortAD( &data[ p ], ad, partition ); + p += 8; + break; + case 1: + UDFLongAD( &data[ p ], ad ); + p += 16; + break; + case 2: + UDFExtAD( &data[ p ], ad ); + p += 20; + break; + case 3: + switch( L_AD ) { + case 8: + UDFShortAD( &data[ p ], ad, partition ); + break; + case 16: + UDFLongAD( &data[ p ], ad ); + break; + case 20: + UDFExtAD( &data[ p ], ad ); + break; + } + p += L_AD; + break; + default: + p += L_AD; + break; + } + } + return 0; +} + static int UDFFileIdentifier( uint8_t *data, uint8_t *FileCharacteristics, char *FileName, struct AD *FileICB ) { @@ -588,8 +686,18 @@ SetUDFCache(device, MapCache, tmpmap.lbn, &tmpmap); return 1; }; + + /* ExtendedFileInfo */ + if( TagID == 266 ) { + UDFExtFileEntry( LogBlock, FileType, partition, File ); + memcpy(&tmpmap.file, File, sizeof(tmpmap.file)); + tmpmap.filetype = *FileType; + SetUDFCache(device, MapCache, tmpmap.lbn, &tmpmap); + return 1; + } + } while( ( lbnum <= partition->Start + ICB.Location + ( ICB.Length - 1 ) - / DVD_VIDEO_LB_LEN ) && ( TagID != 261 ) ); + / DVD_VIDEO_LB_LEN ) && ( TagID != 261 ) && (TagID != 266) ); return 0; } @@ -937,6 +1045,23 @@ TagID = 0; else UDFDescriptor( LogBlock, &TagID ); + /* + * It seems that someone added a FileType of 250, which seems to be + * a "redirect" style file entry. If we discover such an entry, we + * add on the "location" to partition->Start, and try again. + * Who added this? Is there any official guide somewhere? + * 2008/09/17 lundman + * Should we handle 261(250) as well? FileEntry+redirect + */ + if( TagID == 266 ) { + UDFExtFileEntry( LogBlock, &filetype, &partition, &File ); + if (filetype == 250) { + partition.Start += File.AD_chain[0].Location; + lbnum = partition.Start; + SetUDFCache(device, PartitionCache, 0, &partition); + continue; + } + } /* File Set Descriptor */ if( TagID == 256 ) /* File Set Descriptor */ @@ -947,8 +1072,10 @@ /* Sanity checks. */ if( TagID != 256 ) return NULL; - if( RootICB.Partition != 0 ) - return NULL; + /* This following test will fail under UDF2.50 images, as it is no longer + * valid */ + /*if( RootICB.Partition != 0 ) + return NULL;*/ SetUDFCache(device, RootICBCache, 0, &RootICB); }
On Fri, Oct 10, 2008 at 05:52:35PM +0900, Jorgen Lundman wrote:
The patch also includes minor fix to patch1.
Please send an updated version of patch1 instead. Diego
GETN4 changed to GETN8 Lund -- Jorgen Lundman | <lundman@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: dvd_reader.c =================================================================== --- dvd_reader.c (revision 1157) +++ 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: dvd_reader.h =================================================================== --- dvd_reader.h (revision 1157) +++ 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: dvd_udf.c =================================================================== --- dvd_udf.c (revision 1157) +++ 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,38 +472,65 @@ } 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 ); p += 8; break; - case 1: UDFLongAD( &data[ p ], ad ); p += 16; break; - case 2: UDFExtAD( &data[ p ], ad ); p += 20; break; + case 0: + UDFShortAD( &data[ p ], ad, partition ); + p += 8; + break; + case 1: + UDFLongAD( &data[ p ], ad ); + p += 16; + break; + case 2: + UDFExtAD( &data[ p ], ad ); + p += 20; + break; case 3: switch( L_AD ) { - case 8: UDFShortAD( &data[ p ], ad, partition ); break; - case 16: UDFLongAD( &data[ p ], ad ); break; - case 20: UDFExtAD( &data[ p ], ad ); break; + case 8: + UDFShortAD( &data[ p ], ad, partition ); + break; + case 16: + UDFLongAD( &data[ p ], ad ); + break; + case 20: + UDFExtAD( &data[ p ], ad ); + break; } p += L_AD; break; default: - p += L_AD; break; + p += L_AD; + break; } } return 0; @@ -489,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); @@ -530,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) { @@ -548,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); @@ -582,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; @@ -617,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; } @@ -768,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))) { @@ -808,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 */ @@ -837,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: dvd_udf.h =================================================================== --- dvd_udf.h (revision 1157) +++ 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,
Il giorno dom, 12/10/2008 alle 21.29 +0900, Jorgen Lundman ha scritto:
GETN4 changed to GETN8
Lund
sorry for the delay. Just a note to say that I haven't had the time to review your patches. I'll do it in the week-end
On Sun, Oct 12, 2008 at 09:29:21PM +0900, Jorgen Lundman wrote:
GETN4 changed to GETN8
--- dvd_udf.c (revision 1157) +++ dvd_udf.c (working copy) @@ -429,38 +472,65 @@
switch( flags & 0x0007 ) { - case 0: UDFShortAD( &data[ p ], ad, partition ); p += 8; break; - case 1: UDFLongAD( &data[ p ], ad ); p += 16; break; - case 2: UDFExtAD( &data[ p ], ad ); p += 20; break; + case 0: + UDFShortAD( &data[ p ], ad, partition ); + p += 8; + break; + case 1: + UDFLongAD( &data[ p ], ad ); + p += 16; + break; + case 2: + UDFExtAD( &data[ p ], ad ); + p += 20; + break;
cosmetics
case 3: switch( L_AD ) { - case 8: UDFShortAD( &data[ p ], ad, partition ); break; - case 16: UDFLongAD( &data[ p ], ad ); break; - case 20: UDFExtAD( &data[ p ], ad ); break; + case 8: + UDFShortAD( &data[ p ], ad, partition ); + break; + case 16: + UDFLongAD( &data[ p ], ad ); + break; + case 20: + UDFExtAD( &data[ p ], ad ); + break;
cosmetics
default: - p += L_AD; break; + p += L_AD; + break;
cosmetics Nico, do you want these committed separately or not at all? Diego
On Tuesday 21 October 2008 09:31:12 Diego Biurrun wrote:
On Sun, Oct 12, 2008 at 09:29:21PM +0900, Jorgen Lundman wrote:
GETN4 changed to GETN8
cosmetics
Nico, do you want these committed separately or not at all?
Diego
separately, but I have to test the actual working of the code before committing. Don't bother resending
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. Diego
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 ...? 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"
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. -- John GnuPG fingerprint: CADFA1DB594CA50EB79427284617578AADE759A1
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"
Thanks to Jacob Pedersen, we now know that this patch wasn't quite correct. It used the "forward block" to shift the partition, but this meant all files started offset +64KB from the start. This is not great when you try to read the certificates. I committed a fix to this in my version where only directory listings are forwarded, and the partition (plus files) are left properly. Lund Jorgen Lundman wrote:
I'm going out drinking in a bit, so rather than wait, I will just send the patches, then deal with whatever problem there may be.
This patch adds support to handle ExtendedFileInfo (TagID 262) for UDF 2.50 formats. It also includes EXTFINFO with FileType of 250, which acts as a redirect block.
This enables dvdread to handle UDF2.50 filesystems.
The patch also includes minor fix to patch1.
Lund
------------------------------------------------------------------------
_______________________________________________ DVDnav-discuss mailing list DVDnav-discuss@mplayerhq.hu https://lists.mplayerhq.hu/mailman/listinfo/dvdnav-discuss
-- Jorgen Lundman | <lundman@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)
Hi! On Wednesday, 04 March 2009 at 00:42, Jorgen Lundman wrote:
Jorgen Lundman wrote:
I'm going out drinking in a bit, so rather than wait, I will just send the patches, then deal with whatever problem there may be.
This patch adds support to handle ExtendedFileInfo (TagID 262) for UDF 2.50 formats. It also includes EXTFINFO with FileType of 250, which acts as a redirect block.
This enables dvdread to handle UDF2.50 filesystems.
The patch also includes minor fix to patch1.
Thanks to Jacob Pedersen, we now know that this patch wasn't quite correct. It used the "forward block" to shift the partition, but this meant all files started offset +64KB from the start. This is not great when you try to read the certificates.
I committed a fix to this in my version where only directory listings are forwarded, and the partition (plus files) are left properly.
Could you resend the whole UDF patchset rediffed (if necessary) against current SVN? Nico, please review it when you have some time. I seem to remember that at least one patch was already OK'd by Nico. Regards, R. -- 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"
Could you resend the whole UDF patchset rediffed (if necessary) against current SVN? Nico, please review it when you have some time. I seem to remember that at least one patch was already OK'd by Nico.
I am dealing directly with Hovland to re-attempt my patches. I have sent him the first one to fix the AD chains. If that is accepted, I will do the 2nd one. Lund -- Jorgen Lundman | <lundman@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) Attached is patch "dvdread_patch_udf_file.txt". 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. UDF File: 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", 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.
On Sunday, 27 September 2009 at 01:49, Jorgen Lundman wrote:
Could you resend the whole UDF patchset rediffed (if necessary) against current SVN? Nico, please review it when you have some time. I seem to remember that at least one patch was already OK'd by Nico.
I am dealing directly with Hovland to re-attempt my patches. I have sent him the first one to fix the AD chains. If that is accepted, I will do the 2nd one.
Great! Thank you for your patience. Regards, R. -- 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"
On Sunday, 27 September 2009 at 01:49, Jorgen Lundman wrote:
Could you resend the whole UDF patchset rediffed (if necessary) against current SVN? Nico, please review it when you have some time. I seem to remember that at least one patch was already OK'd by Nico.
I am dealing directly with Hovland to re-attempt my patches. I have sent him the first one to fix the AD chains. If that is accepted, I will do the 2nd one.
Some comments below. [...]
Index: dvd_udf.c =================================================================== --- dvd_udf.c (revision 1181) +++ dvd_udf.c (working copy) @@ -40,6 +40,7 @@ #include "dvdread/dvd_reader.h" #include "dvdread/dvd_udf.h"
+ /* 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,
Cosmetics.
@@ -782,7 +807,80 @@ 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); +}
I think the wrapping of free is unnecessary here, especially when the device parameter is unused. dvd_reader.c changes would need to be adjusted accordingly as well.
+/* + * 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++) {
Ugly indentation.
+ + /* 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;
Unnecessary line breaks? Regards, R. -- 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"
+void UDFFreeFile(dvd_reader_t *device, udf_file_t *File) +{ + free(File); +}
I think the wrapping of free is unnecessary here, especially when the device parameter is unused. dvd_reader.c changes would need to be adjusted accordingly as well.
Initially the allocation of the AD chain array was dynamic, and also needed to be free()d when the file was free()d. I made it static for simplicity, but decided to keep the free call so that, should it be made back into dynamic, all memory will still be released properly assuming everyone calls the UDFFreeFile() call. Otherwise, I have no preference. Lund -- Jorgen Lundman | <lundman@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)
Removed Cosmetics, changed indentation to be "tighter" but kept Free call. -- Jorgen Lundman | <lundman@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)
Il martedì 29 settembre 2009 02:58:35 Jorgen Lundman ha scritto:
Removed Cosmetics, changed indentation to be "tighter" but kept Free call.
Thanks. This patch will need a serious testing session and a deep review. Feedback welcome.
Il martedì 29 settembre 2009 10:21:53 Nico Sabbi ha scritto:
Il martedì 29 settembre 2009 02:58:35 Jorgen Lundman ha scritto:
Removed Cosmetics, changed indentation to be "tighter" but kept Free call.
Thanks. This patch will need a serious testing session and a deep review. Feedback welcome.
BTW, a couple of titles to test the difference?
Thanks. This patch will need a serious testing session and a deep review. Feedback welcome.
How it going, any ETA yet? :) Lund -- Jorgen Lundman | <lundman@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)
Il lunedì 19 ottobre 2009 04:37:59 Jorgen Lundman ha scritto:
Thanks. This patch will need a serious testing session and a deep review. Feedback welcome.
How it going, any ETA yet? :)
Lund
will you excuse me if I tell you that i completely forgot about it? I'm really sorry!
will you excuse me if I tell you that i completely forgot about it? I'm really sorry! _______________________________________________
No worries, I'm ready with patch 2 whenever it is done. I get reminded every other week or so when people email me and ask why I haven't added my patches to your repository. Lund -- Jorgen Lundman | <lundman@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)
On Monday, 19 October 2009 at 10:28, Jorgen Lundman wrote:
will you excuse me if I tell you that i completely forgot about it? I'm really sorry! _______________________________________________
No worries, I'm ready with patch 2 whenever it is done. I get reminded every other week or so when people email me and ask why I haven't added my patches to your repository.
Nico: ping? Regards, R. -- 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"
This patch adds the VOB stat() function methods already done in libdvdread-0.9.7. Mostly to be backward compatible with other existing libdvdread users. It enables the API user to be able to get sizes of individual VOB files and combined. It also contains minor fixes to patch2. Lund -- Jorgen Lundman | <lundman@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) diff -ruib ../../../../versions/libdvdread_patch2/libdvdread/src/dvd_reader.c ./dvd_reader.c --- ../../../../versions/libdvdread_patch2/libdvdread/src/dvd_reader.c 2008-10-10 15:44:30.000000000 +0900 +++ ./dvd_reader.c 2008-10-10 17:20:20.000000000 +0900 @@ -912,6 +912,187 @@ } } +static int DVDFileStatVOBUDF(dvd_reader_t *dvd, int title, + int menu, dvd_stat_t *statbuf) +{ + char filename[ MAX_UDF_FILE_NAME_LEN ]; + uint64_t size; + off_t tot_size; + off_t parts_size[9]; + int nr_parts = 0; + int n; + UDF_FILE 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(!(udf_file = UDFFindFile( dvd, filename, &size ))) { + return -1; + } + UDFFreeFile(dvd, udf_file); + + tot_size = size; + nr_parts = 1; + parts_size[0] = size; + + if( !menu ) { + int cur; + + for( cur = 2; cur < 10; cur++ ) { + sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, cur ); + if( !(udf_file = UDFFindFile( dvd, filename, &size ) )) { + break; + } + UDFFreeFile(dvd, udf_file); + + parts_size[nr_parts] = size; + tot_size += size; + nr_parts++; + } + } + + statbuf->size = tot_size; + statbuf->nr_parts = nr_parts; + for(n = 0; n < nr_parts; n++) { + statbuf->parts_size[n] = parts_size[n]; + } + return 0; +} + +static int DVDFileStatVOBPath( dvd_reader_t *dvd, int title, + int menu, dvd_stat_t *statbuf ) +{ + char filename[ MAX_UDF_FILE_NAME_LEN ]; + char full_path[ PATH_MAX + 1 ]; + struct stat fileinfo; + off_t tot_size; + off_t parts_size[9]; + int nr_parts = 0; + int n; + + if( title == 0 ) { + sprintf( filename, "VIDEO_TS.VOB" ); + } else { + sprintf( filename, "VTS_%02d_%d.VOB", title, menu ? 0 : 1 ); + } + if( !findDVDFile( dvd, filename, full_path ) ) { + return -1; + } + + if( stat( full_path, &fileinfo ) < 0 ) { + return -1; + } + + tot_size = fileinfo.st_size; + nr_parts = 1; + parts_size[0] = fileinfo.st_size; + + if( !menu ) { + int cur; + + for( cur = 2; cur < 10; cur++ ) { + + sprintf( filename, "VTS_%02d_%d.VOB", title, cur ); + if( !findDVDFile( dvd, filename, full_path ) ) { + break; + } + + if( stat( full_path, &fileinfo ) < 0 ) { + break; + } + + parts_size[nr_parts] = fileinfo.st_size; + tot_size += parts_size[nr_parts]; + nr_parts++; + } + } + + statbuf->size = tot_size; + statbuf->nr_parts = nr_parts; + for(n = 0; n < nr_parts; n++) { + statbuf->parts_size[n] = parts_size[n]; + } + return 0; +} + + +int DVDFileStat(dvd_reader_t *dvd, int titlenum, + dvd_read_domain_t domain, dvd_stat_t *statbuf) +{ + char filename[ MAX_UDF_FILE_NAME_LEN ]; + char full_path[ PATH_MAX + 1 ]; + struct stat fileinfo; + uint64_t size; + UDF_FILE udf_file; + + /* Check arguments. */ + if( dvd == NULL || titlenum < 0 ) { + errno = EINVAL; + return -1; + } + + switch( domain ) { + case DVD_READ_INFO_FILE: + if( titlenum == 0 ) { + sprintf( filename, "/VIDEO_TS/VIDEO_TS.IFO" ); + } else { + sprintf( filename, "/VIDEO_TS/VTS_%02i_0.IFO", titlenum ); + } + break; + case DVD_READ_INFO_BACKUP_FILE: + if( titlenum == 0 ) { + sprintf( filename, "/VIDEO_TS/VIDEO_TS.BUP" ); + } else { + sprintf( filename, "/VIDEO_TS/VTS_%02i_0.BUP", titlenum ); + } + break; + case DVD_READ_MENU_VOBS: + if( dvd->isImageFile ) { + return DVDFileStatVOBUDF( dvd, titlenum, 1, statbuf ); + } else { + return DVDFileStatVOBPath( dvd, titlenum, 1, statbuf ); + } + break; + case DVD_READ_TITLE_VOBS: + if( titlenum == 0 ) { + return -1; + } + if( dvd->isImageFile ) { + return DVDFileStatVOBUDF( dvd, titlenum, 0, statbuf ); + } else { + return DVDFileStatVOBPath( dvd, titlenum, 0, statbuf ); + } + break; + default: + errno = EINVAL; + return -1; + } + + if( dvd->isImageFile ) { + 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 { + if( findDVDFile( dvd, filename, full_path ) ) { + if( stat( full_path, &fileinfo ) < 0 ) { + ; + } else { + statbuf->size = fileinfo.st_size; + statbuf->nr_parts = 1; + statbuf->parts_size[0] = statbuf->size; + return 0; + } + } + } + return -1; +} + /* Internal, but used from dvd_udf.c */ int UDFReadBlocksRaw( dvd_reader_t *device, uint32_t lb_number, size_t block_count, unsigned char *data, diff -ruib ../../../../versions/libdvdread_patch2/libdvdread/src/dvd_reader.h ./dvd_reader.h --- ../../../../versions/libdvdread_patch2/libdvdread/src/dvd_reader.h 2008-10-10 15:36:13.000000000 +0900 +++ ./dvd_reader.h 2008-10-10 17:19:36.000000000 +0900 @@ -116,6 +116,42 @@ single file. */ } dvd_read_domain_t; +/* + * DVD stat structure for getting VOB sizes + */ +typedef struct { + off_t size; /**< Total size of file in bytes */ + int nr_parts; /**< Number of file parts */ + off_t parts_size[9]; /**< Size of each part in bytes */ +} dvd_stat_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 + * which contains information about the size of the file and + * the number of parts in case of a multipart file and the respective + * sizes of the parts. + * A multipart file is for instance VTS_02_1.VOB, VTS_02_2.VOB, VTS_02_3.VOB + * The size of VTS_02_1.VOB will be stored in stat->parts_size[0], + * VTS_02_2.VOB in stat->parts_size[1], ... + * The total size (sum of all parts) is stored in stat->size and + * stat->nr_parts will hold the number of parts. + * Only DVD_READ_TITLE_VOBS (VTS_??_[1-9].VOB) can be multipart files. + * + * This function is only of use if you want to get the size of each file + * in the filesystem. These sizes are not needed to use any other + * functions in libdvdread. + * + * @param dvd A dvd read handle. + * @param titlenum Which Video Title Set should be used, VIDEO_TS is 0. + * @param domain Which domain. + * @param stat Pointer to where the result is stored. + * @return If successful 0, otherwise -1. + * + * int DVDFileStat(dvd, titlenum, domain, stat); + */ +int DVDFileStat(dvd_reader_t *, int, dvd_read_domain_t, dvd_stat_t *); + /** * Opens a file on the DVD given the title number and domain. * diff -ruib ../../../../versions/libdvdread_patch2/libdvdread/src/dvd_udf.c ./dvd_udf.c --- ../../../../versions/libdvdread_patch2/libdvdread/src/dvd_udf.c 2008-10-10 16:20:12.000000000 +0900 +++ ./dvd_udf.c 2008-10-10 17:16:50.000000000 +0900 @@ -482,7 +482,7 @@ UDFICB( &data[ 16 ], FileType, &flags ); /* Init ad for an empty file (i.e. there isn't a AD, L_AD == 0 ) */ - fad->Length = GETN4( 56 ); /* Was 4 bytes at 60, changed to 64-bit. */ + fad->Length = GETN8( 56 ); /* Was 4 bytes at 60, changed to 64-bit. */ L_EA = GETN4( 168 ); L_AD = GETN4( 172 );
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 | <lundman@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) 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,
This patch enables dvdread to be able to read .ISO files inside of a RAR archive. It does so by using popen() to spawn "unrar" executable. It is recommended it is used with the "unrar" version with "-sk<offset>" feature to allow to lseek() in the RAR archives. Lund -- Jorgen Lundman | <lundman@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) diff -ruib ../../versions/libdvdread_patch4/libdvdread/src/dvd_input.c ./dvd_input.c --- ../../versions/libdvdread_patch4/libdvdread/src/dvd_input.c 2008-10-10 14:42:23.000000000 +0900 +++ ./dvd_input.c 2008-10-10 17:40:50.000000000 +0900 @@ -25,6 +25,7 @@ #include <stdlib.h> #include <fcntl.h> #include <unistd.h> +#include <string.h> #include "dvd_reader.h" #include "dvd_input.h" @@ -37,6 +38,9 @@ int (*dvdinput_title) (dvd_input_t, int); int (*dvdinput_read) (dvd_input_t, void *, int, int); char * (*dvdinput_error) (dvd_input_t); +char * dvdinput_unrar_cmd = NULL; +char * dvdinput_unrar_file = NULL; + #ifdef HAVE_DVDCSS_DVDCSS_H /* linking to libdvdcss */ @@ -66,6 +70,9 @@ static char * (*DVDcss_error) (dvdcss_handle); #endif +/* When is it faster to respawn unrar, rather than seek by eating bytes? */ +#define MAXIMUM_SEEK_SIZE 1048576 + /* The DVDinput handle, add stuff here for new input methods. */ struct dvd_input_s { /* libdvdcss handle */ @@ -73,6 +80,13 @@ /* dummy file input */ int fd; + + /* unrar support */ + char *unrar_archive; + char *unrar_file; + FILE *unrar_stream; + off_t seek_pos; + off_t current_pos; }; @@ -364,3 +378,263 @@ return 0; } } + +/** + * initialize and open a DVD device or file in a RAR file. + */ +static dvd_input_t rarfile_open(const char *target) +{ + dvd_input_t dev; + + /* Allocate the library structure */ + dev = (dvd_input_t) malloc(sizeof(*dev)); + if(dev == NULL) { + fprintf(stderr, "libdvdread: Could not allocate memory.\n"); + return NULL; + } + + dev->unrar_stream = NULL; + dev->unrar_file = NULL; + dev->seek_pos = 0; /* Assume start of file */ + dev->current_pos = 0; + + /* This is kind of sad, to use setupRAR to pass the rarfile name, then + * hope that dvdinput_open is called after. We could also do some sort + * of filename separator parsing perhaps. */ + + /* Allocated in setupRAR, move it over. */ + dev->unrar_archive = dvdinput_unrar_file; + dvdinput_unrar_file = NULL; + + /* The filename inside the RAR archive to operate on */ + dev->unrar_file = strdup(target); + + /* Lets call unrar, to list the release, as a way to quickly check that + * all the volumes are present, and the unrar_cmd works? */ + + return dev; +} + + +/** + * return the last error message + */ +static char *rarfile_error(dvd_input_t dev) +{ + /* use strerror(errno)? */ + return (char *)"unknown error"; +} + +/** + * seek into the device. + */ +static int rarfile_seek(dvd_input_t dev, int blocks) +{ + + dev->seek_pos = (off_t)blocks * (off_t)DVD_VIDEO_LB_LEN; + + /* assert pos % DVD_VIDEO_LB_LEN == 0 */ + return (int) (dev->seek_pos / DVD_VIDEO_LB_LEN); +} + +/** + * set the block for the begining of a new title (key). + */ +static int rarfile_title(dvd_input_t dev, int block) +{ + return -1; +} + +/** + * read data from the device. + */ +static int rarfile_read(dvd_input_t dev, void *buffer, int blocks, int flags) +{ + size_t len, read_size; + char ibuffer[DVD_VIDEO_LB_LEN]; + int ret; + + /* First, position ourselves where the API wants us. This may mean + * spawning new unrar, or possibly eating data until the correct + * position. */ + + /* We already have a stream, here, we can be exactly at the right place, + * or, need to eat data until the correct position, or + * if the seek is too far, close this unrar, and spawn a new. + */ + if (dev->unrar_stream) { + + /* eat data? */ + if (dev->seek_pos > dev->current_pos) { + + /* Seek too far? Better to spawn new unrar? */ + if ((dev->seek_pos - dev->current_pos) >= MAXIMUM_SEEK_SIZE) { +#ifdef DEBUG + fprintf(stderr, "libdvdread: seek too large, re-spawning unrar\r\n"); +#endif + pclose(dev->unrar_stream); + dev->unrar_stream = NULL; + + } else { + /* Not too far, read and eat bytes. */ + while (dev->seek_pos > dev->current_pos) { + + /* Work out how much we need to read, but no larger than + * the size of our buffer.*/ + + read_size = dev->seek_pos - dev->current_pos; + if (read_size > sizeof(ibuffer)) + read_size = sizeof(ibuffer); + + if ((fread(ibuffer, read_size, 1, dev->unrar_stream)) != 1) { + /* Something failed, lets close, and let's try respawn */ + pclose(dev->unrar_stream); + dev->unrar_stream = NULL; + break; + } + dev->current_pos += read_size; + } /* while seek > current */ + } /* NOT >= max seek */ + } /* NOT seek > current */ + + /* Also check if seek < current, then we must restart unrar */ + if (dev->seek_pos < dev->current_pos) { + pclose(dev->unrar_stream); + dev->unrar_stream = NULL; + } + + } /* we have active stream */ + + /* Spawn new unrar? */ + if (!dev->unrar_stream) { + snprintf(ibuffer, sizeof(ibuffer), + "%s p -inul -c- -p- -y -cfg- -sk%"PRIu64" -- \"%s\" \"%s\"", + dvdinput_unrar_cmd, + dev->seek_pos, + dev->unrar_archive, + dev->unrar_file ); + +#ifdef DEBUG + fprintf(stderr, "libdvdvread: spawning '%s'\r\n", ibuffer); +#endif + + dev->unrar_stream = popen(ibuffer, +#ifdef WIN32 + "rb" +#else + "r" /* It is an error to send "b" in Unix :( */ +#endif + ); + + if (!dev->unrar_stream) { + return -1; + } + + /* Update ptr */ + dev->current_pos = dev->seek_pos; + + } + + /* Assert current == seek ? */ +#ifdef DEBUG + if (dev->current_pos != dev->seek_pos) + fprintf(stderr, "libdvdread: somehow, current_pos != seek_pos!?\r\n"); +#endif + + len = (size_t)blocks * DVD_VIDEO_LB_LEN; + + while(len > 0) { + + /* ret = read(dev->fd, buffer, len); */ + ret = fread(buffer, 1, len, dev->unrar_stream); + + if((ret != len) && ferror(dev->unrar_stream)) { + /* One of the reads failed, too bad. We won't even bother + * returning the reads that went ok, and as in the posix spec + * the file postition is left unspecified after a failure. */ + return -1; + } + + if (ret < 0) + return -1; + + if ((ret != len) || feof(dev->unrar_stream)) { + /* Nothing more to read. Return the whole blocks, if any, + * that we got. and adjust the file position back to the + * previous block boundary. */ + size_t bytes = (size_t)blocks * DVD_VIDEO_LB_LEN - len; /* 'ret'? */ + off_t over_read = -(bytes % DVD_VIDEO_LB_LEN); + /*off_t pos =*/ /*lseek(dev->fd, over_read, SEEK_CUR);*/ + dev->current_pos += (off_t)len; + dev->seek_pos = dev->current_pos + (off_t)len + over_read; + /* minus over_read, I did not touch the code above, but I wonder + * if it is correct. It does not even use "ret" in the math. */ + + /* should have pos % 2048 == 0 */ + return (int) (bytes / DVD_VIDEO_LB_LEN); + } + + dev->current_pos += (off_t) ret; + dev->seek_pos += (off_t) ret; + len -= ret; + } + + return blocks; +} + + +/** + * close the DVD device and clean up. + */ +static int rarfile_close(dvd_input_t dev) +{ + + if (dev->unrar_stream) + pclose(dev->unrar_stream); + dev->unrar_stream = NULL; + + if (dev->unrar_archive) + free(dev->unrar_archive); + dev->unrar_archive = NULL; + + if (dev->unrar_file) + free(dev->unrar_file); + dev->unrar_file = NULL; + + free(dev); + + return 0; +} + + + +int dvdinput_setupRAR(const char *unrar_path, const char *rarfile) +{ + +#ifdef DEBUG + fprintf(stderr, "libdvdread: Configuring for unrar.\n"); +#endif + /* Search for unrar in $PATH, common places etc, as well as "unrar_path" + * + * But we really need unrar with special SEEK -sk option for this to work + * + * If you want this to work on Windows, you have to use internal popen() + * functions, as Windows popen() does not work correctly. + * Please see: http://www.lundman.net/win32_popen.c + */ + + dvdinput_unrar_cmd = strdup(unrar_path); + dvdinput_unrar_file = strdup(rarfile); + + /* Check it is present, and executable? */ + + /* libdvdcss replacement functions */ + dvdinput_open = rarfile_open; + dvdinput_close = rarfile_close; + dvdinput_seek = rarfile_seek; + dvdinput_title = rarfile_title; + dvdinput_read = rarfile_read; + dvdinput_error = rarfile_error; + + return 0; +} diff -ruib ../../versions/libdvdread_patch4/libdvdread/src/dvd_input.h ./dvd_input.h --- ../../versions/libdvdread_patch4/libdvdread/src/dvd_input.h 2008-10-10 14:42:23.000000000 +0900 +++ ./dvd_input.h 2008-10-10 17:38:40.000000000 +0900 @@ -46,5 +46,6 @@ * Setup function accessed by dvd_reader.c. Returns 1 if there is CSS support. */ int dvdinput_setup(void); +int dvdinput_setupRAR(const char *, const char *); #endif /* LIBDVDREAD_DVD_INPUT_H */ diff -ruib ../../versions/libdvdread_patch4/libdvdread/src/dvd_reader.c ./dvd_reader.c --- ../../versions/libdvdread_patch4/libdvdread/src/dvd_reader.c 2008-10-10 17:32:13.000000000 +0900 +++ ./dvd_reader.c 2008-10-10 17:37:45.000000000 +0900 @@ -273,6 +273,42 @@ return dvd; } +/* + * Open a image inside a rar. Takes extra filepath argument to the rar archive + */ +dvd_reader_t *DVDOpenRARImageFile( const char *unrar_cmd, + const char *rarfile, + const char *location ) +{ + dvd_reader_t *dvd; + dvd_input_t dev; + + dvdinput_setupRAR(unrar_cmd, rarfile); + + dev = dvdinput_open( location ); + if( !dev ) { + fprintf( stderr, "libdvdread: Can't openRAR %s:%s for reading\n", + rarfile, location); + return NULL; + } + + dvd = (dvd_reader_t *) malloc( sizeof( dvd_reader_t ) ); + if( !dvd ) { + dvdinput_close(dev); + return NULL; + } + dvd->isImageFile = 1; + dvd->dev = dev; + dvd->path_root = NULL; + + dvd->udfcache_level = DEFAULT_UDF_CACHE_LEVEL; + dvd->udfcache = NULL; + + dvd->css_title = 0; + + return dvd; +} + static dvd_reader_t *DVDOpenPath( const char *path_root ) { dvd_reader_t *dvd; diff -ruib ../../versions/libdvdread_patch4/libdvdread/src/dvd_reader.h ./dvd_reader.h --- ../../versions/libdvdread_patch4/libdvdread/src/dvd_reader.h 2008-10-10 17:23:46.000000000 +0900 +++ ./dvd_reader.h 2008-10-10 17:38:17.000000000 +0900 @@ -104,6 +104,17 @@ */ void DVDClose( dvd_reader_t * ); + +/* + * Open an ImageFile contained in a RAR archive volume. This API call should + * probably be cleaned up. + * @lundman: 20080817 + */ +dvd_reader_t *DVDOpenRARImageFile( const char *unrar_cmd, + const char *rarfile, + const char *location ); + + /** * */
On Friday 10 October 2008 10:59:17 Jorgen Lundman wrote:
This patch enables dvdread to be able to read .ISO files inside of a RAR archive. It does so by using popen() to spawn "unrar" executable. It is recommended it is used with the "unrar" version with "-sk<offset>" feature to allow to lseek() in the RAR archives.
Lund
as I already wrote I don't think that complicating the library for a feature that belongs to a different layer is a good idea. No go
as I already wrote I don't think that complicating the library for a feature that belongs to a different layer is a good idea. No go
Yes I agree. What really should happen is to make API calls for dvd_input where the upper layer can register the 5 functions to be called. I would argue this would include registering the 5 dvdcss_* calls as well, and remove dvdcss from dvdread :) Lund -- Jorgen Lundman | <lundman@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)
Jorgen Lundman skrev:
as I already wrote I don't think that complicating the library for a feature that belongs to a different layer is a good idea. No go
Yes I agree. What really should happen is to make API calls for dvd_input where the upper layer can register the 5 functions to be called. I would argue this would include registering the 5 dvdcss_* calls as well, and remove dvdcss from dvdread :)
Makes perfect sense to me. Though, I believe you need opendir and friends too.
On Friday 10 October 2008 09:15:24 Jorgen Lundman wrote:
Attached patch for removing the hacky overload of "struct AD" which is also used for File operations, resulting in 64-bit to 32-bit conversions and more.
Additionally, libdvdread assumed all blocks fit inside one AD chain, in contiguous order, which is generally true for all DVDs. (Since files are limited to 1GB in size). I have extended this to correctly handle the UDF AD chaining as the ECMA_167 specifications detail.
All 32-bit filesize references have been changed to 64-bit.
UDFFindFile() no longer return a "block number" but a reference to a "UDF_FILE". This should be freed by calling UDFFileFree(). All calls from dvd_reader.c have been updated.
An additional function UDFFileBlockPos() has added to translate between a file's block offset, into correct disk block. (Walking the AD chains to find correct block, as well as, File start block and partition block number).
Tested only against title_info.c since I need all patches for complete testing.
this patch is mostly fine (but still untested) but there are a lot of cosmetics at the end (the switch loop and something else)
I can't get svn diff to let me specify a local-changed source to use when diffing instead of your svn, so I will have to use normal "diff" to produce further patches. Any particular options beyond "-run" you prefer? Lund -- Jorgen Lundman | <lundman@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)
participants (6)
-
Andreas Öman -
Diego Biurrun -
Dominik 'Rathann' Mierzejewski -
John Stebbins -
Jorgen Lundman -
Nico Sabbi