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 "config.h"
00032
00033 #include <stdio.h>
00034 #include <stdlib.h>
00035 #include <string.h>
00036
00037 #include <sys/types.h>
00038 #include <sys/stat.h>
00039 #include <unistd.h>
00040 #include <inttypes.h>
00041
00042 #include "dvd_reader.h"
00043 #include "dvd_udf.h"
00044
00045
00046 extern int UDFReadBlocksRaw( dvd_reader_t *device, uint32_t lb_number,
00047 size_t block_count, unsigned char *data,
00048 int encrypted );
00049
00050
00051 static int DVDReadLBUDF( dvd_reader_t *device, uint32_t lb_number,
00052 size_t block_count, unsigned char *data,
00053 int encrypted )
00054 {
00055 int ret;
00056 size_t count = block_count;
00057
00058 while(count > 0) {
00059
00060 ret = UDFReadBlocksRaw(device, lb_number, count, data, encrypted);
00061
00062 if(ret <= 0) {
00063
00064
00065 return ret;
00066 }
00067
00068 count -= (size_t)ret;
00069 lb_number += (uint32_t)ret;
00070 }
00071
00072 return block_count;
00073 }
00074
00075
00076 #ifndef NULL
00077 #define NULL ((void *)0)
00078 #endif
00079
00080 struct Partition {
00081 int valid;
00082 char VolumeDesc[128];
00083 uint16_t Flags;
00084 uint16_t Number;
00085 char Contents[32];
00086 uint32_t AccessType;
00087 uint32_t Start;
00088 uint32_t Length;
00089 };
00090
00091 struct AD {
00092 uint32_t Location;
00093 uint32_t Length;
00094 uint8_t Flags;
00095 uint16_t Partition;
00096 };
00097
00098 struct extent_ad {
00099 uint32_t location;
00100 uint32_t length;
00101 };
00102
00103 struct avdp_t {
00104 struct extent_ad mvds;
00105 struct extent_ad rvds;
00106 };
00107
00108 struct pvd_t {
00109 uint8_t VolumeIdentifier[32];
00110 uint8_t VolumeSetIdentifier[128];
00111 };
00112
00113 struct lbudf {
00114 uint32_t lb;
00115 uint8_t *data;
00116 };
00117
00118 struct icbmap {
00119 uint32_t lbn;
00120 struct AD file;
00121 uint8_t filetype;
00122 };
00123
00124 struct udf_cache {
00125 int avdp_valid;
00126 struct avdp_t avdp;
00127 int pvd_valid;
00128 struct pvd_t pvd;
00129 int partition_valid;
00130 struct Partition partition;
00131 int rooticb_valid;
00132 struct AD rooticb;
00133 int lb_num;
00134 struct lbudf *lbs;
00135 int map_num;
00136 struct icbmap *maps;
00137 };
00138
00139 typedef enum {
00140 PartitionCache, RootICBCache, LBUDFCache, MapCache, AVDPCache, PVDCache
00141 } UDFCacheType;
00142
00143 void FreeUDFCache(void *cache)
00144 {
00145 struct udf_cache *c = (struct udf_cache *)cache;
00146 if(c == NULL) {
00147 return;
00148 }
00149 if(c->lbs) {
00150 free(c->lbs);
00151 }
00152 if(c->maps) {
00153 free(c->maps);
00154 }
00155 free(c);
00156 }
00157
00158
00159 static int GetUDFCache(dvd_reader_t *device, UDFCacheType type,
00160 uint32_t nr, void *data)
00161 {
00162 int n;
00163 struct udf_cache *c;
00164
00165 if(DVDUDFCacheLevel(device, -1) <= 0) {
00166 return 0;
00167 }
00168
00169 c = (struct udf_cache *)GetUDFCacheHandle(device);
00170
00171 if(c == NULL) {
00172 return 0;
00173 }
00174
00175 switch(type) {
00176 case AVDPCache:
00177 if(c->avdp_valid) {
00178 *(struct avdp_t *)data = c->avdp;
00179 return 1;
00180 }
00181 break;
00182 case PVDCache:
00183 if(c->pvd_valid) {
00184 *(struct pvd_t *)data = c->pvd;
00185 return 1;
00186 }
00187 break;
00188 case PartitionCache:
00189 if(c->partition_valid) {
00190 *(struct Partition *)data = c->partition;
00191 return 1;
00192 }
00193 break;
00194 case RootICBCache:
00195 if(c->rooticb_valid) {
00196 *(struct AD *)data = c->rooticb;
00197 return 1;
00198 }
00199 break;
00200 case LBUDFCache:
00201 for(n = 0; n < c->lb_num; n++) {
00202 if(c->lbs[n].lb == nr) {
00203 *(uint8_t **)data = c->lbs[n].data;
00204 return 1;
00205 }
00206 }
00207 break;
00208 case MapCache:
00209 for(n = 0; n < c->map_num; n++) {
00210 if(c->maps[n].lbn == nr) {
00211 *(struct icbmap *)data = c->maps[n];
00212 return 1;
00213 }
00214 }
00215 break;
00216 default:
00217 break;
00218 }
00219
00220 return 0;
00221 }
00222
00223 static int SetUDFCache(dvd_reader_t *device, UDFCacheType type,
00224 uint32_t nr, void *data)
00225 {
00226 int n;
00227 struct udf_cache *c;
00228
00229 if(DVDUDFCacheLevel(device, -1) <= 0) {
00230 return 0;
00231 }
00232
00233 c = (struct udf_cache *)GetUDFCacheHandle(device);
00234
00235 if(c == NULL) {
00236 c = calloc(1, sizeof(struct udf_cache));
00237
00238 if(c == NULL) {
00239 return 0;
00240 }
00241 SetUDFCacheHandle(device, c);
00242 }
00243
00244
00245 switch(type) {
00246 case AVDPCache:
00247 c->avdp = *(struct avdp_t *)data;
00248 c->avdp_valid = 1;
00249 break;
00250 case PVDCache:
00251 c->pvd = *(struct pvd_t *)data;
00252 c->pvd_valid = 1;
00253 break;
00254 case PartitionCache:
00255 c->partition = *(struct Partition *)data;
00256 c->partition_valid = 1;
00257 break;
00258 case RootICBCache:
00259 c->rooticb = *(struct AD *)data;
00260 c->rooticb_valid = 1;
00261 break;
00262 case LBUDFCache:
00263 for(n = 0; n < c->lb_num; n++) {
00264 if(c->lbs[n].lb == nr) {
00265
00266 c->lbs[n].data = *(uint8_t **)data;
00267 c->lbs[n].lb = nr;
00268 return 1;
00269 }
00270 }
00271 c->lb_num++;
00272 c->lbs = realloc(c->lbs, c->lb_num * sizeof(struct lbudf));
00273
00274
00275
00276
00277
00278 if(c->lbs == NULL) {
00279 c->lb_num = 0;
00280 return 0;
00281 }
00282 c->lbs[n].data = *(uint8_t **)data;
00283 c->lbs[n].lb = nr;
00284 break;
00285 case MapCache:
00286 for(n = 0; n < c->map_num; n++) {
00287 if(c->maps[n].lbn == nr) {
00288
00289 c->maps[n] = *(struct icbmap *)data;
00290 c->maps[n].lbn = nr;
00291 return 1;
00292 }
00293 }
00294 c->map_num++;
00295 c->maps = realloc(c->maps, c->map_num * sizeof(struct icbmap));
00296
00297
00298
00299
00300
00301 if(c->maps == NULL) {
00302 c->map_num = 0;
00303 return 0;
00304 }
00305 c->maps[n] = *(struct icbmap *)data;
00306 c->maps[n].lbn = nr;
00307 break;
00308 default:
00309 return 0;
00310 }
00311
00312 return 1;
00313 }
00314
00315
00316
00317 #define GETN1(p) ((uint8_t)data[p])
00318 #define GETN2(p) ((uint16_t)data[p] | ((uint16_t)data[(p) + 1] << 8))
00319 #define GETN3(p) ((uint32_t)data[p] | ((uint32_t)data[(p) + 1] << 8) \
00320 | ((uint32_t)data[(p) + 2] << 16))
00321 #define GETN4(p) ((uint32_t)data[p] \
00322 | ((uint32_t)data[(p) + 1] << 8) \
00323 | ((uint32_t)data[(p) + 2] << 16) \
00324 | ((uint32_t)data[(p) + 3] << 24))
00325
00326 #define GETN(p, n, target) memcpy(target, &data[p], n)
00327
00328 static int Unicodedecode( uint8_t *data, int len, char *target )
00329 {
00330 int p = 1, i = 0;
00331
00332 if( ( data[ 0 ] == 8 ) || ( data[ 0 ] == 16 ) ) do {
00333 if( data[ 0 ] == 16 ) p++;
00334 if( p < len ) {
00335 target[ i++ ] = data[ p++ ];
00336 }
00337 } while( p < len );
00338
00339 target[ i ] = '\0';
00340 return 0;
00341 }
00342
00343 static int UDFDescriptor( uint8_t *data, uint16_t *TagID )
00344 {
00345 *TagID = GETN2(0);
00346
00347 return 0;
00348 }
00349
00350 static int UDFExtentAD( uint8_t *data, uint32_t *Length, uint32_t *Location )
00351 {
00352 *Length = GETN4(0);
00353 *Location = GETN4(4);
00354 return 0;
00355 }
00356
00357 static int UDFShortAD( uint8_t *data, struct AD *ad,
00358 struct Partition *partition )
00359 {
00360 ad->Length = GETN4(0);
00361 ad->Flags = ad->Length >> 30;
00362 ad->Length &= 0x3FFFFFFF;
00363 ad->Location = GETN4(4);
00364 ad->Partition = partition->Number;
00365 return 0;
00366 }
00367
00368 static int UDFLongAD( uint8_t *data, struct AD *ad )
00369 {
00370 ad->Length = GETN4(0);
00371 ad->Flags = ad->Length >> 30;
00372 ad->Length &= 0x3FFFFFFF;
00373 ad->Location = GETN4(4);
00374 ad->Partition = GETN2(8);
00375
00376 return 0;
00377 }
00378
00379 static int UDFExtAD( uint8_t *data, struct AD *ad )
00380 {
00381 ad->Length = GETN4(0);
00382 ad->Flags = ad->Length >> 30;
00383 ad->Length &= 0x3FFFFFFF;
00384 ad->Location = GETN4(12);
00385 ad->Partition = GETN2(16);
00386
00387 return 0;
00388 }
00389
00390 static int UDFICB( uint8_t *data, uint8_t *FileType, uint16_t *Flags )
00391 {
00392 *FileType = GETN1(11);
00393 *Flags = GETN2(18);
00394 return 0;
00395 }
00396
00397
00398 static int UDFPartition( uint8_t *data, uint16_t *Flags, uint16_t *Number,
00399 char *Contents, uint32_t *Start, uint32_t *Length )
00400 {
00401 *Flags = GETN2(20);
00402 *Number = GETN2(22);
00403 GETN(24, 32, Contents);
00404 *Start = GETN4(188);
00405 *Length = GETN4(192);
00406 return 0;
00407 }
00408
00413 static int UDFLogVolume( uint8_t *data, char *VolumeDescriptor )
00414 {
00415 uint32_t lbsize, MT_L, N_PM;
00416 Unicodedecode(&data[84], 128, VolumeDescriptor);
00417 lbsize = GETN4(212);
00418 MT_L = GETN4(264);
00419 N_PM = GETN4(268);
00420 if (lbsize != DVD_VIDEO_LB_LEN) return 1;
00421 return 0;
00422 }
00423
00424 static int UDFFileEntry( uint8_t *data, uint8_t *FileType,
00425 struct Partition *partition, struct AD *ad )
00426 {
00427 uint16_t flags;
00428 uint32_t L_EA, L_AD;
00429 unsigned int p;
00430
00431 UDFICB( &data[ 16 ], FileType, &flags );
00432
00433
00434 ad->Length = GETN4( 60 );
00435 ad->Flags = 0;
00436 ad->Location = 0;
00437 ad->Partition = partition->Number;
00438
00439 L_EA = GETN4( 168 );
00440 L_AD = GETN4( 172 );
00441 p = 176 + L_EA;
00442 while( p < 176 + L_EA + L_AD ) {
00443 switch( flags & 0x0007 ) {
00444 case 0: UDFShortAD( &data[ p ], ad, partition ); p += 8; break;
00445 case 1: UDFLongAD( &data[ p ], ad ); p += 16; break;
00446 case 2: UDFExtAD( &data[ p ], ad ); p += 20; break;
00447 case 3:
00448 switch( L_AD ) {
00449 case 8: UDFShortAD( &data[ p ], ad, partition ); break;
00450 case 16: UDFLongAD( &data[ p ], ad ); break;
00451 case 20: UDFExtAD( &data[ p ], ad ); break;
00452 }
00453 p += L_AD;
00454 break;
00455 default:
00456 p += L_AD; break;
00457 }
00458 }
00459 return 0;
00460 }
00461
00462 static int UDFFileIdentifier( uint8_t *data, uint8_t *FileCharacteristics,
00463 char *FileName, struct AD *FileICB )
00464 {
00465 uint8_t L_FI;
00466 uint16_t L_IU;
00467
00468 *FileCharacteristics = GETN1(18);
00469 L_FI = GETN1(19);
00470 UDFLongAD(&data[20], FileICB);
00471 L_IU = GETN2(36);
00472 if (L_FI) Unicodedecode(&data[38 + L_IU], L_FI, FileName);
00473 else FileName[0] = '\0';
00474 return 4 * ((38 + L_FI + L_IU + 3) / 4);
00475 }
00476
00484 static int UDFMapICB( dvd_reader_t *device, struct AD ICB, uint8_t *FileType,
00485 struct Partition *partition, struct AD *File )
00486 {
00487 uint8_t LogBlock_base[DVD_VIDEO_LB_LEN + 2048];
00488 uint8_t *LogBlock = (uint8_t *)(((uintptr_t)LogBlock_base & ~((uintptr_t)2047)) + 2048);
00489 uint32_t lbnum;
00490 uint16_t TagID;
00491 struct icbmap tmpmap;
00492
00493 lbnum = partition->Start + ICB.Location;
00494 tmpmap.lbn = lbnum;
00495 if(GetUDFCache(device, MapCache, lbnum, &tmpmap)) {
00496 *FileType = tmpmap.filetype;
00497 *File = tmpmap.file;
00498 return 1;
00499 }
00500
00501 do {
00502 if( DVDReadLBUDF( device, lbnum++, 1, LogBlock, 0 ) <= 0 ) {
00503 TagID = 0;
00504 } else {
00505 UDFDescriptor( LogBlock, &TagID );
00506 }
00507
00508 if( TagID == 261 ) {
00509 UDFFileEntry( LogBlock, FileType, partition, File );
00510 tmpmap.file = *File;
00511 tmpmap.filetype = *FileType;
00512 SetUDFCache(device, MapCache, tmpmap.lbn, &tmpmap);
00513 return 1;
00514 };
00515 } while( ( lbnum <= partition->Start + ICB.Location + ( ICB.Length - 1 )
00516 / DVD_VIDEO_LB_LEN ) && ( TagID != 261 ) );
00517
00518 return 0;
00519 }
00520
00527 static int UDFScanDir( dvd_reader_t *device, struct AD Dir, char *FileName,
00528 struct Partition *partition, struct AD *FileICB,
00529 int cache_file_info)
00530 {
00531 char filename[ MAX_UDF_FILE_NAME_LEN ];
00532 uint8_t directory_base[ 2 * DVD_VIDEO_LB_LEN + 2048];
00533 uint8_t *directory = (uint8_t *)(((uintptr_t)directory_base & ~((uintptr_t)2047)) + 2048);
00534 uint32_t lbnum;
00535 uint16_t TagID;
00536 uint8_t filechar;
00537 unsigned int p;
00538 uint8_t *cached_dir_base = NULL, *cached_dir;
00539 uint32_t dir_lba;
00540 struct AD tmpICB;
00541 int found = 0;
00542 int in_cache = 0;
00543
00544
00545 lbnum = partition->Start + Dir.Location;
00546
00547 if(DVDUDFCacheLevel(device, -1) > 0) {
00548
00549
00550 if(!GetUDFCache(device, LBUDFCache, lbnum, &cached_dir)) {
00551 dir_lba = (Dir.Length + DVD_VIDEO_LB_LEN) / DVD_VIDEO_LB_LEN;
00552 if((cached_dir_base = malloc(dir_lba * DVD_VIDEO_LB_LEN + 2048)) == NULL) {
00553 return 0;
00554 }
00555 cached_dir = (uint8_t *)(((uintptr_t)cached_dir_base & ~((uintptr_t)2047)) + 2048);
00556 if( DVDReadLBUDF( device, lbnum, dir_lba, cached_dir, 0) <= 0 ) {
00557 free(cached_dir_base);
00558 cached_dir = NULL;
00559 }
00560
00561
00562
00563
00564
00565
00566 SetUDFCache(device, LBUDFCache, lbnum, &cached_dir);
00567 } else {
00568 in_cache = 1;
00569 }
00570
00571 if(cached_dir == NULL) {
00572 return 0;
00573 }
00574
00575 p = 0;
00576
00577 while( p < Dir.Length ) {
00578 UDFDescriptor( &cached_dir[ p ], &TagID );
00579 if( TagID == 257 ) {
00580 p += UDFFileIdentifier( &cached_dir[ p ], &filechar,
00581 filename, &tmpICB );
00582 if(cache_file_info && !in_cache) {
00583 uint8_t tmpFiletype;
00584 struct AD tmpFile;
00585
00586 if( !strcasecmp( FileName, filename ) ) {
00587 *FileICB = tmpICB;
00588 found = 1;
00589
00590 }
00591 UDFMapICB(device, tmpICB, &tmpFiletype,
00592 partition, &tmpFile);
00593 } else {
00594 if( !strcasecmp( FileName, filename ) ) {
00595 *FileICB = tmpICB;
00596 return 1;
00597 }
00598 }
00599 } else {
00600 if(cache_file_info && (!in_cache) && found) {
00601 return 1;
00602 }
00603 return 0;
00604 }
00605 }
00606 if(cache_file_info && (!in_cache) && found) {
00607 return 1;
00608 }
00609 return 0;
00610 }
00611
00612 if( DVDReadLBUDF( device, lbnum, 2, directory, 0 ) <= 0 ) {
00613 return 0;
00614 }
00615
00616 p = 0;
00617 while( p < Dir.Length ) {
00618 if( p > DVD_VIDEO_LB_LEN ) {
00619 ++lbnum;
00620 p -= DVD_VIDEO_LB_LEN;
00621 Dir.Length -= DVD_VIDEO_LB_LEN;
00622 if( DVDReadLBUDF( device, lbnum, 2, directory, 0 ) <= 0 ) {
00623 return 0;
00624 }
00625 }
00626 UDFDescriptor( &directory[ p ], &TagID );
00627 if( TagID == 257 ) {
00628 p += UDFFileIdentifier( &directory[ p ], &filechar,
00629 filename, FileICB );
00630 if( !strcasecmp( FileName, filename ) ) {
00631 return 1;
00632 }
00633 } else {
00634 return 0;
00635 }
00636 }
00637
00638 return 0;
00639 }
00640
00641
00642 static int UDFGetAVDP( dvd_reader_t *device,
00643 struct avdp_t *avdp)
00644 {
00645 uint8_t Anchor_base[ DVD_VIDEO_LB_LEN + 2048 ];
00646 uint8_t *Anchor = (uint8_t *)(((uintptr_t)Anchor_base & ~((uintptr_t)2047)) + 2048);
00647 uint32_t lbnum, MVDS_location, MVDS_length;
00648 uint16_t TagID;
00649 uint32_t lastsector;
00650 int terminate;
00651 struct avdp_t;
00652
00653 if(GetUDFCache(device, AVDPCache, 0, avdp)) {
00654 return 1;
00655 }
00656
00657
00658 lastsector = 0;
00659 lbnum = 256;
00660 terminate = 0;
00661
00662 for(;;) {
00663 if( DVDReadLBUDF( device, lbnum, 1, Anchor, 0 ) > 0 ) {
00664 UDFDescriptor( Anchor, &TagID );
00665 } else {
00666 TagID = 0;
00667 }
00668 if (TagID != 2) {
00669
00670 if( terminate ) return 0;
00671
00672 if( lastsector ) {
00673
00674
00675
00676
00677 lbnum = lastsector;
00678 terminate = 1;
00679 } else {
00680
00681 if( lastsector ) {
00682
00683 lbnum = lastsector - 256;
00684 } else {
00685
00686 return 0;
00687 }
00688 }
00689 } else {
00690
00691 break;
00692 }
00693 }
00694
00695 UDFExtentAD( &Anchor[ 16 ], &MVDS_length, &MVDS_location );
00696 avdp->mvds.location = MVDS_location;
00697 avdp->mvds.length = MVDS_length;
00698
00699
00700 UDFExtentAD( &Anchor[ 24 ], &MVDS_length, &MVDS_location );
00701 avdp->rvds.location = MVDS_location;
00702 avdp->rvds.length = MVDS_length;
00703
00704 SetUDFCache(device, AVDPCache, 0, avdp);
00705
00706 return 1;
00707 }
00708
00714 static int UDFFindPartition( dvd_reader_t *device, int partnum,
00715 struct Partition *part )
00716 {
00717 uint8_t LogBlock_base[ DVD_VIDEO_LB_LEN + 2048 ];
00718 uint8_t *LogBlock = (uint8_t *)(((uintptr_t)LogBlock_base & ~((uintptr_t)2047)) + 2048);
00719 uint32_t lbnum, MVDS_location, MVDS_length;
00720 uint16_t TagID;
00721 int i, volvalid;
00722 struct avdp_t avdp;
00723
00724
00725 if(!UDFGetAVDP(device, &avdp)) {
00726 return 0;
00727 }
00728
00729
00730 MVDS_location = avdp.mvds.location;
00731 MVDS_length = avdp.mvds.length;
00732
00733 part->valid = 0;
00734 volvalid = 0;
00735 part->VolumeDesc[ 0 ] = '\0';
00736 i = 1;
00737 do {
00738
00739 lbnum = MVDS_location;
00740 do {
00741
00742 if( DVDReadLBUDF( device, lbnum++, 1, LogBlock, 0 ) <= 0 ) {
00743 TagID = 0;
00744 } else {
00745 UDFDescriptor( LogBlock, &TagID );
00746 }
00747
00748 if( ( TagID == 5 ) && ( !part->valid ) ) {
00749
00750 UDFPartition( LogBlock, &part->Flags, &part->Number,
00751 part->Contents, &part->Start, &part->Length );
00752 part->valid = ( partnum == part->Number );
00753 } else if( ( TagID == 6 ) && ( !volvalid ) ) {
00754
00755 if( UDFLogVolume( LogBlock, part->VolumeDesc ) ) {
00756
00757 } else {
00758 volvalid = 1;
00759 }
00760 }
00761
00762 } while( ( lbnum <= MVDS_location + ( MVDS_length - 1 )
00763 / DVD_VIDEO_LB_LEN ) && ( TagID != 8 )
00764 && ( ( !part->valid ) || ( !volvalid ) ) );
00765
00766 if( ( !part->valid) || ( !volvalid ) ) {
00767
00768 MVDS_location = avdp.mvds.location;
00769 MVDS_length = avdp.mvds.length;
00770 }
00771 } while( i-- && ( ( !part->valid ) || ( !volvalid ) ) );
00772
00773
00774 return part->valid;
00775 }
00776
00777 uint32_t UDFFindFile( dvd_reader_t *device, char *filename,
00778 uint32_t *filesize )
00779 {
00780 uint8_t LogBlock_base[ DVD_VIDEO_LB_LEN + 2048 ];
00781 uint8_t *LogBlock = (uint8_t *)(((uintptr_t)LogBlock_base & ~((uintptr_t)2047)) + 2048);
00782 uint32_t lbnum;
00783 uint16_t TagID;
00784 struct Partition partition;
00785 struct AD RootICB, File, ICB;
00786 char tokenline[ MAX_UDF_FILE_NAME_LEN ];
00787 char *token;
00788 uint8_t filetype;
00789
00790 *filesize = 0;
00791 tokenline[0] = '\0';
00792 strcat( tokenline, filename );
00793
00794
00795 if(!(GetUDFCache(device, PartitionCache, 0, &partition) &&
00796 GetUDFCache(device, RootICBCache, 0, &RootICB))) {
00797
00798 if( !UDFFindPartition( device, 0, &partition ) ) return 0;
00799 SetUDFCache(device, PartitionCache, 0, &partition);
00800
00801
00802 lbnum = partition.Start;
00803 do {
00804 if( DVDReadLBUDF( device, lbnum++, 1, LogBlock, 0 ) <= 0 ) {
00805 TagID = 0;
00806 } else {
00807 UDFDescriptor( LogBlock, &TagID );
00808 }
00809
00810
00811 if( TagID == 256 ) {
00812 UDFLongAD( &LogBlock[ 400 ], &RootICB );
00813 }
00814 } while( ( lbnum < partition.Start + partition.Length )
00815 && ( TagID != 8 ) && ( TagID != 256 ) );
00816
00817
00818 if( TagID != 256 ) return 0;
00819 if( RootICB.Partition != 0 ) return 0;
00820 SetUDFCache(device, RootICBCache, 0, &RootICB);
00821 }
00822
00823
00824 if( !UDFMapICB( device, RootICB, &filetype, &partition, &File ) ) return 0;
00825 if( filetype != 4 ) return 0;
00826
00827 {
00828 int cache_file_info = 0;
00829
00830 token = strtok(tokenline, "/");
00831
00832 while( token != NULL ) {
00833
00834 if( !UDFScanDir( device, File, token, &partition, &ICB,
00835 cache_file_info)) {
00836 return 0;
00837 }
00838 if( !UDFMapICB( device, ICB, &filetype, &partition, &File ) ) {
00839 return 0;
00840 }
00841 if(!strcmp(token, "VIDEO_TS")) {
00842 cache_file_info = 1;
00843 }
00844 token = strtok( NULL, "/" );
00845 }
00846 }
00847
00848
00849 if( File.Partition != 0 ) return 0;
00850
00851 *filesize = File.Length;
00852
00853 if( !File.Location )
00854 return 0;
00855 else
00856 return partition.Start + File.Location;
00857 }
00858
00859
00860
00867 static int UDFGetDescriptor( dvd_reader_t *device, int id,
00868 uint8_t *descriptor, int bufsize)
00869 {
00870 uint32_t lbnum, MVDS_location, MVDS_length;
00871 struct avdp_t avdp;
00872 uint16_t TagID;
00873 uint32_t lastsector;
00874 int i, terminate;
00875 int desc_found = 0;
00876
00877 lastsector = 0;
00878 lbnum = 256;
00879 terminate = 0;
00880 if(bufsize < DVD_VIDEO_LB_LEN) {
00881 return 0;
00882 }
00883
00884 if(!UDFGetAVDP(device, &avdp)) {
00885 return 0;
00886 }
00887
00888
00889 MVDS_location = avdp.mvds.location;
00890 MVDS_length = avdp.mvds.length;
00891
00892 i = 1;
00893 do {
00894
00895 lbnum = MVDS_location;
00896 do {
00897
00898 if( DVDReadLBUDF( device, lbnum++, 1, descriptor, 0 ) <= 0 ) {
00899 TagID = 0;
00900 } else {
00901 UDFDescriptor( descriptor, &TagID );
00902 }
00903
00904 if( (TagID == id) && ( !desc_found ) ) {
00905
00906 desc_found = 1;
00907 }
00908 } while( ( lbnum <= MVDS_location + ( MVDS_length - 1 )
00909 / DVD_VIDEO_LB_LEN ) && ( TagID != 8 )
00910 && ( !desc_found) );
00911
00912 if( !desc_found ) {
00913
00914 MVDS_location = avdp.rvds.location;
00915 MVDS_length = avdp.rvds.length;
00916 }
00917 } while( i-- && ( !desc_found ) );
00918
00919 return desc_found;
00920 }
00921
00922
00923 static int UDFGetPVD(dvd_reader_t *device, struct pvd_t *pvd)
00924 {
00925 uint8_t pvd_buf_base[DVD_VIDEO_LB_LEN + 2048];
00926 uint8_t *pvd_buf = (uint8_t *)(((uintptr_t)pvd_buf_base & ~((uintptr_t)2047)) + 2048);
00927
00928 if(GetUDFCache(device, PVDCache, 0, pvd)) {
00929 return 1;
00930 }
00931
00932 if(!UDFGetDescriptor( device, 1, pvd_buf,
00933 sizeof(pvd_buf_base) - (pvd_buf - pvd_buf_base))) {
00934 return 0;
00935 }
00936
00937 memcpy(pvd->VolumeIdentifier, &pvd_buf[24], 32);
00938 memcpy(pvd->VolumeSetIdentifier, &pvd_buf[72], 128);
00939 SetUDFCache(device, PVDCache, 0, pvd);
00940
00941 return 1;
00942 }
00943
00950 int UDFGetVolumeIdentifier(dvd_reader_t *device, char *volid,
00951 unsigned int volid_size)
00952 {
00953 struct pvd_t pvd;
00954 unsigned int volid_len;
00955
00956
00957 if(!UDFGetPVD(device, &pvd)) {
00958 return 0;
00959 }
00960
00961 volid_len = pvd.VolumeIdentifier[31];
00962 if(volid_len > 31) {
00963
00964 volid_len = 31;
00965 }
00966 if(volid_size > volid_len) {
00967 volid_size = volid_len;
00968 }
00969 Unicodedecode(pvd.VolumeIdentifier, volid_size, volid);
00970
00971 return volid_len;
00972 }
00973
00983 int UDFGetVolumeSetIdentifier(dvd_reader_t *device, uint8_t *volsetid,
00984 unsigned int volsetid_size)
00985 {
00986 struct pvd_t pvd;
00987
00988
00989 if(!UDFGetPVD(device, &pvd)) {
00990 return 0;
00991 }
00992
00993
00994 if(volsetid_size > 128) {
00995 volsetid_size = 128;
00996 }
00997
00998 memcpy(volsetid, pvd.VolumeSetIdentifier, volsetid_size);
00999
01000 return 128;
01001 }