diff options
author | aurel <aurel@b3059339-0415-0410-9bf9-f77b7e298cf2> | 2005-06-30 22:48:26 +0000 |
---|---|---|
committer | aurel <aurel@b3059339-0415-0410-9bf9-f77b7e298cf2> | 2005-06-30 22:48:26 +0000 |
commit | eb3c1b5cedfc1b7d35a2d261780979b00170946e (patch) | |
tree | ccc33eb81679684b7f2ca3d7c610d721375c4ea5 /libmpdvdkit2/dvd_udf.c | |
parent | c8fbf4405d7b433f0dc622bc9dcf81d0ceb5ef36 (diff) | |
download | mpv-eb3c1b5cedfc1b7d35a2d261780979b00170946e.tar.bz2 mpv-eb3c1b5cedfc1b7d35a2d261780979b00170946e.tar.xz |
update libdvdread to v0.9.4
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@15875 b3059339-0415-0410-9bf9-f77b7e298cf2
Diffstat (limited to 'libmpdvdkit2/dvd_udf.c')
-rw-r--r-- | libmpdvdkit2/dvd_udf.c | 369 |
1 files changed, 362 insertions, 7 deletions
diff --git a/libmpdvdkit2/dvd_udf.c b/libmpdvdkit2/dvd_udf.c index a01aba790a..f2144451ee 100644 --- a/libmpdvdkit2/dvd_udf.c +++ b/libmpdvdkit2/dvd_udf.c @@ -5,8 +5,6 @@ * Modifications by: * Billy Biggs <vektor@dumbterm.net>. * Björn Englund <d4bjorn@dtek.chalmers.se>. - * Joey Parrish <joey@nicewarrior.org>. - * - updated from libdvdread 0.9.4 and removed udf caching * * Modified for use with MPlayer, changes contained in libdvdread_changes.diff. * detailed CVS changelog at http://www.mplayerhq.hu/cgi-bin/cvsweb.cgi/main/ @@ -34,10 +32,11 @@ * http://www.gnu.org/copyleft/gpl.html */ +#include "config.h" + #include <stdio.h> #include <stdlib.h> #include <string.h> -//#include <assert.h> #ifndef __MINGW32__ #include <sys/ioctl.h> #endif @@ -50,7 +49,7 @@ #include "dvd_udf.h" /* Private but located in/shared with dvd_reader.c */ -extern int DVDReadBlocksUDFRaw( dvd_reader_t *device, uint32_t lb_number, +extern int UDFReadBlocksRaw( dvd_reader_t *device, uint32_t lb_number, size_t block_count, unsigned char *data, int encrypted ); @@ -64,7 +63,7 @@ static int DVDReadLBUDF( dvd_reader_t *device, uint32_t lb_number, while(count > 0) { - ret = DVDReadBlocksUDFRaw(device, lb_number, count, data, encrypted); + ret = UDFReadBlocksRaw(device, lb_number, count, data, encrypted); if(ret <= 0) { /* One of the reads failed or nothing more to read, too bad. @@ -128,6 +127,201 @@ struct icbmap { uint8_t filetype; }; +struct udf_cache { + int avdp_valid; + struct avdp_t avdp; + int pvd_valid; + struct pvd_t pvd; + int partition_valid; + struct Partition partition; + int rooticb_valid; + struct AD rooticb; + int lb_num; + struct lbudf *lbs; + int map_num; + struct icbmap *maps; +}; + +typedef enum { + PartitionCache, RootICBCache, LBUDFCache, MapCache, AVDPCache, PVDCache +} UDFCacheType; + +extern void *GetUDFCacheHandle(dvd_reader_t *device); +extern void SetUDFCacheHandle(dvd_reader_t *device, void *cache); + +void FreeUDFCache(void *cache) +{ + struct udf_cache *c = (struct udf_cache *)cache; + if(c == NULL) { + return; + } + if(c->lbs) { + free(c->lbs); + } + if(c->maps) { + free(c->maps); + } + free(c); +} + + +static int GetUDFCache(dvd_reader_t *device, UDFCacheType type, + uint32_t nr, void *data) +{ + int n; + struct udf_cache *c; + + if(DVDUDFCacheLevel(device, -1) <= 0) { + return 0; + } + + c = (struct udf_cache *)GetUDFCacheHandle(device); + + if(c == NULL) { + return 0; + } + + switch(type) { + case AVDPCache: + if(c->avdp_valid) { + *(struct avdp_t *)data = c->avdp; + return 1; + } + break; + case PVDCache: + if(c->pvd_valid) { + *(struct pvd_t *)data = c->pvd; + return 1; + } + break; + case PartitionCache: + if(c->partition_valid) { + *(struct Partition *)data = c->partition; + return 1; + } + break; + case RootICBCache: + if(c->rooticb_valid) { + *(struct AD *)data = c->rooticb; + return 1; + } + break; + case LBUDFCache: + for(n = 0; n < c->lb_num; n++) { + if(c->lbs[n].lb == nr) { + *(uint8_t **)data = c->lbs[n].data; + return 1; + } + } + break; + case MapCache: + for(n = 0; n < c->map_num; n++) { + if(c->maps[n].lbn == nr) { + *(struct icbmap *)data = c->maps[n]; + return 1; + } + } + break; + default: + break; + } + + return 0; +} + +static int SetUDFCache(dvd_reader_t *device, UDFCacheType type, + uint32_t nr, void *data) +{ + int n; + struct udf_cache *c; + + if(DVDUDFCacheLevel(device, -1) <= 0) { + return 0; + } + + c = (struct udf_cache *)GetUDFCacheHandle(device); + + if(c == NULL) { + c = calloc(1, sizeof(struct udf_cache)); + // fprintf(stderr, "calloc: %d\n", sizeof(struct udf_cache)); + if(c == NULL) { + return 0; + } + SetUDFCacheHandle(device, c); + } + + + switch(type) { + case AVDPCache: + c->avdp = *(struct avdp_t *)data; + c->avdp_valid = 1; + break; + case PVDCache: + c->pvd = *(struct pvd_t *)data; + c->pvd_valid = 1; + break; + case PartitionCache: + c->partition = *(struct Partition *)data; + c->partition_valid = 1; + break; + case RootICBCache: + c->rooticb = *(struct AD *)data; + c->rooticb_valid = 1; + break; + case LBUDFCache: + for(n = 0; n < c->lb_num; n++) { + if(c->lbs[n].lb == nr) { + /* replace with new data */ + c->lbs[n].data = *(uint8_t **)data; + c->lbs[n].lb = nr; + return 1; + } + } + c->lb_num++; + c->lbs = realloc(c->lbs, c->lb_num * sizeof(struct lbudf)); + /* + fprintf(stderr, "realloc lb: %d * %d = %d\n", + c->lb_num, sizeof(struct lbudf), + c->lb_num * sizeof(struct lbudf)); + */ + if(c->lbs == NULL) { + c->lb_num = 0; + return 0; + } + c->lbs[n].data = *(uint8_t **)data; + c->lbs[n].lb = nr; + break; + case MapCache: + for(n = 0; n < c->map_num; n++) { + if(c->maps[n].lbn == nr) { + /* replace with new data */ + c->maps[n] = *(struct icbmap *)data; + c->maps[n].lbn = nr; + return 1; + } + } + c->map_num++; + c->maps = realloc(c->maps, c->map_num * sizeof(struct icbmap)); + /* + fprintf(stderr, "realloc maps: %d * %d = %d\n", + c->map_num, sizeof(struct icbmap), + c->map_num * sizeof(struct icbmap)); + */ + if(c->maps == NULL) { + c->map_num = 0; + return 0; + } + c->maps[n] = *(struct icbmap *)data; + c->maps[n].lbn = nr; + break; + default: + return 0; + } + + return 1; +} + + /* For direct data access, LSB first */ #define GETN1(p) ((uint8_t)data[p]) #define GETN2(p) ((uint16_t)data[p] | ((uint16_t)data[(p) + 1] << 8)) @@ -302,8 +496,16 @@ static int UDFMapICB( dvd_reader_t *device, struct AD ICB, uint8_t *FileType, uint8_t LogBlock[DVD_VIDEO_LB_LEN]; uint32_t lbnum; uint16_t TagID; + struct icbmap tmpmap; lbnum = partition->Start + ICB.Location; + tmpmap.lbn = lbnum; + if(GetUDFCache(device, MapCache, lbnum, &tmpmap)) { + *FileType = tmpmap.filetype; + *File = tmpmap.file; + return 1; + } + do { if( DVDReadLBUDF( device, lbnum++, 1, LogBlock, 0 ) <= 0 ) { TagID = 0; @@ -313,6 +515,9 @@ static int UDFMapICB( dvd_reader_t *device, struct AD ICB, uint8_t *FileType, if( TagID == 261 ) { UDFFileEntry( LogBlock, FileType, partition, File ); + tmpmap.file = *File; + tmpmap.filetype = *FileType; + SetUDFCache(device, MapCache, tmpmap.lbn, &tmpmap); return 1; }; } while( ( lbnum <= partition->Start + ICB.Location + ( ICB.Length - 1 ) @@ -328,7 +533,8 @@ static int UDFMapICB( dvd_reader_t *device, struct AD ICB, uint8_t *FileType, * return 1 on success, 0 on error; */ static int UDFScanDir( dvd_reader_t *device, struct AD Dir, char *FileName, - struct Partition *partition, struct AD *FileICB ) + struct Partition *partition, struct AD *FileICB, + int cache_file_info) { char filename[ MAX_UDF_FILE_NAME_LEN ]; uint8_t directory[ 2 * DVD_VIDEO_LB_LEN ]; @@ -336,9 +542,78 @@ static int UDFScanDir( dvd_reader_t *device, struct AD Dir, char *FileName, uint16_t TagID; uint8_t filechar; unsigned int p; + uint8_t *cached_dir = NULL; + uint32_t dir_lba; + struct AD tmpICB; + int found = 0; + int in_cache = 0; /* Scan dir for ICB of file */ lbnum = partition->Start + Dir.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; + if((cached_dir = malloc(dir_lba * DVD_VIDEO_LB_LEN)) == NULL) { + return 0; + } + if( DVDReadLBUDF( device, lbnum, dir_lba, cached_dir, 0) <= 0 ) { + free(cached_dir); + cached_dir = NULL; + } + /* + if(cached_dir) { + fprintf(stderr, "malloc dir: %d\n", + dir_lba * DVD_VIDEO_LB_LEN); + } + */ + SetUDFCache(device, LBUDFCache, lbnum, &cached_dir); + } else { + in_cache = 1; + } + + if(cached_dir == NULL) { + return 0; + } + + p = 0; + + while( p < Dir.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; + + if( !strcasecmp( FileName, filename ) ) { + *FileICB = tmpICB; + found = 1; + + } + UDFMapICB(device, tmpICB, &tmpFiletype, + partition, &tmpFile); + } else { + if( !strcasecmp( FileName, filename ) ) { + *FileICB = tmpICB; + return 1; + } + } + } else { + if(cache_file_info && (!in_cache) && found) { + return 1; + } + return 0; + } + } + if(cache_file_info && (!in_cache) && found) { + return 1; + } + return 0; + } if( DVDReadLBUDF( device, lbnum, 2, directory, 0 ) <= 0 ) { return 0; @@ -380,6 +655,10 @@ static int UDFGetAVDP( dvd_reader_t *device, int terminate; struct avdp_t; + if(GetUDFCache(device, AVDPCache, 0, avdp)) { + return 1; + } + /* Find Anchor */ lastsector = 0; lbnum = 256; /* Try #1, prime anchor */ @@ -427,6 +706,8 @@ static int UDFGetAVDP( dvd_reader_t *device, avdp->rvds.location = MVDS_location; avdp->rvds.length = MVDS_length; + SetUDFCache(device, AVDPCache, 0, avdp); + return 1; } @@ -514,8 +795,11 @@ uint32_t UDFFindFile( dvd_reader_t *device, char *filename, strcat( tokenline, filename ); + if(!(GetUDFCache(device, PartitionCache, 0, &partition) && + GetUDFCache(device, RootICBCache, 0, &RootICB))) { /* Find partition, 0 is the standard location for DVD Video.*/ if( !UDFFindPartition( device, 0, &partition ) ) return 0; + SetUDFCache(device, PartitionCache, 0, &partition); /* Find root dir ICB */ lbnum = partition.Start; @@ -536,23 +820,30 @@ uint32_t UDFFindFile( dvd_reader_t *device, char *filename, /* Sanity checks. */ if( TagID != 256 ) return 0; if( RootICB.Partition != 0 ) return 0; + SetUDFCache(device, RootICBCache, 0, &RootICB); + } /* Find root dir */ if( !UDFMapICB( device, RootICB, &filetype, &partition, &File ) ) return 0; if( filetype != 4 ) return 0; /* Root dir should be dir */ { + int cache_file_info = 0; /* Tokenize filepath */ token = strtok(tokenline, "/"); while( token != NULL ) { - if( !UDFScanDir( device, File, token, &partition, &ICB)) { + if( !UDFScanDir( device, File, token, &partition, &ICB, + cache_file_info)) { return 0; } if( !UDFMapICB( device, ICB, &filetype, &partition, &File ) ) { return 0; } + if(!strcmp(token, "VIDEO_TS")) { + cache_file_info = 1; + } token = strtok( NULL, "/" ); } } @@ -636,12 +927,76 @@ static int UDFGetPVD(dvd_reader_t *device, struct pvd_t *pvd) { uint8_t pvd_buf[DVD_VIDEO_LB_LEN]; + if(GetUDFCache(device, PVDCache, 0, pvd)) { + return 1; + } + if(!UDFGetDescriptor( device, 1, pvd_buf, sizeof(pvd_buf))) { return 0; } memcpy(pvd->VolumeIdentifier, &pvd_buf[24], 32); memcpy(pvd->VolumeSetIdentifier, &pvd_buf[72], 128); + SetUDFCache(device, PVDCache, 0, pvd); return 1; } + +/** + * Gets the Volume Identifier string, in 8bit unicode (latin-1) + * volid, place to put the string + * volid_size, size of the buffer volid points to + * returns the size of buffer needed for all data + */ +int UDFGetVolumeIdentifier(dvd_reader_t *device, char *volid, + unsigned int volid_size) +{ + struct pvd_t pvd; + unsigned int volid_len; + + /* get primary volume descriptor */ + if(!UDFGetPVD(device, &pvd)) { + return 0; + } + + volid_len = pvd.VolumeIdentifier[31]; + if(volid_len > 31) { + /* this field is only 32 bytes something is wrong */ + volid_len = 31; + } + if(volid_size > volid_len) { + volid_size = volid_len; + } + Unicodedecode(pvd.VolumeIdentifier, volid_size, volid); + + return volid_len; +} + +/** + * Gets the Volume Set Identifier, as a 128-byte dstring (not decoded) + * WARNING This is not a null terminated string + * volsetid, place to put the data + * volsetid_size, size of the buffer volsetid points to + * the buffer should be >=128 bytes to store the whole volumesetidentifier + * returns the size of the available volsetid information (128) + * or 0 on error + */ +int UDFGetVolumeSetIdentifier(dvd_reader_t *device, uint8_t *volsetid, + unsigned int volsetid_size) +{ + struct pvd_t pvd; + + /* get primary volume descriptor */ + if(!UDFGetPVD(device, &pvd)) { + return 0; + } + + + if(volsetid_size > 128) { + volsetid_size = 128; + } + + memcpy(volsetid, pvd.VolumeSetIdentifier, volsetid_size); + + return 128; +} |