2 * Copyright (C) 2010 Team Boxee
5 * Copyright (C) 2010-2013 Team XBMC
8 * This Program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
13 * This Program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with XBMC; see the file COPYING. If not, see
20 * <http://www.gnu.org/licenses/>.
22 * Note: parts of this code comes from libdvdread.
23 * Jorgen Lundman and team boxee did the necessary modifications to support udf 2.5
30 #include "utils/log.h"
34 /* For direct data access, LSB first */
35 #define GETN1(p) ((uint8_t)data[p])
36 #define GETN2(p) ((uint16_t)data[p] | ((uint16_t)data[(p) + 1] << 8))
37 #define GETN3(p) ((uint32_t)data[p] | ((uint32_t)data[(p) + 1] << 8) \
38 | ((uint32_t)data[(p) + 2] << 16))
39 #define GETN4(p) ((uint32_t)data[p] \
40 | ((uint32_t)data[(p) + 1] << 8) \
41 | ((uint32_t)data[(p) + 2] << 16) \
42 | ((uint32_t)data[(p) + 3] << 24))
43 #define GETN8(p) ((uint64_t)data[p] \
44 | ((uint64_t)data[(p) + 1] << 8) \
45 | ((uint64_t)data[(p) + 2] << 16) \
46 | ((uint64_t)data[(p) + 3] << 24) \
47 | ((uint64_t)data[(p) + 4] << 32) \
48 | ((uint64_t)data[(p) + 5] << 40) \
49 | ((uint64_t)data[(p) + 6] << 48) \
50 | ((uint64_t)data[(p) + 7] << 56))
52 /* This is wrong with regard to endianess */
53 #define GETN(p, n, target) memcpy(target, &data[p], n)
55 using namespace XFILE;
57 static int Unicodedecode( uint8_t *data, int len, char *target )
61 if( ( data[ 0 ] == 8 ) || ( data[ 0 ] == 16 ) ) do {
62 if( data[ 0 ] == 16 ) p++; /* Ignore MSB of unicode16 */
64 target[ i++ ] = data[ p++ ];
72 static int UDFExtentAD( uint8_t *data, uint32_t *Length, uint32_t *Location )
79 static int UDFShortAD( uint8_t *data, struct AD *ad )
81 ad->Length = GETN4(0);
82 ad->Flags = ad->Length >> 30;
83 ad->Length &= 0x3FFFFFFF;
84 ad->Location = GETN4(4);
88 static int UDFLongAD( uint8_t *data, struct AD *ad )
90 ad->Length = GETN4(0);
91 ad->Flags = ad->Length >> 30;
92 ad->Length &= 0x3FFFFFFF;
93 ad->Location = GETN4(4);
94 ad->Partition = GETN2(8);
95 /* GETN(10, 6, Use); */
99 static int UDFExtAD( uint8_t *data, struct AD *ad )
101 ad->Length = GETN4(0);
102 ad->Flags = ad->Length >> 30;
103 ad->Length &= 0x3FFFFFFF;
104 ad->Location = GETN4(12);
105 ad->Partition = GETN2(16);
106 /* GETN(10, 6, Use); */
110 static int UDFAD( uint8_t *ptr, uint32_t len, struct FileAD *fad)
114 if (fad->num_AD >= UDF_MAX_AD_CHAINS)
117 ad = &fad->AD_chain[fad->num_AD];
118 ad->Partition = fad->Partition;
122 switch( fad->Flags & 0x0007 ) {
124 UDFShortAD( ptr, ad );
127 UDFLongAD( ptr, ad );
135 UDFShortAD( ptr, ad );
138 UDFLongAD( ptr, ad );
152 static int UDFICB( uint8_t *data, uint8_t *FileType, uint16_t *Flags )
154 *FileType = GETN1(11);
159 static int UDFPartition( uint8_t *data, uint16_t *Flags, uint16_t *Number,
160 char *Contents, uint32_t *Start, uint32_t *Length )
164 GETN(24, 32, Contents);
166 *Length = GETN4(192);
170 static int UDFLogVolume( uint8_t *data, char *VolumeDescriptor )
173 Unicodedecode(&data[84], 128, VolumeDescriptor);
174 lbsize = GETN4(212); /* should be 2048 */
175 if (lbsize != DVD_VIDEO_LB_LEN) return 1;
179 static int UDFAdEntry( uint8_t *data, struct FileAD *fad )
186 while( p < 24 + L_AD ) {
187 p += UDFAD( &data[ p ], L_AD, fad );
192 static int UDFExtFileEntry( uint8_t *data, struct FileAD *fad )
197 UDFICB( &data[ 16 ], &fad->Type, &fad->Flags );
199 /* Init ad for an empty file (i.e. there isn't a AD, L_AD == 0 ) */
200 fad->Length = GETN8(56); // 64-bit.
206 while( p < 216 + L_EA + L_AD ) {
207 p += UDFAD( &data[ p ], L_AD, fad );
214 * The differences in ExtFile are indicated below:
215 * struct extfile_entry {
216 * struct desc_tag tag;
217 * struct icb_tag icbtag;
222 * uint8_t rec_format;
223 * uint8_t rec_disp_attr;
226 * uint64_t obj_size; // NEW
227 * uint64_t logblks_rec;
228 * struct timestamp atime;
229 * struct timestamp mtime;
230 * struct timestamp ctime; // NEW
231 * struct timestamp attrtime;
233 * uint32_t reserved1; // NEW
234 * struct long_ad ex_attr_icb;
235 * struct long_ad streamdir_icb; // NEW
236 * struct regid imp_id;
237 * uint64_t unique_id;
243 * So old "l_ea" is now +216
248 static int UDFFileEntry( uint8_t *data, struct FileAD *fad )
253 UDFICB( &data[ 16 ], &fad->Type, &fad->Flags );
255 fad->Length = GETN8( 56 ); /* Was 4 bytes at 60, changed for 64bit. */
260 if (176 + L_EA + L_AD > DVD_VIDEO_LB_LEN)
265 while( p < 176 + L_EA + L_AD ) {
266 p += UDFAD( &data[ p ], L_AD, fad );
271 uint32_t UDFFilePos(struct FileAD *File, uint64_t pos, uint64_t *res)
275 for (i = 0; i < File->num_AD; i++) {
277 if (pos < File->AD_chain[i].Length)
280 pos -= File->AD_chain[i].Length;
283 if (i == File->num_AD)
286 *res = (uint64_t)(File->Partition_Start + File->AD_chain[i].Location) * DVD_VIDEO_LB_LEN + pos;
287 return File->AD_chain[i].Length - (uint32_t)pos;
290 uint32_t UDFFileBlockPos(struct FileAD *File, uint32_t lb)
294 rem = UDFFilePos(File, lb * DVD_VIDEO_LB_LEN, &res);
296 return (uint32_t)(res / DVD_VIDEO_LB_LEN);
301 static int UDFFileIdentifier( uint8_t *data, uint8_t *FileCharacteristics,
302 char *FileName, struct AD *FileICB )
307 *FileCharacteristics = GETN1(18);
309 UDFLongAD(&data[20], FileICB);
311 if (L_FI) Unicodedecode(&data[38 + L_IU], L_FI, FileName);
312 else FileName[0] = '\0';
313 return 4 * ((38 + L_FI + L_IU + 3) / 4);
316 static int UDFDescriptor( uint8_t *data, uint16_t *TagID )
319 /* TODO: check CRC 'n stuff */
323 int udf25::UDFScanDirX( udf_dir_t *dirp )
325 char filename[ MAX_UDF_FILE_NAME_LEN ];
326 uint8_t directory_base[ 2 * DVD_VIDEO_LB_LEN + 2048];
327 uint8_t *directory = (uint8_t *)(((uintptr_t)directory_base & ~((uintptr_t)2047)) + 2048);
334 struct Partition partition;
336 if(!(GetUDFCache(PartitionCache, 0, &partition))) {
337 if(!UDFFindPartition(0, &partition))
341 /* Scan dir for ICB of file */
342 lbnum = dirp->dir_current;
344 // I have cut out the caching part of the original UDFScanDir() function
345 // one day we should probably bring it back.
346 memset(&File, 0, sizeof(File));
348 if( DVDReadLBUDF( lbnum, 2, directory, 0 ) <= 0 ) {
354 while( p < dirp->dir_length ) {
355 if( p > DVD_VIDEO_LB_LEN ) {
357 p -= DVD_VIDEO_LB_LEN;
359 //Dir.Length -= DVD_VIDEO_LB_LEN;
360 if (dirp->dir_length >= DVD_VIDEO_LB_LEN)
361 dirp->dir_length -= DVD_VIDEO_LB_LEN;
363 dirp->dir_length = 0;
365 if( DVDReadLBUDF( lbnum, 2, directory, 0 ) <= 0 ) {
369 UDFDescriptor( &directory[ p ], &TagID );
373 p += UDFFileIdentifier( &directory[ p ], &filechar,
374 filename, &FileICB );
377 dirp->dir_current = lbnum;
379 if (!*filename) // No filename, simulate "." dirname
380 strcpy((char *)dirp->entry.d_name, ".");
382 // Bah, MSVC don't have strlcpy()
383 strncpy((char *)dirp->entry.d_name, filename,
384 sizeof(dirp->entry.d_name)-1);
385 dirp->entry.d_name[ sizeof(dirp->entry.d_name) - 1 ] = 0;
389 // Look up the Filedata
390 if( !UDFMapICB( FileICB, &partition, &File))
393 dirp->entry.d_type = DVD_DT_DIR;
395 dirp->entry.d_type = DVD_DT_REG; // Add more types?
397 dirp->entry.d_filesize = File.Length;
410 int udf25::SetUDFCache(UDFCacheType type, uint32_t nr, void *data)
416 if(DVDUDFCacheLevel(-1) <= 0)
419 c = (struct udf_cache *)GetUDFCacheHandle();
422 c = (struct udf_cache *)calloc(1, sizeof(struct udf_cache));
423 /* fprintf(stderr, "calloc: %d\n", sizeof(struct udf_cache)); */
426 SetUDFCacheHandle(c);
432 c->avdp = *(struct avdp_t *)data;
436 c->pvd = *(struct pvd_t *)data;
440 c->partition = *(struct Partition *)data;
441 c->partition_valid = 1;
444 c->rooticb = *(struct AD *)data;
445 c->rooticb_valid = 1;
448 for(n = 0; n < c->lb_num; n++) {
449 if(c->lbs[n].lb == nr) {
450 /* replace with new data */
451 c->lbs[n].data_base = ((uint8_t **)data)[0];
452 c->lbs[n].data = ((uint8_t **)data)[1];
458 tmp = realloc(c->lbs, c->lb_num * sizeof(struct lbudf));
460 fprintf(stderr, "realloc lb: %d * %d = %d\n",
461 c->lb_num, sizeof(struct lbudf),
462 c->lb_num * sizeof(struct lbudf));
465 if(c->lbs) free(c->lbs);
469 c->lbs = (struct lbudf *)tmp;
470 c->lbs[n].data_base = ((uint8_t **)data)[0];
471 c->lbs[n].data = ((uint8_t **)data)[1];
475 for(n = 0; n < c->map_num; n++) {
476 if(c->maps[n].lbn == nr) {
477 /* replace with new data */
478 c->maps[n] = *(struct icbmap *)data;
484 tmp = realloc(c->maps, c->map_num * sizeof(struct icbmap));
486 fprintf(stderr, "realloc maps: %d * %d = %d\n",
487 c->map_num, sizeof(struct icbmap),
488 c->map_num * sizeof(struct icbmap));
491 if(c->maps) free(c->maps);
495 c->maps = (struct icbmap *)tmp;
496 c->maps[n] = *(struct icbmap *)data;
506 int udf25::DVDUDFCacheLevel(int level)
510 } else if(level < 0) {
511 return m_udfcache_level;
514 m_udfcache_level = level;
519 void *udf25::GetUDFCacheHandle()
524 void udf25::SetUDFCacheHandle(void *cache)
529 int udf25::GetUDFCache(UDFCacheType type, uint32_t nr, void *data)
534 if(DVDUDFCacheLevel(-1) <= 0)
537 c = (struct udf_cache *)GetUDFCacheHandle();
545 *(struct avdp_t *)data = c->avdp;
551 *(struct pvd_t *)data = c->pvd;
556 if(c->partition_valid) {
557 *(struct Partition *)data = c->partition;
562 if(c->rooticb_valid) {
563 *(struct AD *)data = c->rooticb;
568 for(n = 0; n < c->lb_num; n++) {
569 if(c->lbs[n].lb == nr) {
570 *(uint8_t **)data = c->lbs[n].data;
576 for(n = 0; n < c->map_num; n++) {
577 if(c->maps[n].lbn == nr) {
578 *(struct icbmap *)data = c->maps[n];
590 int udf25::ReadAt( int64_t pos, size_t len, unsigned char *data )
593 ret = m_fp->Seek(pos, SEEK_SET);
597 ret = m_fp->Read(data, len);
598 if(ret < (int64_t)len)
600 CLog::Log(LOGERROR, "udf25::ReadFile - less data than requested available!" );
606 int udf25::DVDReadLBUDF( uint32_t lb_number, size_t block_count, unsigned char *data, int encrypted )
609 size_t len = block_count * DVD_VIDEO_LB_LEN;
610 int64_t pos = lb_number * (int64_t)DVD_VIDEO_LB_LEN;
612 ret = ReadAt(pos, len, data);
616 if((unsigned int)ret < len)
618 CLog::Log(LOGERROR, "udf25::DVDReadLBUDF - Block was not complete, setting to wanted %u (got %u)", (unsigned int)len, (unsigned int)ret);
619 memset(&data[ret], 0, len - ret);
622 return len / DVD_VIDEO_LB_LEN;
625 int udf25::UDFGetAVDP( struct avdp_t *avdp)
627 uint8_t Anchor_base[ DVD_VIDEO_LB_LEN + 2048 ];
628 uint8_t *Anchor = (uint8_t *)(((uintptr_t)Anchor_base & ~((uintptr_t)2047)) + 2048);
629 uint32_t lbnum, MVDS_location, MVDS_length;
635 if(GetUDFCache(AVDPCache, 0, avdp))
640 lbnum = 256; /* Try #1, prime anchor */
644 if( DVDReadLBUDF( lbnum, 1, Anchor, 0 ) > 0 ) {
645 UDFDescriptor( Anchor, &TagID );
651 if( terminate ) return 0; /* Final try failed */
654 /* We already found the last sector. Try #3, alternative
655 * backup anchor. If that fails, don't try again.
660 /* TODO: Find last sector of the disc (this is optional). */
662 /* Try #2, backup anchor */
663 lbnum = lastsector - 256;
665 /* Unable to find last sector */
669 /* It's an anchor! We can leave */
672 /* Main volume descriptor */
673 UDFExtentAD( &Anchor[ 16 ], &MVDS_length, &MVDS_location );
674 avdp->mvds.location = MVDS_location;
675 avdp->mvds.length = MVDS_length;
677 /* Backup volume descriptor */
678 UDFExtentAD( &Anchor[ 24 ], &MVDS_length, &MVDS_location );
679 avdp->rvds.location = MVDS_location;
680 avdp->rvds.length = MVDS_length;
682 SetUDFCache(AVDPCache, 0, avdp);
687 int udf25::UDFFindPartition( int partnum, struct Partition *part )
689 uint8_t LogBlock_base[ DVD_VIDEO_LB_LEN + 2048 ];
690 uint8_t *LogBlock = (uint8_t *)(((uintptr_t)LogBlock_base & ~((uintptr_t)2047)) + 2048);
691 uint32_t lbnum, MVDS_location, MVDS_length;
696 if(!UDFGetAVDP(&avdp))
699 /* Main volume descriptor */
700 MVDS_location = avdp.mvds.location;
701 MVDS_length = avdp.mvds.length;
705 part->VolumeDesc[ 0 ] = '\0';
708 /* Find Volume Descriptor */
709 lbnum = MVDS_location;
712 if( DVDReadLBUDF( lbnum++, 1, LogBlock, 0 ) <= 0 )
715 UDFDescriptor( LogBlock, &TagID );
717 if( ( TagID == 5 ) && ( !part->valid ) ) {
718 /* Partition Descriptor */
719 UDFPartition( LogBlock, &part->Flags, &part->Number,
720 part->Contents, &part->Start, &part->Length );
721 part->valid = ( partnum == part->Number );
722 } else if( ( TagID == 6 ) && ( !volvalid ) ) {
723 /* Logical Volume Descriptor */
724 if( UDFLogVolume( LogBlock, part->VolumeDesc ) ) {
725 /* TODO: sector size wrong! */
730 } while( ( lbnum <= MVDS_location + ( MVDS_length - 1 )
731 / DVD_VIDEO_LB_LEN ) && ( TagID != 8 )
732 && ( ( !part->valid ) || ( !volvalid ) ) );
734 if( ( !part->valid) || ( !volvalid ) ) {
735 /* Backup volume descriptor */
736 MVDS_location = avdp.mvds.location;
737 MVDS_length = avdp.mvds.length;
739 } while( i-- && ( ( !part->valid ) || ( !volvalid ) ) );
741 /* Look for a metadata partition */
744 if( DVDReadLBUDF( lbnum++, 1, LogBlock, 0 ) <= 0 )
747 UDFDescriptor( LogBlock, &TagID );
750 * It seems that someone added a FileType of 250, which seems to be
751 * a "redirect" style file entry. If we discover such an entry, we
752 * add on the "location" to partition->Start, and try again.
753 * Who added this? Is there any official guide somewhere?
755 * Should we handle 261(250) as well? FileEntry+redirect
759 File.Partition = part->Number;
760 File.Partition_Start = part->Start;
762 UDFExtFileEntry( LogBlock, &File );
763 if (File.Type == 250) {
764 part->Start += File.AD_chain[0].Location;
765 part->Length = File.AD_chain[0].Length;
770 } while( ( lbnum < part->Start + part->Length )
771 && ( TagID != 8 ) && ( TagID != 256 ) );
773 /* We only care for the partition, not the volume */
777 int udf25::UDFMapICB( struct AD ICB, struct Partition *partition, struct FileAD *File )
779 uint8_t LogBlock_base[DVD_VIDEO_LB_LEN + 2048];
780 uint8_t *LogBlock = (uint8_t *)(((uintptr_t)LogBlock_base & ~((uintptr_t)2047)) + 2048);
783 struct icbmap tmpmap;
785 lbnum = partition->Start + ICB.Location;
787 if(GetUDFCache(MapCache, lbnum, &tmpmap)) {
788 memcpy(File, &tmpmap.file, sizeof(tmpmap.file));
792 memset(File, 0, sizeof(*File));
793 File->Partition = partition->Number;
794 File->Partition_Start = partition->Start;
797 if( DVDReadLBUDF( lbnum++, 1, LogBlock, 0 ) <= 0 )
800 UDFDescriptor( LogBlock, &TagID );
803 UDFFileEntry( LogBlock, File );
807 /* ExtendedFileInfo */
809 UDFExtFileEntry( LogBlock, File );
814 } while( lbnum <= partition->Start + ICB.Location + ( ICB.Length - 1 )
815 / DVD_VIDEO_LB_LEN );
820 /* check if ad chain continues elsewhere */
821 while(File->num_AD && File->AD_chain[File->num_AD-1].Flags == 3) {
822 struct AD* ad = &File->AD_chain[File->num_AD-1];
824 /* remove the forward pointer from the list */
827 if( DVDReadLBUDF( File->Partition_Start + ad->Location, 1, LogBlock, 0 ) <= 0 )
830 UDFDescriptor( LogBlock, &TagID );
833 /* add all additional entries */
834 UDFAdEntry( LogBlock, File );
840 memcpy(&tmpmap.file, File, sizeof(tmpmap.file));
841 SetUDFCache(MapCache, tmpmap.lbn, &tmpmap);
849 int udf25::UDFScanDir( struct FileAD Dir, char *FileName, struct Partition *partition, struct AD *FileICB, int cache_file_info)
851 char filename[ MAX_UDF_FILE_NAME_LEN ];
852 uint8_t directory_base[ 2 * DVD_VIDEO_LB_LEN + 2048];
853 uint8_t *directory = (uint8_t *)(((uintptr_t)directory_base & ~((uintptr_t)2047)) + 2048);
858 uint8_t *cached_dir_base = NULL, *cached_dir;
864 /* Scan dir for ICB of file */
865 lbnum = partition->Start + Dir.AD_chain[0].Location;
867 if(DVDUDFCacheLevel(-1) > 0) {
870 if(!GetUDFCache(LBUDFCache, lbnum, &cached_dir)) {
871 dir_lba = (Dir.AD_chain[0].Length + DVD_VIDEO_LB_LEN) / DVD_VIDEO_LB_LEN;
872 if((cached_dir_base = (uint8_t *)malloc(dir_lba * DVD_VIDEO_LB_LEN + 2048)) == NULL)
874 cached_dir = (uint8_t *)(((uintptr_t)cached_dir_base & ~((uintptr_t)2047)) + 2048);
875 if( DVDReadLBUDF( lbnum, dir_lba, cached_dir, 0) <= 0 ) {
876 free(cached_dir_base);
877 cached_dir_base = NULL;
882 fprintf(stderr, "malloc dir: %d\n", dir_lba * DVD_VIDEO_LB_LEN);
887 data[0] = cached_dir_base;
888 data[1] = cached_dir;
889 SetUDFCache(LBUDFCache, lbnum, data);
894 if(cached_dir == NULL)
899 while( p < Dir.AD_chain[0].Length ) { /* Assuming dirs don't use chains? */
900 UDFDescriptor( &cached_dir[ p ], &TagID );
902 p += UDFFileIdentifier( &cached_dir[ p ], &filechar,
904 if(cache_file_info && !in_cache) {
905 struct FileAD tmpFile;
907 memset(&tmpFile, 0, sizeof(tmpFile));
909 if( !strcasecmp( FileName, filename ) ) {
910 memcpy(FileICB, &tmpICB, sizeof(tmpICB));
913 UDFMapICB(tmpICB, partition, &tmpFile);
915 if( !strcasecmp( FileName, filename ) ) {
916 memcpy(FileICB, &tmpICB, sizeof(tmpICB));
921 if(cache_file_info && (!in_cache) && found)
926 if(cache_file_info && (!in_cache) && found)
931 if( DVDReadLBUDF( lbnum, 2, directory, 0 ) <= 0 )
935 while( p < Dir.AD_chain[0].Length ) {
936 if( p > DVD_VIDEO_LB_LEN ) {
938 p -= DVD_VIDEO_LB_LEN;
939 Dir.AD_chain[0].Length -= DVD_VIDEO_LB_LEN;
940 if( DVDReadLBUDF( lbnum, 2, directory, 0 ) <= 0 ) {
944 UDFDescriptor( &directory[ p ], &TagID );
946 p += UDFFileIdentifier( &directory[ p ], &filechar,
948 if( !strcasecmp( FileName, filename ) ) {
961 m_udfcache_level = 1;
971 UDF_FILE udf25::UDFFindFile( const char* filename, uint64_t *filesize )
973 uint8_t LogBlock_base[ DVD_VIDEO_LB_LEN + 2048 ];
974 uint8_t *LogBlock = (uint8_t *)(((uintptr_t)LogBlock_base & ~((uintptr_t)2047)) + 2048);
977 struct Partition partition;
978 struct AD RootICB, ICB;
980 char tokenline[ MAX_UDF_FILE_NAME_LEN ];
982 struct FileAD *result;
986 strncat(tokenline, filename, MAX_UDF_FILE_NAME_LEN - 1);
987 memset(&ICB, 0, sizeof(ICB));
988 memset(&File, 0, sizeof(File));
990 if(!(GetUDFCache(PartitionCache, 0, &partition) &&
991 GetUDFCache(RootICBCache, 0, &RootICB))) {
992 /* Find partition, 0 is the standard location for DVD Video.*/
993 if( !UDFFindPartition(0, &partition ) ) return 0;
994 SetUDFCache(PartitionCache, 0, &partition);
996 /* Find root dir ICB */
997 lbnum = partition.Start;
999 if( DVDReadLBUDF( lbnum++, 1, LogBlock, 0 ) <= 0 )
1002 UDFDescriptor( LogBlock, &TagID );
1004 /* File Set Descriptor */
1005 if( TagID == 256 ) /* File Set Descriptor */
1006 UDFLongAD( &LogBlock[ 400 ], &RootICB );
1007 } while( ( lbnum < partition.Start + partition.Length )
1008 && ( TagID != 8 ) && ( TagID != 256 ) );
1010 /* Sanity checks. */
1013 /* This following test will fail under UDF2.50 images, as it is no longer
1015 /*if( RootICB.Partition != 0 )
1017 SetUDFCache(RootICBCache, 0, &RootICB);
1021 if( !UDFMapICB( RootICB, &partition, &File ) )
1023 if( File.Type != 4 )
1024 return NULL; /* Root dir should be dir */
1026 int cache_file_info = 0;
1027 /* Tokenize filepath */
1028 token = strtok(tokenline, "/");
1030 while( token != NULL ) {
1031 if( !UDFScanDir( File, token, &partition, &ICB,
1034 if( !UDFMapICB( ICB, &partition, &File ) )
1036 if(!strcmp(token, "index.bdmv"))
1037 cache_file_info = 1;
1038 token = strtok( NULL, "/" );
1043 if( File.AD_chain[0].Partition != 0 )
1045 *filesize = File.Length;
1046 /* Hack to not return partition.Start for empty files. */
1047 if( !File.AD_chain[0].Location )
1050 /* Allocate a new UDF_FILE and return it. */
1051 result = (struct FileAD *) malloc(sizeof(*result));
1052 if (!result) return NULL;
1054 memcpy(result, &File, sizeof(*result));
1058 bool udf25::Open(const char *isofile)
1062 if(!m_fp->Open(isofile))
1064 CLog::Log(LOGERROR,"file_open - Could not open input");
1072 HANDLE udf25::OpenFile( const char* filename )
1075 UDF_FILE file = NULL;
1076 BD_FILE bdfile = NULL;
1079 return INVALID_HANDLE_VALUE;
1081 file = UDFFindFile(filename, &filesize);
1083 return INVALID_HANDLE_VALUE;
1085 bdfile = (BD_FILE)calloc(1, sizeof(*bdfile));
1087 bdfile->file = file;
1088 bdfile->filesize = filesize;
1089 return (HANDLE)bdfile;
1093 long udf25::ReadFile(HANDLE hFile, unsigned char *pBuffer, long lSize)
1095 BD_FILE bdfile = (BD_FILE)hFile;
1101 /* Check arguments. */
1102 if( bdfile == NULL || pBuffer == NULL )
1108 len = UDFFilePos(bdfile->file, bdfile->seek_pos, &pos);
1112 pos -= 32 * DVD_VIDEO_LB_LEN; /* why? */
1114 if((uint32_t)lSize < len)
1117 ret = ReadAt(pos, len, pBuffer);
1120 CLog::Log(LOGERROR, "udf25::ReadFile - error during read" );
1127 bdfile->seek_pos += ret;
1132 return len_origin - lSize;
1135 void udf25::CloseFile(HANDLE hFile)
1137 if(hFile == INVALID_HANDLE_VALUE)
1140 BD_FILE bdfile = (BD_FILE)hFile;
1148 int64_t udf25::Seek(HANDLE hFile, int64_t lOffset, int whence)
1150 BD_FILE bdfile = (BD_FILE)hFile;
1155 int64_t seek_pos = bdfile->seek_pos;
1160 bdfile->seek_pos = lOffset;
1165 bdfile->seek_pos += lOffset;
1169 bdfile->seek_pos = bdfile->filesize + lOffset;
1173 if (bdfile->seek_pos > bdfile->filesize)
1175 bdfile->seek_pos = seek_pos;
1176 return bdfile->seek_pos;
1179 return bdfile->seek_pos;
1182 int64_t udf25::GetFileSize(HANDLE hFile)
1184 BD_FILE bdfile = (BD_FILE)hFile;
1189 return bdfile->filesize;
1192 int64_t udf25::GetFilePosition(HANDLE hFile)
1194 BD_FILE bdfile = (BD_FILE)hFile;
1199 return bdfile->seek_pos;
1202 udf_dir_t *udf25::OpenDir( const char *subdir )
1207 bd_file = (BD_FILE)OpenFile(subdir);
1209 if (bd_file == (BD_FILE)INVALID_HANDLE_VALUE)
1212 result = (udf_dir_t *)calloc(1, sizeof(udf_dir_t));
1214 CloseFile((HANDLE)bd_file);
1218 result->dir_location = UDFFileBlockPos(bd_file->file, 0);
1219 result->dir_current = UDFFileBlockPos(bd_file->file, 0);
1220 result->dir_length = (uint32_t) bd_file->filesize;
1221 CloseFile((HANDLE)bd_file);
1226 udf_dirent_t *udf25::ReadDir( udf_dir_t *dirp )
1228 if (!UDFScanDirX(dirp)) {
1229 dirp->current_p = 0;
1230 dirp->dir_current = dirp->dir_location; // this is a rewind, wanted?
1234 return &dirp->entry;
1237 int udf25::CloseDir( udf_dir_t *dirp )
1239 if (!dirp) return 0;