changed: Add logic to properly handle subtitles for stacked files
[vuplus_xbmc] / xbmc / filesystem / udf25.cpp
1 /*
2  *      Copyright (C) 2010 Team Boxee
3  *      http://www.boxee.tv
4  *
5  *      Copyright (C) 2010-2013 Team XBMC
6  *      http://xbmc.org
7  *
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)
11  *  any later version.
12  *
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.
17  *
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/>.
21  *
22  *  Note: parts of this code comes from libdvdread.
23  *  Jorgen Lundman and team boxee did the necessary modifications to support udf 2.5
24  *
25  */
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <fcntl.h>
29 #include "system.h"
30 #include "utils/log.h"
31 #include "udf25.h"
32 #include "File.h"
33
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))
51
52 /* This is wrong with regard to endianess */
53 #define GETN(p, n, target) memcpy(target, &data[p], n)
54
55 using namespace XFILE;
56
57 static int Unicodedecode( uint8_t *data, int len, char *target )
58 {
59   int p = 1, i = 0;
60
61   if( ( data[ 0 ] == 8 ) || ( data[ 0 ] == 16 ) ) do {
62     if( data[ 0 ] == 16 ) p++;  /* Ignore MSB of unicode16 */
63     if( p < len ) {
64       target[ i++ ] = data[ p++ ];
65     }
66   } while( p < len );
67
68   target[ i ] = '\0';
69   return 0;
70 }
71
72 static int UDFExtentAD( uint8_t *data, uint32_t *Length, uint32_t *Location )
73 {
74   *Length   = GETN4(0);
75   *Location = GETN4(4);
76   return 0;
77 }
78
79 static int UDFShortAD( uint8_t *data, struct AD *ad )
80 {
81   ad->Length = GETN4(0);
82   ad->Flags = ad->Length >> 30;
83   ad->Length &= 0x3FFFFFFF;
84   ad->Location = GETN4(4);
85   return 0;
86 }
87
88 static int UDFLongAD( uint8_t *data, struct AD *ad )
89 {
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); */
96   return 0;
97 }
98
99 static int UDFExtAD( uint8_t *data, struct AD *ad )
100 {
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); */
107   return 0;
108 }
109
110 static int UDFAD( uint8_t *ptr, uint32_t len, struct FileAD *fad)
111 {
112   struct AD *ad;
113
114   if (fad->num_AD  >= UDF_MAX_AD_CHAINS)
115     return len;
116
117   ad =  &fad->AD_chain[fad->num_AD];
118   ad->Partition = fad->Partition;
119   ad->Flags     = 0;
120   fad->num_AD++;
121
122   switch( fad->Flags & 0x0007 ) {
123     case 0:
124       UDFShortAD( ptr, ad );
125       return 8;
126     case 1:
127       UDFLongAD( ptr, ad );
128       return 16;
129     case 2:
130       UDFExtAD( ptr, ad );
131       return 20;
132     case 3:
133       switch( len ) {
134         case 8:
135           UDFShortAD( ptr, ad );
136           break;
137         case 16:
138           UDFLongAD( ptr,  ad );
139           break;
140         case 20:
141           UDFExtAD( ptr, ad );
142           break;
143       }
144       break;
145     default:
146       break;
147   }
148
149   return len;
150 }
151
152 static int UDFICB( uint8_t *data, uint8_t *FileType, uint16_t *Flags )
153 {
154   *FileType = GETN1(11);
155   *Flags = GETN2(18);
156   return 0;
157 }
158
159 static int UDFPartition( uint8_t *data, uint16_t *Flags, uint16_t *Number,
160                          char *Contents, uint32_t *Start, uint32_t *Length )
161 {
162   *Flags = GETN2(20);
163   *Number = GETN2(22);
164   GETN(24, 32, Contents);
165   *Start = GETN4(188);
166   *Length = GETN4(192);
167   return 0;
168 }
169
170 static int UDFLogVolume( uint8_t *data, char *VolumeDescriptor )
171 {
172   uint32_t lbsize;
173   Unicodedecode(&data[84], 128, VolumeDescriptor);
174   lbsize = GETN4(212);  /* should be 2048 */
175   if (lbsize != DVD_VIDEO_LB_LEN) return 1;
176   return 0;
177 }
178
179 static int UDFAdEntry( uint8_t *data, struct FileAD *fad )
180 {
181   uint32_t L_AD;
182   unsigned int p;
183
184   L_AD = GETN4(20);
185   p = 24;
186   while( p < 24 + L_AD ) {
187     p += UDFAD( &data[ p ], L_AD, fad );
188   }
189   return 0;
190 }
191
192 static int UDFExtFileEntry( uint8_t *data, struct FileAD *fad )
193 {
194   uint32_t L_EA, L_AD;
195   unsigned int p;
196
197   UDFICB( &data[ 16 ], &fad->Type, &fad->Flags );
198
199   /* Init ad for an empty file (i.e. there isn't a AD, L_AD == 0 ) */
200   fad->Length = GETN8(56); // 64-bit.
201
202   L_EA = GETN4( 208);
203   L_AD = GETN4( 212);
204   p = 216 + L_EA;
205   fad->num_AD = 0;
206   while( p < 216 + L_EA + L_AD ) {
207     p += UDFAD( &data[ p ], L_AD, fad );
208   }
209   return 0;
210
211 }
212
213 /* TagID 266
214  * The differences in ExtFile are indicated below:
215  * struct extfile_entry {
216  *         struct desc_tag         tag;
217  *         struct icb_tag          icbtag;
218  *         uint32_t                uid;
219  *         uint32_t                gid;
220  *         uint32_t                perm;
221  *         uint16_t                link_cnt;
222  *         uint8_t                 rec_format;
223  *         uint8_t                 rec_disp_attr;
224  *         uint32_t                rec_len;
225  *         uint64_t                inf_len;
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;
232  *         uint32_t                ckpoint;
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;
238  *         uint32_t                l_ea;
239  *         uint32_t                l_ad;
240  *         uint8_t                 data[1];
241  * } __packed;
242  *
243  * So old "l_ea" is now +216
244  *
245  * Lund
246  */
247
248 static int UDFFileEntry( uint8_t *data, struct FileAD *fad )
249 {
250   uint32_t L_EA, L_AD;
251   unsigned int p;
252
253   UDFICB( &data[ 16 ], &fad->Type, &fad->Flags );
254
255   fad->Length = GETN8( 56 ); /* Was 4 bytes at 60, changed for 64bit. */
256
257   L_EA = GETN4( 168 );
258   L_AD = GETN4( 172 );
259
260   if (176 + L_EA + L_AD > DVD_VIDEO_LB_LEN)
261     return 0;
262
263   p = 176 + L_EA;
264   fad->num_AD = 0;
265   while( p < 176 + L_EA + L_AD ) {
266       p += UDFAD( &data[ p ], L_AD, fad );
267   }
268   return 0;
269 }
270
271 uint32_t UDFFilePos(struct FileAD *File, uint64_t pos, uint64_t *res)
272 {
273   uint32_t i;
274
275   for (i = 0; i < File->num_AD; i++) {
276
277     if (pos < File->AD_chain[i].Length)
278       break;
279
280     pos -= File->AD_chain[i].Length;
281   }
282
283   if (i == File->num_AD)
284     return 0;
285
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;
288 }
289
290 uint32_t UDFFileBlockPos(struct FileAD *File, uint32_t lb)
291 {
292   uint64_t res;
293   uint32_t rem;
294   rem = UDFFilePos(File, lb * DVD_VIDEO_LB_LEN, &res);
295   if(rem > 0)
296     return (uint32_t)(res / DVD_VIDEO_LB_LEN);
297   else
298     return 0;
299 }
300
301 static int UDFFileIdentifier( uint8_t *data, uint8_t *FileCharacteristics,
302                               char *FileName, struct AD *FileICB )
303 {
304   uint8_t L_FI;
305   uint16_t L_IU;
306
307   *FileCharacteristics = GETN1(18);
308   L_FI = GETN1(19);
309   UDFLongAD(&data[20], FileICB);
310   L_IU = GETN2(36);
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);
314 }
315
316 static int UDFDescriptor( uint8_t *data, uint16_t *TagID )
317 {
318   *TagID = GETN2(0);
319   /* TODO: check CRC 'n stuff */
320   return 0;
321 }
322
323 int udf25::UDFScanDirX( udf_dir_t *dirp )
324 {
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);
328   uint32_t lbnum;
329   uint16_t TagID;
330   uint8_t filechar;
331   unsigned int p;
332   struct AD FileICB;
333   struct FileAD File;
334   struct Partition partition;
335
336   if(!(GetUDFCache(PartitionCache, 0, &partition))) {
337     if(!UDFFindPartition(0, &partition))
338       return 0;
339   }
340
341   /* Scan dir for ICB of file */
342   lbnum = dirp->dir_current;
343
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));
347
348   if( DVDReadLBUDF( lbnum, 2, directory, 0 ) <= 0 ) {
349     return 0;
350   }
351
352
353   p = dirp->current_p;
354   while( p < dirp->dir_length ) {
355     if( p > DVD_VIDEO_LB_LEN ) {
356       ++lbnum;
357       p -= DVD_VIDEO_LB_LEN;
358
359       //Dir.Length -= DVD_VIDEO_LB_LEN;
360       if (dirp->dir_length >= DVD_VIDEO_LB_LEN)
361         dirp->dir_length -= DVD_VIDEO_LB_LEN;
362       else
363         dirp->dir_length = 0;
364
365       if( DVDReadLBUDF( lbnum, 2, directory, 0 ) <= 0 ) {
366         return 0;
367       }
368     }
369     UDFDescriptor( &directory[ p ], &TagID );
370
371     if( TagID == 257 ) {
372
373       p += UDFFileIdentifier( &directory[ p ], &filechar,
374                               filename, &FileICB );
375
376       dirp->current_p = p;
377       dirp->dir_current = lbnum;
378
379       if (!*filename)  // No filename, simulate "." dirname
380         strcpy((char *)dirp->entry.d_name, ".");
381       else {
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;
386       }
387
388
389       // Look up the Filedata
390       if( !UDFMapICB( FileICB, &partition, &File))
391         return 0;
392       if (File.Type == 4)
393         dirp->entry.d_type = DVD_DT_DIR;
394       else
395         dirp->entry.d_type = DVD_DT_REG; // Add more types?
396
397       dirp->entry.d_filesize = File.Length;
398
399       return 1;
400
401     } else {
402       // Not TagID 257
403       return 0;
404     }
405   }
406   // End of DIR
407   return 0;
408 }
409
410 int udf25::SetUDFCache(UDFCacheType type, uint32_t nr, void *data)
411 {
412   int n;
413   struct udf_cache *c;
414   void *tmp;
415
416   if(DVDUDFCacheLevel(-1) <= 0)
417     return 0;
418
419   c = (struct udf_cache *)GetUDFCacheHandle();
420
421   if(c == NULL) {
422     c = (struct udf_cache *)calloc(1, sizeof(struct udf_cache));
423     /* fprintf(stderr, "calloc: %d\n", sizeof(struct udf_cache)); */
424     if(c == NULL)
425       return 0;
426     SetUDFCacheHandle(c);
427   }
428
429
430   switch(type) {
431   case AVDPCache:
432     c->avdp = *(struct avdp_t *)data;
433     c->avdp_valid = 1;
434     break;
435   case PVDCache:
436     c->pvd = *(struct pvd_t *)data;
437     c->pvd_valid = 1;
438     break;
439   case PartitionCache:
440     c->partition = *(struct Partition *)data;
441     c->partition_valid = 1;
442     break;
443   case RootICBCache:
444     c->rooticb = *(struct AD *)data;
445     c->rooticb_valid = 1;
446     break;
447   case LBUDFCache:
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];
453         c->lbs[n].lb = nr;
454         return 1;
455       }
456     }
457     c->lb_num++;
458     tmp = realloc(c->lbs, c->lb_num * sizeof(struct lbudf));
459     /*
460     fprintf(stderr, "realloc lb: %d * %d = %d\n",
461     c->lb_num, sizeof(struct lbudf),
462     c->lb_num * sizeof(struct lbudf));
463     */
464     if(tmp == NULL) {
465       if(c->lbs) free(c->lbs);
466       c->lb_num = 0;
467       return 0;
468     }
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];
472     c->lbs[n].lb = nr;
473     break;
474   case MapCache:
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;
479         c->maps[n].lbn = nr;
480         return 1;
481       }
482     }
483     c->map_num++;
484     tmp = realloc(c->maps, c->map_num * sizeof(struct icbmap));
485     /*
486     fprintf(stderr, "realloc maps: %d * %d = %d\n",
487       c->map_num, sizeof(struct icbmap),
488       c->map_num * sizeof(struct icbmap));
489     */
490     if(tmp == NULL) {
491       if(c->maps) free(c->maps);
492       c->map_num = 0;
493       return 0;
494     }
495     c->maps = (struct icbmap *)tmp;
496     c->maps[n] = *(struct icbmap *)data;
497     c->maps[n].lbn = nr;
498     break;
499   default:
500     return 0;
501   }
502
503   return 1;
504 }
505
506 int udf25::DVDUDFCacheLevel(int level)
507 {
508   if(level > 0) {
509     level = 1;
510   } else if(level < 0) {
511     return m_udfcache_level;
512   }
513
514   m_udfcache_level = level;
515
516   return level;
517 }
518
519 void *udf25::GetUDFCacheHandle()
520 {
521   return m_udfcache;
522 }
523
524 void udf25::SetUDFCacheHandle(void *cache)
525 {
526   m_udfcache = cache;
527 }
528
529 int udf25::GetUDFCache(UDFCacheType type, uint32_t nr, void *data)
530 {
531   int n;
532   struct udf_cache *c;
533
534   if(DVDUDFCacheLevel(-1) <= 0)
535     return 0;
536
537   c = (struct udf_cache *)GetUDFCacheHandle();
538
539   if(c == NULL)
540     return 0;
541
542   switch(type) {
543   case AVDPCache:
544     if(c->avdp_valid) {
545       *(struct avdp_t *)data = c->avdp;
546       return 1;
547     }
548     break;
549   case PVDCache:
550     if(c->pvd_valid) {
551       *(struct pvd_t *)data = c->pvd;
552       return 1;
553     }
554     break;
555   case PartitionCache:
556     if(c->partition_valid) {
557       *(struct Partition *)data = c->partition;
558       return 1;
559     }
560     break;
561   case RootICBCache:
562     if(c->rooticb_valid) {
563       *(struct AD *)data = c->rooticb;
564       return 1;
565     }
566     break;
567   case LBUDFCache:
568     for(n = 0; n < c->lb_num; n++) {
569       if(c->lbs[n].lb == nr) {
570         *(uint8_t **)data = c->lbs[n].data;
571         return 1;
572       }
573     }
574     break;
575   case MapCache:
576     for(n = 0; n < c->map_num; n++) {
577       if(c->maps[n].lbn == nr) {
578         *(struct icbmap *)data = c->maps[n];
579         return 1;
580       }
581     }
582     break;
583   default:
584     break;
585   }
586
587   return 0;
588 }
589
590 int udf25::ReadAt( int64_t pos, size_t len, unsigned char *data )
591 {
592   int64_t ret;
593   ret = m_fp->Seek(pos, SEEK_SET);
594   if(ret != pos)
595     return -1;
596
597   ret = m_fp->Read(data, len);
598   if(ret < (int64_t)len)
599   {
600     CLog::Log(LOGERROR, "udf25::ReadFile - less data than requested available!" );
601     return (int)ret;
602   }
603   return (int)ret;
604 }
605
606 int udf25::DVDReadLBUDF( uint32_t lb_number, size_t block_count, unsigned char *data, int encrypted )
607 {
608   int ret;
609   size_t  len = block_count * DVD_VIDEO_LB_LEN;
610   int64_t pos = lb_number   * (int64_t)DVD_VIDEO_LB_LEN;
611
612   ret = ReadAt(pos, len, data);
613   if(ret < 0)
614     return ret;
615
616   if((unsigned int)ret < len)
617   {
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);
620   }
621
622   return len / DVD_VIDEO_LB_LEN;
623 }
624
625 int udf25::UDFGetAVDP( struct avdp_t *avdp)
626 {
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;
630   uint16_t TagID;
631   uint32_t lastsector;
632   int terminate;
633   struct avdp_t;
634
635   if(GetUDFCache(AVDPCache, 0, avdp))
636     return 1;
637
638   /* Find Anchor */
639   lastsector = 0;
640   lbnum = 256;   /* Try #1, prime anchor */
641   terminate = 0;
642
643   for(;;) {
644     if( DVDReadLBUDF( lbnum, 1, Anchor, 0 ) > 0 ) {
645       UDFDescriptor( Anchor, &TagID );
646     } else {
647       TagID = 0;
648     }
649     if (TagID != 2) {
650       /* Not an anchor */
651       if( terminate ) return 0; /* Final try failed */
652
653       if( lastsector ) {
654         /* We already found the last sector.  Try #3, alternative
655          * backup anchor.  If that fails, don't try again.
656          */
657         lbnum = lastsector;
658         terminate = 1;
659       } else {
660         /* TODO: Find last sector of the disc (this is optional). */
661         if( lastsector )
662           /* Try #2, backup anchor */
663           lbnum = lastsector - 256;
664         else
665           /* Unable to find last sector */
666           return 0;
667       }
668     } else
669       /* It's an anchor! We can leave */
670       break;
671   }
672   /* Main volume descriptor */
673   UDFExtentAD( &Anchor[ 16 ], &MVDS_length, &MVDS_location );
674   avdp->mvds.location = MVDS_location;
675   avdp->mvds.length = MVDS_length;
676
677   /* Backup volume descriptor */
678   UDFExtentAD( &Anchor[ 24 ], &MVDS_length, &MVDS_location );
679   avdp->rvds.location = MVDS_location;
680   avdp->rvds.length = MVDS_length;
681
682   SetUDFCache(AVDPCache, 0, avdp);
683
684   return 1;
685 }
686
687 int udf25::UDFFindPartition( int partnum, struct Partition *part )
688 {
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;
692   uint16_t TagID;
693   int i, volvalid;
694   struct avdp_t avdp;
695
696   if(!UDFGetAVDP(&avdp))
697     return 0;
698
699   /* Main volume descriptor */
700   MVDS_location = avdp.mvds.location;
701   MVDS_length = avdp.mvds.length;
702
703   part->valid = 0;
704   volvalid = 0;
705   part->VolumeDesc[ 0 ] = '\0';
706   i = 1;
707   do {
708     /* Find Volume Descriptor */
709     lbnum = MVDS_location;
710     do {
711
712       if( DVDReadLBUDF( lbnum++, 1, LogBlock, 0 ) <= 0 )
713         TagID = 0;
714       else
715         UDFDescriptor( LogBlock, &TagID );
716
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! */
726         } else
727           volvalid = 1;
728       }
729
730     } while( ( lbnum <= MVDS_location + ( MVDS_length - 1 )
731                / DVD_VIDEO_LB_LEN ) && ( TagID != 8 )
732              && ( ( !part->valid ) || ( !volvalid ) ) );
733
734     if( ( !part->valid) || ( !volvalid ) ) {
735       /* Backup volume descriptor */
736       MVDS_location = avdp.mvds.location;
737       MVDS_length = avdp.mvds.length;
738     }
739   } while( i-- && ( ( !part->valid ) || ( !volvalid ) ) );
740
741   /* Look for a metadata partition */
742   lbnum = part->Start;
743   do {
744     if( DVDReadLBUDF( lbnum++, 1, LogBlock, 0 ) <= 0 )
745       TagID = 0;
746     else
747       UDFDescriptor( LogBlock, &TagID );
748
749     /*
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?
754      * 2008/09/17 lundman
755      * Should we handle 261(250) as well? FileEntry+redirect
756      */
757     if( TagID == 266 ) {
758       struct FileAD File;
759       File.Partition       = part->Number;
760       File.Partition_Start = part->Start;
761
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;
766         break;
767       }
768     }
769
770   } while( ( lbnum < part->Start + part->Length )
771           && ( TagID != 8 ) && ( TagID != 256 ) );
772
773   /* We only care for the partition, not the volume */
774   return part->valid;
775 }
776
777 int udf25::UDFMapICB( struct AD ICB, struct Partition *partition, struct FileAD *File )
778 {
779   uint8_t LogBlock_base[DVD_VIDEO_LB_LEN + 2048];
780   uint8_t *LogBlock = (uint8_t *)(((uintptr_t)LogBlock_base & ~((uintptr_t)2047)) + 2048);
781   uint32_t lbnum;
782   uint16_t TagID;
783   struct icbmap tmpmap;
784
785   lbnum = partition->Start + ICB.Location;
786   tmpmap.lbn = lbnum;
787   if(GetUDFCache(MapCache, lbnum, &tmpmap)) {
788     memcpy(File, &tmpmap.file, sizeof(tmpmap.file));
789     return 1;
790   }
791
792   memset(File, 0, sizeof(*File));
793   File->Partition       = partition->Number;
794   File->Partition_Start = partition->Start;
795
796   do {
797     if( DVDReadLBUDF( lbnum++, 1, LogBlock, 0 ) <= 0 )
798       TagID = 0;
799     else
800       UDFDescriptor( LogBlock, &TagID );
801
802     if( TagID == 261 ) {
803       UDFFileEntry( LogBlock, File );
804       break;
805     };
806
807     /* ExtendedFileInfo */
808     if( TagID == 266 ) {
809       UDFExtFileEntry( LogBlock, File );
810       break;
811     }
812
813
814   } while( lbnum <= partition->Start + ICB.Location + ( ICB.Length - 1 )
815              / DVD_VIDEO_LB_LEN );
816
817
818   if(File->Type) {
819
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];
823
824       /* remove the forward pointer from the list */
825       File->num_AD--;
826
827       if( DVDReadLBUDF( File->Partition_Start + ad->Location, 1, LogBlock, 0 ) <= 0 )
828         TagID = 0;
829       else
830         UDFDescriptor( LogBlock, &TagID );
831
832       if( TagID == 258 ) {
833         /* add all additional entries */
834         UDFAdEntry( LogBlock, File );
835       } else {
836         return 0;
837       }
838     }
839
840     memcpy(&tmpmap.file, File, sizeof(tmpmap.file));
841     SetUDFCache(MapCache, tmpmap.lbn, &tmpmap);
842
843     return 1;
844   }
845
846   return 0;
847 }
848
849 int udf25::UDFScanDir( struct FileAD Dir, char *FileName, struct Partition *partition, struct AD *FileICB, int cache_file_info)
850 {
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);
854   uint32_t lbnum;
855   uint16_t TagID;
856   uint8_t filechar;
857   unsigned int p;
858   uint8_t *cached_dir_base = NULL, *cached_dir;
859   uint32_t dir_lba;
860   struct AD tmpICB;
861   int found = 0;
862   int in_cache = 0;
863
864   /* Scan dir for ICB of file */
865   lbnum = partition->Start + Dir.AD_chain[0].Location;
866
867   if(DVDUDFCacheLevel(-1) > 0) {
868     /* caching */
869
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)
873         return 0;
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;
878         cached_dir = NULL;
879       }
880       /*
881       if(cached_dir) {
882         fprintf(stderr, "malloc dir: %d\n",  dir_lba * DVD_VIDEO_LB_LEN);
883       }
884       */
885       {
886         uint8_t *data[2];
887         data[0] = cached_dir_base;
888         data[1] = cached_dir;
889         SetUDFCache(LBUDFCache, lbnum, data);
890       }
891     } else
892       in_cache = 1;
893
894     if(cached_dir == NULL)
895       return 0;
896
897     p = 0;
898
899     while( p < Dir.AD_chain[0].Length ) {  /* Assuming dirs don't use chains? */
900       UDFDescriptor( &cached_dir[ p ], &TagID );
901       if( TagID == 257 ) {
902         p += UDFFileIdentifier( &cached_dir[ p ], &filechar,
903                                 filename, &tmpICB );
904         if(cache_file_info && !in_cache) {
905           struct FileAD tmpFile;
906
907           memset(&tmpFile, 0, sizeof(tmpFile));
908
909           if( !strcasecmp( FileName, filename ) ) {
910             memcpy(FileICB, &tmpICB, sizeof(tmpICB));
911             found = 1;
912           }
913           UDFMapICB(tmpICB, partition, &tmpFile);
914         } else {
915           if( !strcasecmp( FileName, filename ) ) {
916             memcpy(FileICB, &tmpICB, sizeof(tmpICB));
917             return 1;
918           }
919         }
920       } else {
921         if(cache_file_info && (!in_cache) && found)
922           return 1;
923         return 0;
924       }
925     }
926     if(cache_file_info && (!in_cache) && found)
927       return 1;
928     return 0;
929   }
930
931   if( DVDReadLBUDF( lbnum, 2, directory, 0 ) <= 0 )
932     return 0;
933
934   p = 0;
935   while( p < Dir.AD_chain[0].Length ) {
936     if( p > DVD_VIDEO_LB_LEN ) {
937       ++lbnum;
938       p -= DVD_VIDEO_LB_LEN;
939       Dir.AD_chain[0].Length -= DVD_VIDEO_LB_LEN;
940       if( DVDReadLBUDF( lbnum, 2, directory, 0 ) <= 0 ) {
941         return 0;
942       }
943     }
944     UDFDescriptor( &directory[ p ], &TagID );
945     if( TagID == 257 ) {
946       p += UDFFileIdentifier( &directory[ p ], &filechar,
947                               filename, FileICB );
948       if( !strcasecmp( FileName, filename ) ) {
949         return 1;
950       }
951     } else
952       return 0;
953   }
954
955   return 0;
956 }
957
958 udf25::udf25( )
959 {
960   m_fp = NULL;
961   m_udfcache_level = 1;
962   m_udfcache = NULL;
963 }
964
965 udf25::~udf25( )
966 {
967   delete m_fp;
968   free(m_udfcache);
969 }
970
971 UDF_FILE udf25::UDFFindFile( const char* filename, uint64_t *filesize )
972 {
973   uint8_t LogBlock_base[ DVD_VIDEO_LB_LEN + 2048 ];
974   uint8_t *LogBlock = (uint8_t *)(((uintptr_t)LogBlock_base & ~((uintptr_t)2047)) + 2048);
975   uint32_t lbnum;
976   uint16_t TagID;
977   struct Partition partition;
978   struct AD RootICB, ICB;
979   struct FileAD File;
980   char tokenline[ MAX_UDF_FILE_NAME_LEN ];
981   char *token;
982   struct FileAD *result;
983
984   *filesize = 0;
985   tokenline[0] = '\0';
986   strncat(tokenline, filename, MAX_UDF_FILE_NAME_LEN - 1);
987   memset(&ICB, 0, sizeof(ICB));
988   memset(&File, 0, sizeof(File));
989
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);
995
996     /* Find root dir ICB */
997     lbnum = partition.Start;
998     do {
999       if( DVDReadLBUDF( lbnum++, 1, LogBlock, 0 ) <= 0 )
1000         TagID = 0;
1001       else
1002         UDFDescriptor( LogBlock, &TagID );
1003
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 ) );
1009
1010     /* Sanity checks. */
1011     if( TagID != 256 )
1012       return NULL;
1013     /* This following test will fail under UDF2.50 images, as it is no longer
1014      * valid */
1015     /*if( RootICB.Partition != 0 )
1016       return 0;*/
1017     SetUDFCache(RootICBCache, 0, &RootICB);
1018   }
1019
1020   /* Find root dir */
1021   if( !UDFMapICB( RootICB, &partition, &File ) )
1022     return NULL;
1023   if( File.Type != 4 )
1024     return NULL;  /* Root dir should be dir */
1025   {
1026     int cache_file_info = 0;
1027     /* Tokenize filepath */
1028     token = strtok(tokenline, "/");
1029
1030     while( token != NULL ) {
1031       if( !UDFScanDir( File, token, &partition, &ICB,
1032                        cache_file_info))
1033         return NULL;
1034       if( !UDFMapICB( ICB, &partition, &File ) )
1035         return NULL;
1036       if(!strcmp(token, "index.bdmv"))
1037         cache_file_info = 1;
1038       token = strtok( NULL, "/" );
1039     }
1040   }
1041
1042   /* Sanity check. */
1043   if( File.AD_chain[0].Partition != 0 )
1044     return 0;
1045   *filesize = File.Length;
1046   /* Hack to not return partition.Start for empty files. */
1047   if( !File.AD_chain[0].Location )
1048     return NULL;
1049
1050   /* Allocate a new UDF_FILE and return it. */
1051   result = (struct FileAD *) malloc(sizeof(*result));
1052   if (!result) return NULL;
1053
1054   memcpy(result, &File, sizeof(*result));
1055   return result;
1056 }
1057
1058 bool udf25::Open(const char *isofile)
1059 {
1060   m_fp = new CFile();
1061
1062   if(!m_fp->Open(isofile))
1063   {
1064     CLog::Log(LOGERROR,"file_open - Could not open input");
1065     delete m_fp;
1066     m_fp = NULL;
1067     return false;
1068   }
1069   return true;
1070 }
1071
1072 HANDLE udf25::OpenFile( const char* filename )
1073 {
1074   uint64_t filesize;
1075   UDF_FILE file = NULL;
1076   BD_FILE bdfile = NULL;
1077
1078   if(!m_fp)
1079     return INVALID_HANDLE_VALUE;
1080
1081   file = UDFFindFile(filename, &filesize);
1082   if(!file)
1083     return INVALID_HANDLE_VALUE;
1084
1085   bdfile = (BD_FILE)calloc(1, sizeof(*bdfile));
1086
1087   bdfile->file     = file;
1088   bdfile->filesize = filesize;
1089   return (HANDLE)bdfile;
1090 }
1091
1092
1093 long udf25::ReadFile(HANDLE hFile, unsigned char *pBuffer, long lSize)
1094 {
1095   BD_FILE bdfile = (BD_FILE)hFile;
1096   long    len_origin;
1097   uint64_t pos;
1098   uint32_t len;
1099   int      ret;
1100
1101   /* Check arguments. */
1102   if( bdfile == NULL || pBuffer == NULL )
1103     return -1;
1104
1105   len_origin = lSize;
1106   while(lSize > 0)
1107   {
1108     len = UDFFilePos(bdfile->file, bdfile->seek_pos, &pos);
1109     if(len == 0)
1110       break;
1111
1112     pos -= 32 * DVD_VIDEO_LB_LEN; /* why? */
1113
1114     if((uint32_t)lSize < len)
1115       len = lSize;
1116
1117     ret = ReadAt(pos, len, pBuffer);
1118     if(ret < 0)
1119     {
1120       CLog::Log(LOGERROR, "udf25::ReadFile - error during read" );
1121       return ret;
1122     }
1123
1124     if(ret == 0)
1125       break;
1126
1127     bdfile->seek_pos += ret;
1128     pBuffer          += ret;
1129     lSize            -= ret;
1130   }
1131
1132   return len_origin - lSize;
1133 }
1134
1135 void udf25::CloseFile(HANDLE hFile)
1136 {
1137   if(hFile == INVALID_HANDLE_VALUE)
1138     return;
1139
1140   BD_FILE bdfile = (BD_FILE)hFile;
1141   if(bdfile)
1142   {
1143     free(bdfile->file);
1144     free(bdfile);
1145   }
1146 }
1147
1148 int64_t udf25::Seek(HANDLE hFile, int64_t lOffset, int whence)
1149 {
1150   BD_FILE bdfile = (BD_FILE)hFile;
1151
1152   if(bdfile == NULL)
1153     return -1;
1154
1155   int64_t seek_pos = bdfile->seek_pos;
1156   switch (whence)
1157   {
1158   case SEEK_SET:
1159     // cur = pos
1160     bdfile->seek_pos = lOffset;
1161     break;
1162
1163   case SEEK_CUR:
1164     // cur += pos
1165     bdfile->seek_pos += lOffset;
1166     break;
1167   case SEEK_END:
1168     // end += pos
1169     bdfile->seek_pos = bdfile->filesize + lOffset;
1170     break;
1171   }
1172
1173   if (bdfile->seek_pos > bdfile->filesize)
1174   {
1175     bdfile->seek_pos = seek_pos;
1176     return bdfile->seek_pos;
1177   }
1178
1179   return bdfile->seek_pos;
1180 }
1181
1182 int64_t udf25::GetFileSize(HANDLE hFile)
1183 {
1184   BD_FILE bdfile = (BD_FILE)hFile;
1185
1186   if(bdfile == NULL)
1187     return -1;
1188
1189   return bdfile->filesize;
1190 }
1191
1192 int64_t udf25::GetFilePosition(HANDLE hFile)
1193 {
1194   BD_FILE bdfile = (BD_FILE)hFile;
1195
1196   if(bdfile == NULL)
1197     return -1;
1198
1199   return bdfile->seek_pos;
1200 }
1201
1202 udf_dir_t *udf25::OpenDir( const char *subdir )
1203 {
1204   udf_dir_t *result;
1205   BD_FILE bd_file;
1206
1207   bd_file = (BD_FILE)OpenFile(subdir);
1208
1209   if (bd_file == (BD_FILE)INVALID_HANDLE_VALUE)
1210     return NULL;
1211
1212   result = (udf_dir_t *)calloc(1, sizeof(udf_dir_t));
1213   if (!result) {
1214     CloseFile((HANDLE)bd_file);
1215     return NULL;
1216   }
1217
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);
1222
1223   return result;
1224 }
1225
1226 udf_dirent_t *udf25::ReadDir( udf_dir_t *dirp )
1227 {
1228   if (!UDFScanDirX(dirp)) {
1229     dirp->current_p = 0;
1230     dirp->dir_current = dirp->dir_location; // this is a rewind, wanted?
1231     return NULL;
1232   }
1233
1234   return &dirp->entry;
1235 }
1236
1237 int udf25::CloseDir( udf_dir_t *dirp )
1238 {
1239   if (!dirp) return 0;
1240
1241   free(dirp);
1242
1243   CloseFile(NULL);
1244
1245   return 0;
1246 }