MythTV  0.26-pre
dvd_udf.c
Go to the documentation of this file.
00001 /*
00002  * This code is based on dvdudf by:
00003  *   Christian Wolff <scarabaeus@convergence.de>.
00004  *
00005  * Modifications by:
00006  *   Billy Biggs <vektor@dumbterm.net>.
00007  *   Björn Englund <d4bjorn@dtek.chalmers.se>.
00008  *
00009  * dvdudf: parse and read the UDF volume information of a DVD Video
00010  * Copyright (C) 1999 Christian Wolff for convergence integrated media
00011  * GmbH The author can be reached at scarabaeus@convergence.de, the
00012  * project's page is at http://linuxtv.org/dvd/
00013  *
00014  * This file is part of libdvdread.
00015  *
00016  * libdvdread is free software; you can redistribute it and/or modify
00017  * it under the terms of the GNU General Public License as published by
00018  * the Free Software Foundation; either version 2 of the License, or
00019  * (at your option) any later version.
00020  *
00021  * libdvdread is distributed in the hope that it will be useful,
00022  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00023  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00024  * GNU General Public License for more details.
00025  *
00026  * You should have received a copy of the GNU General Public License along
00027  * with libdvdread; if not, write to the Free Software Foundation, Inc.,
00028  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00029  */
00030 
00031 #include <stdio.h>
00032 #include <stdlib.h>
00033 #include <string.h>
00034 
00035 #include <sys/types.h>
00036 #include <sys/stat.h>
00037 #include <unistd.h>
00038 #include <inttypes.h>
00039 
00040 #include "dvdread_internal.h"
00041 #include "dvdread/dvd_reader.h"
00042 #include "dvdread/dvd_udf.h"
00043 
00044 /* It's required to either fail or deliver all the blocks asked for. */
00045 static int DVDReadLBUDF( dvd_reader_t *device, uint32_t lb_number,
00046                          size_t block_count, unsigned char *data,
00047                          int encrypted )
00048 {
00049   int ret;
00050   size_t count = block_count;
00051 
00052   while(count > 0) {
00053 
00054     ret = UDFReadBlocksRaw(device, lb_number, count, data, encrypted);
00055 
00056     if(ret <= 0) {
00057       /* One of the reads failed or nothing more to read, too bad.
00058        * We won't even bother returning the reads that went ok. */
00059       return ret;
00060     }
00061 
00062     count -= (size_t)ret;
00063     lb_number += (uint32_t)ret;
00064   }
00065 
00066   return block_count;
00067 }
00068 
00069 
00070 #ifndef NULL
00071 #define NULL ((void *)0)
00072 #endif
00073 
00074 struct Partition {
00075   int valid;
00076   char VolumeDesc[128];
00077   uint16_t Flags;
00078   uint16_t Number;
00079   char Contents[32];
00080   uint32_t AccessType;
00081   uint32_t Start;
00082   uint32_t Length;
00083 };
00084 
00085 struct AD {
00086   uint32_t Location;
00087   uint32_t Length;
00088   uint8_t  Flags;
00089   uint16_t Partition;
00090 };
00091 
00092 struct extent_ad {
00093   uint32_t location;
00094   uint32_t length;
00095 };
00096 
00097 struct avdp_t {
00098   struct extent_ad mvds;
00099   struct extent_ad rvds;
00100 };
00101 
00102 struct pvd_t {
00103   uint8_t VolumeIdentifier[32];
00104   uint8_t VolumeSetIdentifier[128];
00105 };
00106 
00107 struct lbudf {
00108   uint32_t lb;
00109   uint8_t *data;
00110   /* needed for proper freeing */
00111   uint8_t *data_base;
00112 };
00113 
00114 struct icbmap {
00115   uint32_t lbn;
00116   struct AD file;
00117   uint8_t filetype;
00118 };
00119 
00120 struct udf_cache {
00121   int avdp_valid;
00122   struct avdp_t avdp;
00123   int pvd_valid;
00124   struct pvd_t pvd;
00125   int partition_valid;
00126   struct Partition partition;
00127   int rooticb_valid;
00128   struct AD rooticb;
00129   int lb_num;
00130   struct lbudf *lbs;
00131   int map_num;
00132   struct icbmap *maps;
00133 };
00134 
00135 typedef enum {
00136   PartitionCache, RootICBCache, LBUDFCache, MapCache, AVDPCache, PVDCache
00137 } UDFCacheType;
00138 
00139 void FreeUDFCache(void *cache)
00140 {
00141   struct udf_cache *c = (struct udf_cache *)cache;
00142   if(c == NULL)
00143     return;
00144 
00145   if(c->lbs) {
00146     int n;
00147     for(n = 0; n < c->lb_num; n++)
00148       free(c->lbs[n].data_base);
00149     free(c->lbs);
00150   }
00151   if(c->maps)
00152     free(c->maps);
00153   free(c);
00154 }
00155 
00156 
00157 static int GetUDFCache(dvd_reader_t *device, UDFCacheType type,
00158                        uint32_t nr, void *data)
00159 {
00160   int n;
00161   struct udf_cache *c;
00162 
00163   if(DVDUDFCacheLevel(device, -1) <= 0)
00164     return 0;
00165 
00166   c = (struct udf_cache *)GetUDFCacheHandle(device);
00167 
00168   if(c == NULL)
00169     return 0;
00170 
00171   switch(type) {
00172   case AVDPCache:
00173     if(c->avdp_valid) {
00174       *(struct avdp_t *)data = c->avdp;
00175       return 1;
00176     }
00177     break;
00178   case PVDCache:
00179     if(c->pvd_valid) {
00180       *(struct pvd_t *)data = c->pvd;
00181       return 1;
00182     }
00183     break;
00184   case PartitionCache:
00185     if(c->partition_valid) {
00186       *(struct Partition *)data = c->partition;
00187       return 1;
00188     }
00189     break;
00190   case RootICBCache:
00191     if(c->rooticb_valid) {
00192       *(struct AD *)data = c->rooticb;
00193       return 1;
00194     }
00195     break;
00196   case LBUDFCache:
00197     for(n = 0; n < c->lb_num; n++) {
00198       if(c->lbs[n].lb == nr) {
00199         *(uint8_t **)data = c->lbs[n].data;
00200         return 1;
00201       }
00202     }
00203     break;
00204   case MapCache:
00205     for(n = 0; n < c->map_num; n++) {
00206       if(c->maps[n].lbn == nr) {
00207         *(struct icbmap *)data = c->maps[n];
00208         return 1;
00209       }
00210     }
00211     break;
00212   default:
00213     break;
00214   }
00215 
00216   return 0;
00217 }
00218 
00219 static int SetUDFCache(dvd_reader_t *device, UDFCacheType type,
00220                        uint32_t nr, void *data)
00221 {
00222   int n;
00223   struct udf_cache *c;
00224   void *tmp;
00225 
00226   if(DVDUDFCacheLevel(device, -1) <= 0)
00227     return 0;
00228 
00229   c = (struct udf_cache *)GetUDFCacheHandle(device);
00230 
00231   if(c == NULL) {
00232     c = calloc(1, sizeof(struct udf_cache));
00233     /* fprintf(stderr, "calloc: %d\n", sizeof(struct udf_cache)); */
00234     if(c == NULL)
00235       return 0;
00236     SetUDFCacheHandle(device, c);
00237   }
00238 
00239 
00240   switch(type) {
00241   case AVDPCache:
00242     c->avdp = *(struct avdp_t *)data;
00243     c->avdp_valid = 1;
00244     break;
00245   case PVDCache:
00246     c->pvd = *(struct pvd_t *)data;
00247     c->pvd_valid = 1;
00248     break;
00249   case PartitionCache:
00250     c->partition = *(struct Partition *)data;
00251     c->partition_valid = 1;
00252     break;
00253   case RootICBCache:
00254     c->rooticb = *(struct AD *)data;
00255     c->rooticb_valid = 1;
00256     break;
00257   case LBUDFCache:
00258     for(n = 0; n < c->lb_num; n++) {
00259       if(c->lbs[n].lb == nr) {
00260         /* replace with new data */
00261         c->lbs[n].data_base = ((uint8_t **)data)[0];
00262         c->lbs[n].data = ((uint8_t **)data)[1];
00263         c->lbs[n].lb = nr;
00264         return 1;
00265       }
00266     }
00267     c->lb_num++;
00268     tmp = realloc(c->lbs, c->lb_num * sizeof(struct lbudf));
00269     /*
00270     fprintf(stderr, "realloc lb: %d * %d = %d\n",
00271     c->lb_num, sizeof(struct lbudf),
00272     c->lb_num * sizeof(struct lbudf));
00273     */
00274     if(tmp == NULL) {
00275       if(c->lbs) free(c->lbs);
00276       c->lb_num = 0;
00277       return 0;
00278     }
00279     c->lbs = tmp;
00280     c->lbs[n].data_base = ((uint8_t **)data)[0];
00281     c->lbs[n].data = ((uint8_t **)data)[1];
00282     c->lbs[n].lb = nr;
00283     break;
00284   case MapCache:
00285     for(n = 0; n < c->map_num; n++) {
00286       if(c->maps[n].lbn == nr) {
00287         /* replace with new data */
00288         c->maps[n] = *(struct icbmap *)data;
00289         c->maps[n].lbn = nr;
00290         return 1;
00291       }
00292     }
00293     c->map_num++;
00294     tmp = realloc(c->maps, c->map_num * sizeof(struct icbmap));
00295     /*
00296     fprintf(stderr, "realloc maps: %d * %d = %d\n",
00297       c->map_num, sizeof(struct icbmap),
00298       c->map_num * sizeof(struct icbmap));
00299     */
00300     if(tmp == NULL) {
00301       if(c->maps) free(c->maps);
00302       c->map_num = 0;
00303       return 0;
00304     }
00305     c->maps = tmp;
00306     c->maps[n] = *(struct icbmap *)data;
00307     c->maps[n].lbn = nr;
00308     break;
00309   default:
00310     return 0;
00311   }
00312 
00313   return 1;
00314 }
00315 
00316 
00317 /* For direct data access, LSB first */
00318 #define GETN1(p) ((uint8_t)data[p])
00319 #define GETN2(p) ((uint16_t)data[p] | ((uint16_t)data[(p) + 1] << 8))
00320 #define GETN3(p) ((uint32_t)data[p] | ((uint32_t)data[(p) + 1] << 8)    \
00321                   | ((uint32_t)data[(p) + 2] << 16))
00322 #define GETN4(p) ((uint32_t)data[p]                     \
00323                   | ((uint32_t)data[(p) + 1] << 8)      \
00324                   | ((uint32_t)data[(p) + 2] << 16)     \
00325                   | ((uint32_t)data[(p) + 3] << 24))
00326 /* This is wrong with regard to endianess */
00327 #define GETN(p, n, target) memcpy(target, &data[p], n)
00328 
00329 static int Unicodedecode( uint8_t *data, int len, char *target )
00330 {
00331   int p = 1, i = 0;
00332   int err = 0;
00333 
00334   if( ( data[ 0 ] == 8 ) || ( data[ 0 ] == 16 ) ) do {
00335     if( data[ 0 ] == 16 ) err |= data[p++];  /* character cannot be converted to 8bit, return error */
00336     if( p < len ) {
00337       target[ i++ ] = data[ p++ ];
00338     }
00339   } while( p < len );
00340 
00341   target[ i ] = '\0';
00342   return !err;
00343 }
00344 
00345 static int UDFDescriptor( uint8_t *data, uint16_t *TagID )
00346 {
00347   *TagID = GETN2(0);
00348   /* TODO: check CRC 'n stuff */
00349   return 0;
00350 }
00351 
00352 static int UDFExtentAD( uint8_t *data, uint32_t *Length, uint32_t *Location )
00353 {
00354   *Length   = GETN4(0);
00355   *Location = GETN4(4);
00356   return 0;
00357 }
00358 
00359 static int UDFShortAD( uint8_t *data, struct AD *ad,
00360                        struct Partition *partition )
00361 {
00362   ad->Length = GETN4(0);
00363   ad->Flags = ad->Length >> 30;
00364   ad->Length &= 0x3FFFFFFF;
00365   ad->Location = GETN4(4);
00366   ad->Partition = partition->Number; /* use number of current partition */
00367   return 0;
00368 }
00369 
00370 static int UDFLongAD( uint8_t *data, struct AD *ad )
00371 {
00372   ad->Length = GETN4(0);
00373   ad->Flags = ad->Length >> 30;
00374   ad->Length &= 0x3FFFFFFF;
00375   ad->Location = GETN4(4);
00376   ad->Partition = GETN2(8);
00377   /* GETN(10, 6, Use); */
00378   return 0;
00379 }
00380 
00381 static int UDFExtAD( uint8_t *data, struct AD *ad )
00382 {
00383   ad->Length = GETN4(0);
00384   ad->Flags = ad->Length >> 30;
00385   ad->Length &= 0x3FFFFFFF;
00386   ad->Location = GETN4(12);
00387   ad->Partition = GETN2(16);
00388   /* GETN(10, 6, Use); */
00389   return 0;
00390 }
00391 
00392 static int UDFICB( uint8_t *data, uint8_t *FileType, uint16_t *Flags )
00393 {
00394   *FileType = GETN1(11);
00395   *Flags = GETN2(18);
00396   return 0;
00397 }
00398 
00399 
00400 static int UDFPartition( uint8_t *data, uint16_t *Flags, uint16_t *Number,
00401                          char *Contents, uint32_t *Start, uint32_t *Length )
00402 {
00403   *Flags = GETN2(20);
00404   *Number = GETN2(22);
00405   GETN(24, 32, Contents);
00406   *Start = GETN4(188);
00407   *Length = GETN4(192);
00408   return 0;
00409 }
00410 
00415 static int UDFLogVolume( uint8_t *data, char *VolumeDescriptor )
00416 {
00417   uint32_t lbsize, MT_L, N_PM;
00418   Unicodedecode(&data[84], 128, VolumeDescriptor);
00419   lbsize = GETN4(212);  /* should be 2048 */
00420   MT_L = GETN4(264);    /* should be 6 */
00421   N_PM = GETN4(268);    /* should be 1 */
00422   if (lbsize != DVD_VIDEO_LB_LEN) return 1;
00423   return 0;
00424 }
00425 
00426 static int UDFFileEntry( uint8_t *data, uint8_t *FileType,
00427                          struct Partition *partition, struct AD *ad )
00428 {
00429   uint16_t flags;
00430   uint32_t L_EA, L_AD;
00431   unsigned int p;
00432 
00433   UDFICB( &data[ 16 ], FileType, &flags );
00434 
00435   /* Init ad for an empty file (i.e. there isn't a AD, L_AD == 0 ) */
00436   ad->Length = GETN4( 60 ); /* Really 8 bytes a 56 */
00437   ad->Flags = 0;
00438   ad->Location = 0; /* what should we put here?  */
00439   ad->Partition = partition->Number; /* use number of current partition */
00440 
00441   L_EA = GETN4( 168 );
00442   L_AD = GETN4( 172 );
00443 
00444   if (176 + L_EA + L_AD > DVD_VIDEO_LB_LEN)
00445     return 0;
00446 
00447   p = 176 + L_EA;
00448   while( p < 176 + L_EA + L_AD ) {
00449     switch( flags & 0x0007 ) {
00450     case 0:
00451       UDFShortAD( &data[ p ], ad, partition );
00452       p += 8;
00453       break;
00454     case 1:
00455       UDFLongAD( &data[ p ], ad );
00456       p += 16;
00457       break;
00458     case 2:
00459       UDFExtAD( &data[ p ], ad );
00460       p += 20;
00461       break;
00462     case 3:
00463       switch( L_AD ) {
00464       case 8:
00465         UDFShortAD( &data[ p ], ad, partition );
00466         break;
00467       case 16:
00468         UDFLongAD( &data[ p ], ad );
00469         break;
00470       case 20:
00471         UDFExtAD( &data[ p ], ad );
00472         break;
00473       }
00474       p += L_AD;
00475       break;
00476     default:
00477       p += L_AD;
00478       break;
00479     }
00480   }
00481   return 0;
00482 }
00483 
00484 static int UDFFileIdentifier( uint8_t *data, uint8_t *FileCharacteristics,
00485                               char *FileName, struct AD *FileICB )
00486 {
00487   uint8_t L_FI;
00488   uint16_t L_IU;
00489 
00490   *FileCharacteristics = GETN1(18);
00491   L_FI = GETN1(19);
00492   UDFLongAD(&data[20], FileICB);
00493   L_IU = GETN2(36);
00494   if (L_FI) {
00495     if (!Unicodedecode(&data[38 + L_IU], L_FI, FileName)) FileName[0] = 0;
00496   } else FileName[0] = '\0';
00497   return 4 * ((38 + L_FI + L_IU + 3) / 4);
00498 }
00499 
00507 static int UDFMapICB( dvd_reader_t *device, struct AD ICB, uint8_t *FileType,
00508                       struct Partition *partition, struct AD *File )
00509 {
00510   uint8_t LogBlock_base[DVD_VIDEO_LB_LEN + 2048];
00511   uint8_t *LogBlock = (uint8_t *)(((uintptr_t)LogBlock_base & ~((uintptr_t)2047)) + 2048);
00512   uint32_t lbnum;
00513   uint16_t TagID;
00514   struct icbmap tmpmap;
00515 
00516   lbnum = partition->Start + ICB.Location;
00517   tmpmap.lbn = lbnum;
00518   if(GetUDFCache(device, MapCache, lbnum, &tmpmap)) {
00519     *FileType = tmpmap.filetype;
00520     memcpy(File, &tmpmap.file, sizeof(tmpmap.file));
00521     return 1;
00522   }
00523 
00524   do {
00525     if( DVDReadLBUDF( device, lbnum++, 1, LogBlock, 0 ) <= 0 )
00526       TagID = 0;
00527     else
00528       UDFDescriptor( LogBlock, &TagID );
00529 
00530     if( TagID == 261 ) {
00531       UDFFileEntry( LogBlock, FileType, partition, File );
00532       memcpy(&tmpmap.file, File, sizeof(tmpmap.file));
00533       tmpmap.filetype = *FileType;
00534       SetUDFCache(device, MapCache, tmpmap.lbn, &tmpmap);
00535       return 1;
00536     };
00537   } while( ( lbnum <= partition->Start + ICB.Location + ( ICB.Length - 1 )
00538              / DVD_VIDEO_LB_LEN ) && ( TagID != 261 ) );
00539 
00540   return 0;
00541 }
00542 
00549 static int UDFScanDir( dvd_reader_t *device, struct AD Dir, char *FileName,
00550                        struct Partition *partition, struct AD *FileICB,
00551                        int cache_file_info)
00552 {
00553   char filename[ MAX_UDF_FILE_NAME_LEN ];
00554   uint8_t directory_base[ 2 * DVD_VIDEO_LB_LEN + 2048];
00555   uint8_t *directory = (uint8_t *)(((uintptr_t)directory_base & ~((uintptr_t)2047)) + 2048);
00556   uint32_t lbnum;
00557   uint16_t TagID;
00558   uint8_t filechar;
00559   unsigned int p;
00560   uint8_t *cached_dir_base = NULL, *cached_dir;
00561   uint32_t dir_lba;
00562   struct AD tmpICB;
00563   int found = 0;
00564   int in_cache = 0;
00565 
00566   /* Scan dir for ICB of file */
00567   lbnum = partition->Start + Dir.Location;
00568 
00569   if(DVDUDFCacheLevel(device, -1) > 0) {
00570     /* caching */
00571 
00572     if(!GetUDFCache(device, LBUDFCache, lbnum, &cached_dir)) {
00573       dir_lba = (Dir.Length + DVD_VIDEO_LB_LEN) / DVD_VIDEO_LB_LEN;
00574       if((cached_dir_base = malloc(dir_lba * DVD_VIDEO_LB_LEN + 2048)) == NULL)
00575         return 0;
00576       cached_dir = (uint8_t *)(((uintptr_t)cached_dir_base & ~((uintptr_t)2047)) + 2048);
00577       if( DVDReadLBUDF( device, lbnum, dir_lba, cached_dir, 0) <= 0 ) {
00578         free(cached_dir_base);
00579         cached_dir_base = NULL;
00580         cached_dir = NULL;
00581       }
00582       /*
00583       if(cached_dir) {
00584         fprintf(stderr, "malloc dir: %d\n",  dir_lba * DVD_VIDEO_LB_LEN);
00585       }
00586       */
00587       {
00588         uint8_t *data[2];
00589         data[0] = cached_dir_base;
00590         data[1] = cached_dir;
00591         SetUDFCache(device, LBUDFCache, lbnum, data);
00592       }
00593     } else
00594       in_cache = 1;
00595 
00596     if(cached_dir == NULL)
00597       return 0;
00598 
00599     p = 0;
00600 
00601     while( p < Dir.Length ) {
00602       UDFDescriptor( &cached_dir[ p ], &TagID );
00603       if( TagID == 257 ) {
00604         p += UDFFileIdentifier( &cached_dir[ p ], &filechar,
00605                                 filename, &tmpICB );
00606         if(cache_file_info && !in_cache) {
00607           uint8_t tmpFiletype;
00608           struct AD tmpFile;
00609 
00610           if( !strcasecmp( FileName, filename ) ) {
00611             memcpy(FileICB, &tmpICB, sizeof(tmpICB));
00612             found = 1;
00613           }
00614           UDFMapICB(device, tmpICB, &tmpFiletype, partition, &tmpFile);
00615         } else {
00616           if( !strcasecmp( FileName, filename ) ) {
00617             memcpy(FileICB, &tmpICB, sizeof(tmpICB));
00618             return 1;
00619           }
00620         }
00621       } else {
00622         if(cache_file_info && (!in_cache) && found)
00623           return 1;
00624         return 0;
00625       }
00626     }
00627     if(cache_file_info && (!in_cache) && found)
00628       return 1;
00629     return 0;
00630   }
00631 
00632   if( DVDReadLBUDF( device, lbnum, 2, directory, 0 ) <= 0 )
00633     return 0;
00634 
00635   p = 0;
00636   while( p < Dir.Length ) {
00637     if( p > DVD_VIDEO_LB_LEN ) {
00638       ++lbnum;
00639       p -= DVD_VIDEO_LB_LEN;
00640       Dir.Length -= DVD_VIDEO_LB_LEN;
00641       if( DVDReadLBUDF( device, lbnum, 2, directory, 0 ) <= 0 ) {
00642         return 0;
00643       }
00644     }
00645     UDFDescriptor( &directory[ p ], &TagID );
00646     if( TagID == 257 ) {
00647       p += UDFFileIdentifier( &directory[ p ], &filechar,
00648                               filename, FileICB );
00649       if( !strcasecmp( FileName, filename ) ) {
00650         return 1;
00651       }
00652     } else
00653       return 0;
00654   }
00655 
00656   return 0;
00657 }
00658 
00659 
00660 static int UDFGetAVDP( dvd_reader_t *device,
00661                        struct avdp_t *avdp)
00662 {
00663   uint8_t Anchor_base[ DVD_VIDEO_LB_LEN + 2048 ];
00664   uint8_t *Anchor = (uint8_t *)(((uintptr_t)Anchor_base & ~((uintptr_t)2047)) + 2048);
00665   uint32_t lbnum, MVDS_location, MVDS_length;
00666   uint16_t TagID;
00667   uint32_t lastsector;
00668   int terminate;
00669   struct avdp_t;
00670 
00671   if(GetUDFCache(device, AVDPCache, 0, avdp))
00672     return 1;
00673 
00674   /* Find Anchor */
00675   lastsector = 0;
00676   lbnum = 256;   /* Try #1, prime anchor */
00677   terminate = 0;
00678 
00679   for(;;) {
00680     if( DVDReadLBUDF( device, lbnum, 1, Anchor, 0 ) > 0 ) {
00681       UDFDescriptor( Anchor, &TagID );
00682     } else {
00683       TagID = 0;
00684     }
00685     if (TagID != 2) {
00686       /* Not an anchor */
00687       if( terminate ) return 0; /* Final try failed */
00688 
00689       if( lastsector ) {
00690         /* We already found the last sector.  Try #3, alternative
00691          * backup anchor.  If that fails, don't try again.
00692          */
00693         lbnum = lastsector;
00694         terminate = 1;
00695       } else {
00696         /* TODO: Find last sector of the disc (this is optional). */
00697         if( lastsector )
00698           /* Try #2, backup anchor */
00699           lbnum = lastsector - 256;
00700         else
00701           /* Unable to find last sector */
00702           return 0;
00703       }
00704     } else
00705       /* It's an anchor! We can leave */
00706       break;
00707   }
00708   /* Main volume descriptor */
00709   UDFExtentAD( &Anchor[ 16 ], &MVDS_length, &MVDS_location );
00710   avdp->mvds.location = MVDS_location;
00711   avdp->mvds.length = MVDS_length;
00712 
00713   /* Backup volume descriptor */
00714   UDFExtentAD( &Anchor[ 24 ], &MVDS_length, &MVDS_location );
00715   avdp->rvds.location = MVDS_location;
00716   avdp->rvds.length = MVDS_length;
00717 
00718   SetUDFCache(device, AVDPCache, 0, avdp);
00719 
00720   return 1;
00721 }
00722 
00728 static int UDFFindPartition( dvd_reader_t *device, int partnum,
00729                              struct Partition *part )
00730 {
00731   uint8_t LogBlock_base[ DVD_VIDEO_LB_LEN + 2048 ];
00732   uint8_t *LogBlock = (uint8_t *)(((uintptr_t)LogBlock_base & ~((uintptr_t)2047)) + 2048);
00733   uint32_t lbnum, MVDS_location, MVDS_length;
00734   uint16_t TagID;
00735   int i, volvalid;
00736   struct avdp_t avdp;
00737 
00738   if(!UDFGetAVDP(device, &avdp))
00739     return 0;
00740 
00741   /* Main volume descriptor */
00742   MVDS_location = avdp.mvds.location;
00743   MVDS_length = avdp.mvds.length;
00744 
00745   part->valid = 0;
00746   volvalid = 0;
00747   part->VolumeDesc[ 0 ] = '\0';
00748   i = 1;
00749   do {
00750     /* Find Volume Descriptor */
00751     lbnum = MVDS_location;
00752     do {
00753 
00754       if( DVDReadLBUDF( device, lbnum++, 1, LogBlock, 0 ) <= 0 )
00755         TagID = 0;
00756       else
00757         UDFDescriptor( LogBlock, &TagID );
00758 
00759       if( ( TagID == 5 ) && ( !part->valid ) ) {
00760         /* Partition Descriptor */
00761         UDFPartition( LogBlock, &part->Flags, &part->Number,
00762                       part->Contents, &part->Start, &part->Length );
00763         part->valid = ( partnum == part->Number );
00764       } else if( ( TagID == 6 ) && ( !volvalid ) ) {
00765         /* Logical Volume Descriptor */
00766         if( UDFLogVolume( LogBlock, part->VolumeDesc ) ) {
00767           /* TODO: sector size wrong! */
00768         } else
00769           volvalid = 1;
00770       }
00771 
00772     } while( ( lbnum <= MVDS_location + ( MVDS_length - 1 )
00773                / DVD_VIDEO_LB_LEN ) && ( TagID != 8 )
00774              && ( ( !part->valid ) || ( !volvalid ) ) );
00775 
00776     if( ( !part->valid) || ( !volvalid ) ) {
00777       /* Backup volume descriptor */
00778       MVDS_location = avdp.mvds.location;
00779       MVDS_length = avdp.mvds.length;
00780     }
00781   } while( i-- && ( ( !part->valid ) || ( !volvalid ) ) );
00782 
00783   /* We only care for the partition, not the volume */
00784   return part->valid;
00785 }
00786 
00787 uint32_t UDFFindFile( dvd_reader_t *device, char *filename,
00788                       uint32_t *filesize )
00789 {
00790   uint8_t LogBlock_base[ DVD_VIDEO_LB_LEN + 2048 ];
00791   uint8_t *LogBlock = (uint8_t *)(((uintptr_t)LogBlock_base & ~((uintptr_t)2047)) + 2048);
00792   uint32_t lbnum;
00793   uint16_t TagID;
00794   struct Partition partition;
00795   struct AD RootICB, File, ICB;
00796   char tokenline[ MAX_UDF_FILE_NAME_LEN ];
00797   char *token;
00798   uint8_t filetype;
00799 
00800   *filesize = 0;
00801   tokenline[0] = '\0';
00802   strncat(tokenline, filename, MAX_UDF_FILE_NAME_LEN - 1);
00803   memset(&ICB, 0, sizeof(ICB));
00804 
00805   if(!(GetUDFCache(device, PartitionCache, 0, &partition) &&
00806        GetUDFCache(device, RootICBCache, 0, &RootICB))) {
00807     /* Find partition, 0 is the standard location for DVD Video.*/
00808     if( !UDFFindPartition( device, 0, &partition ) ) return 0;
00809     SetUDFCache(device, PartitionCache, 0, &partition);
00810 
00811     /* Find root dir ICB */
00812     lbnum = partition.Start;
00813     do {
00814       if( DVDReadLBUDF( device, lbnum++, 1, LogBlock, 0 ) <= 0 )
00815         TagID = 0;
00816       else
00817         UDFDescriptor( LogBlock, &TagID );
00818 
00819       /* File Set Descriptor */
00820       if( TagID == 256 )  /* File Set Descriptor */
00821         UDFLongAD( &LogBlock[ 400 ], &RootICB );
00822     } while( ( lbnum < partition.Start + partition.Length )
00823              && ( TagID != 8 ) && ( TagID != 256 ) );
00824 
00825     /* Sanity checks. */
00826     if( TagID != 256 )
00827       return 0;
00828     if( RootICB.Partition != 0 )
00829       return 0;
00830     SetUDFCache(device, RootICBCache, 0, &RootICB);
00831   }
00832 
00833   /* Find root dir */
00834   if( !UDFMapICB( device, RootICB, &filetype, &partition, &File ) )
00835     return 0;
00836   if( filetype != 4 )
00837     return 0;  /* Root dir should be dir */
00838   {
00839     int cache_file_info = 0;
00840     /* Tokenize filepath */
00841     token = strtok(tokenline, "/");
00842 
00843     while( token != NULL ) {
00844       if( !UDFScanDir( device, File, token, &partition, &ICB,
00845                        cache_file_info))
00846         return 0;
00847       if( !UDFMapICB( device, ICB, &filetype, &partition, &File ) )
00848         return 0;
00849       if(!strcmp(token, "VIDEO_TS"))
00850         cache_file_info = 1;
00851       token = strtok( NULL, "/" );
00852     }
00853   }
00854 
00855   /* Sanity check. */
00856   if( File.Partition != 0 )
00857     return 0;
00858   *filesize = File.Length;
00859   /* Hack to not return partition.Start for empty files. */
00860   if( !File.Location )
00861     return 0;
00862   else
00863     return partition.Start + File.Location;
00864 }
00865 
00866 
00867 
00874 static int UDFGetDescriptor( dvd_reader_t *device, int id,
00875                              uint8_t *descriptor, int bufsize)
00876 {
00877   uint32_t lbnum, MVDS_location, MVDS_length;
00878   struct avdp_t avdp;
00879   uint16_t TagID;
00880   uint32_t lastsector;
00881   int i, terminate;
00882   int desc_found = 0;
00883   /* Find Anchor */
00884   lastsector = 0;
00885   lbnum = 256;   /* Try #1, prime anchor */
00886   terminate = 0;
00887   if(bufsize < DVD_VIDEO_LB_LEN)
00888     return 0;
00889 
00890   if(!UDFGetAVDP(device, &avdp))
00891     return 0;
00892 
00893   /* Main volume descriptor */
00894   MVDS_location = avdp.mvds.location;
00895   MVDS_length = avdp.mvds.length;
00896 
00897   i = 1;
00898   do {
00899     /* Find  Descriptor */
00900     lbnum = MVDS_location;
00901     do {
00902       if( DVDReadLBUDF( device, lbnum++, 1, descriptor, 0 ) <= 0 )
00903         TagID = 0;
00904       else
00905         UDFDescriptor( descriptor, &TagID );
00906       if( (TagID == id) && ( !desc_found ) )
00907         /* Descriptor */
00908         desc_found = 1;
00909     } while( ( lbnum <= MVDS_location + ( MVDS_length - 1 )
00910                / DVD_VIDEO_LB_LEN ) && ( TagID != 8 )
00911              && ( !desc_found) );
00912 
00913     if( !desc_found ) {
00914       /* Backup volume descriptor */
00915       MVDS_location = avdp.rvds.location;
00916       MVDS_length = avdp.rvds.length;
00917     }
00918   } while( i-- && ( !desc_found )  );
00919 
00920   return desc_found;
00921 }
00922 
00923 
00924 static int UDFGetPVD(dvd_reader_t *device, struct pvd_t *pvd)
00925 {
00926   uint8_t pvd_buf_base[DVD_VIDEO_LB_LEN + 2048];
00927   uint8_t *pvd_buf = (uint8_t *)(((uintptr_t)pvd_buf_base & ~((uintptr_t)2047)) + 2048);
00928   if(GetUDFCache(device, PVDCache, 0, pvd))
00929     return 1;
00930 
00931   if(!UDFGetDescriptor( device, 1, pvd_buf, DVD_VIDEO_LB_LEN))
00932     return 0;
00933 
00934   memcpy(pvd->VolumeIdentifier, &pvd_buf[24], 32);
00935   memcpy(pvd->VolumeSetIdentifier, &pvd_buf[72], 128);
00936   SetUDFCache(device, PVDCache, 0, pvd);
00937   return 1;
00938 }
00939 
00946 int UDFGetVolumeIdentifier(dvd_reader_t *device, char *volid,
00947                            unsigned int volid_size)
00948 {
00949   struct pvd_t pvd;
00950   unsigned int volid_len;
00951 
00952   /* get primary volume descriptor */
00953   if(!UDFGetPVD(device, &pvd))
00954     return 0;
00955 
00956   volid_len = pvd.VolumeIdentifier[31];
00957   if(volid_len > 31)
00958     /* this field is only 32 bytes something is wrong */
00959     volid_len = 31;
00960   if(volid_size > volid_len)
00961     volid_size = volid_len;
00962   Unicodedecode(pvd.VolumeIdentifier, volid_size, volid);
00963 
00964   return volid_len;
00965 }
00966 
00976 int UDFGetVolumeSetIdentifier(dvd_reader_t *device, uint8_t *volsetid,
00977                               unsigned int volsetid_size)
00978 {
00979   struct pvd_t pvd;
00980 
00981   /* get primary volume descriptor */
00982   if(!UDFGetPVD(device, &pvd))
00983     return 0;
00984 
00985 
00986   if(volsetid_size > 128)
00987     volsetid_size = 128;
00988 
00989   memcpy(volsetid, pvd.VolumeSetIdentifier, volsetid_size);
00990 
00991   return 128;
00992 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends