|
MythTV
0.26-pre
|
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 }
1.7.6.1