00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
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
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
00058
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
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
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
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
00271
00272
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
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
00297
00298
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
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
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++];
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
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;
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
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
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);
00420 MT_L = GETN4(264);
00421 N_PM = GETN4(268);
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
00436 ad->Length = GETN4( 60 );
00437 ad->Flags = 0;
00438 ad->Location = 0;
00439 ad->Partition = partition->Number;
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
00567 lbnum = partition->Start + Dir.Location;
00568
00569 if(DVDUDFCacheLevel(device, -1) > 0) {
00570
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
00584
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
00675 lastsector = 0;
00676 lbnum = 256;
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
00687 if( terminate ) return 0;
00688
00689 if( lastsector ) {
00690
00691
00692
00693 lbnum = lastsector;
00694 terminate = 1;
00695 } else {
00696
00697 if( lastsector )
00698
00699 lbnum = lastsector - 256;
00700 else
00701
00702 return 0;
00703 }
00704 } else
00705
00706 break;
00707 }
00708
00709 UDFExtentAD( &Anchor[ 16 ], &MVDS_length, &MVDS_location );
00710 avdp->mvds.location = MVDS_location;
00711 avdp->mvds.length = MVDS_length;
00712
00713
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
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
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
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
00766 if( UDFLogVolume( LogBlock, part->VolumeDesc ) ) {
00767
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
00778 MVDS_location = avdp.mvds.location;
00779 MVDS_length = avdp.mvds.length;
00780 }
00781 } while( i-- && ( ( !part->valid ) || ( !volvalid ) ) );
00782
00783
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
00808 if( !UDFFindPartition( device, 0, &partition ) ) return 0;
00809 SetUDFCache(device, PartitionCache, 0, &partition);
00810
00811
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
00820 if( TagID == 256 )
00821 UDFLongAD( &LogBlock[ 400 ], &RootICB );
00822 } while( ( lbnum < partition.Start + partition.Length )
00823 && ( TagID != 8 ) && ( TagID != 256 ) );
00824
00825
00826 if( TagID != 256 )
00827 return 0;
00828 if( RootICB.Partition != 0 )
00829 return 0;
00830 SetUDFCache(device, RootICBCache, 0, &RootICB);
00831 }
00832
00833
00834 if( !UDFMapICB( device, RootICB, &filetype, &partition, &File ) )
00835 return 0;
00836 if( filetype != 4 )
00837 return 0;
00838 {
00839 int cache_file_info = 0;
00840
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
00856 if( File.Partition != 0 )
00857 return 0;
00858 *filesize = File.Length;
00859
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
00884 lastsector = 0;
00885 lbnum = 256;
00886 terminate = 0;
00887 if(bufsize < DVD_VIDEO_LB_LEN)
00888 return 0;
00889
00890 if(!UDFGetAVDP(device, &avdp))
00891 return 0;
00892
00893
00894 MVDS_location = avdp.mvds.location;
00895 MVDS_length = avdp.mvds.length;
00896
00897 i = 1;
00898 do {
00899
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
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
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
00953 if(!UDFGetPVD(device, &pvd))
00954 return 0;
00955
00956 volid_len = pvd.VolumeIdentifier[31];
00957 if(volid_len > 31)
00958
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
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 }