comparison dvdread/dvd_udf.c @ 20981:22cb9d5f1e21

Rename libdvdread to dvdread. We really only include only the dvdread subdirectory of libdvdread. This will also allow getting rid of some local modifications.
author diego
date Sat, 18 Nov 2006 00:33:01 +0000
parents libdvdread/dvd_udf.c@1a4fcea7ab53
children de28f9e8cb00
comparison
equal deleted inserted replaced
20980:70ca50bcc4a8 20981:22cb9d5f1e21
1 /*
2 * This code is based on dvdudf by:
3 * Christian Wolff <scarabaeus@convergence.de>.
4 *
5 * Modifications by:
6 * Billy Biggs <vektor@dumbterm.net>.
7 * Björn Englund <d4bjorn@dtek.chalmers.se>.
8 *
9 * Modified for use with MPlayer, changes contained in libdvdread_changes.diff.
10 * detailed changelog at http://svn.mplayerhq.hu/mplayer/trunk/
11 * $Id$
12 *
13 * dvdudf: parse and read the UDF volume information of a DVD Video
14 * Copyright (C) 1999 Christian Wolff for convergence integrated media
15 * GmbH The author can be reached at scarabaeus@convergence.de, the
16 * project's page is at http://linuxtv.org/dvd/
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or (at
21 * your option) any later version.
22 *
23 * This program is distributed in the hope that it will be useful, but
24 * WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26 * General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
31 * 02111-1307, USA. Or, point your browser to
32 * http://www.gnu.org/copyleft/gpl.html
33 */
34
35 #include "config.h"
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #ifndef __MINGW32__
41 #include <sys/ioctl.h>
42 #endif
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <unistd.h>
46 #include <inttypes.h>
47
48 #include "dvd_reader.h"
49 #include "dvd_udf.h"
50
51 /* Private but located in/shared with dvd_reader.c */
52 extern int UDFReadBlocksRaw( dvd_reader_t *device, uint32_t lb_number,
53 size_t block_count, unsigned char *data,
54 int encrypted );
55
56 /* It's required to either fail or deliver all the blocks asked for. */
57 static int DVDReadLBUDF( dvd_reader_t *device, uint32_t lb_number,
58 size_t block_count, unsigned char *data,
59 int encrypted )
60 {
61 int ret;
62 size_t count = block_count;
63
64 while(count > 0) {
65
66 ret = UDFReadBlocksRaw(device, lb_number, count, data, encrypted);
67
68 if(ret <= 0) {
69 /* One of the reads failed or nothing more to read, too bad.
70 * We won't even bother returning the reads that went ok. */
71 return ret;
72 }
73
74 count -= (size_t)ret;
75 lb_number += (uint32_t)ret;
76 }
77
78 return block_count;
79 }
80
81
82 #ifndef NULL
83 #define NULL ((void *)0)
84 #endif
85
86 struct Partition {
87 int valid;
88 char VolumeDesc[128];
89 uint16_t Flags;
90 uint16_t Number;
91 char Contents[32];
92 uint32_t AccessType;
93 uint32_t Start;
94 uint32_t Length;
95 };
96
97 struct AD {
98 uint32_t Location;
99 uint32_t Length;
100 uint8_t Flags;
101 uint16_t Partition;
102 };
103
104 struct extent_ad {
105 uint32_t location;
106 uint32_t length;
107 };
108
109 struct avdp_t {
110 struct extent_ad mvds;
111 struct extent_ad rvds;
112 };
113
114 struct pvd_t {
115 uint8_t VolumeIdentifier[32];
116 uint8_t VolumeSetIdentifier[128];
117 };
118
119 struct lbudf {
120 uint32_t lb;
121 uint8_t *data;
122 };
123
124 struct icbmap {
125 uint32_t lbn;
126 struct AD file;
127 uint8_t filetype;
128 };
129
130 struct udf_cache {
131 int avdp_valid;
132 struct avdp_t avdp;
133 int pvd_valid;
134 struct pvd_t pvd;
135 int partition_valid;
136 struct Partition partition;
137 int rooticb_valid;
138 struct AD rooticb;
139 int lb_num;
140 struct lbudf *lbs;
141 int map_num;
142 struct icbmap *maps;
143 };
144
145 typedef enum {
146 PartitionCache, RootICBCache, LBUDFCache, MapCache, AVDPCache, PVDCache
147 } UDFCacheType;
148
149 extern void *GetUDFCacheHandle(dvd_reader_t *device);
150 extern void SetUDFCacheHandle(dvd_reader_t *device, void *cache);
151
152 void FreeUDFCache(void *cache)
153 {
154 struct udf_cache *c = (struct udf_cache *)cache;
155 if(c == NULL) {
156 return;
157 }
158 if(c->lbs) {
159 free(c->lbs);
160 }
161 if(c->maps) {
162 free(c->maps);
163 }
164 free(c);
165 }
166
167
168 static int GetUDFCache(dvd_reader_t *device, UDFCacheType type,
169 uint32_t nr, void *data)
170 {
171 int n;
172 struct udf_cache *c;
173
174 if(DVDUDFCacheLevel(device, -1) <= 0) {
175 return 0;
176 }
177
178 c = (struct udf_cache *)GetUDFCacheHandle(device);
179
180 if(c == NULL) {
181 return 0;
182 }
183
184 switch(type) {
185 case AVDPCache:
186 if(c->avdp_valid) {
187 *(struct avdp_t *)data = c->avdp;
188 return 1;
189 }
190 break;
191 case PVDCache:
192 if(c->pvd_valid) {
193 *(struct pvd_t *)data = c->pvd;
194 return 1;
195 }
196 break;
197 case PartitionCache:
198 if(c->partition_valid) {
199 *(struct Partition *)data = c->partition;
200 return 1;
201 }
202 break;
203 case RootICBCache:
204 if(c->rooticb_valid) {
205 *(struct AD *)data = c->rooticb;
206 return 1;
207 }
208 break;
209 case LBUDFCache:
210 for(n = 0; n < c->lb_num; n++) {
211 if(c->lbs[n].lb == nr) {
212 *(uint8_t **)data = c->lbs[n].data;
213 return 1;
214 }
215 }
216 break;
217 case MapCache:
218 for(n = 0; n < c->map_num; n++) {
219 if(c->maps[n].lbn == nr) {
220 *(struct icbmap *)data = c->maps[n];
221 return 1;
222 }
223 }
224 break;
225 default:
226 break;
227 }
228
229 return 0;
230 }
231
232 static int SetUDFCache(dvd_reader_t *device, UDFCacheType type,
233 uint32_t nr, void *data)
234 {
235 int n;
236 struct udf_cache *c;
237
238 if(DVDUDFCacheLevel(device, -1) <= 0) {
239 return 0;
240 }
241
242 c = (struct udf_cache *)GetUDFCacheHandle(device);
243
244 if(c == NULL) {
245 c = calloc(1, sizeof(struct udf_cache));
246 // fprintf(stderr, "calloc: %d\n", sizeof(struct udf_cache));
247 if(c == NULL) {
248 return 0;
249 }
250 SetUDFCacheHandle(device, c);
251 }
252
253
254 switch(type) {
255 case AVDPCache:
256 c->avdp = *(struct avdp_t *)data;
257 c->avdp_valid = 1;
258 break;
259 case PVDCache:
260 c->pvd = *(struct pvd_t *)data;
261 c->pvd_valid = 1;
262 break;
263 case PartitionCache:
264 c->partition = *(struct Partition *)data;
265 c->partition_valid = 1;
266 break;
267 case RootICBCache:
268 c->rooticb = *(struct AD *)data;
269 c->rooticb_valid = 1;
270 break;
271 case LBUDFCache:
272 for(n = 0; n < c->lb_num; n++) {
273 if(c->lbs[n].lb == nr) {
274 /* replace with new data */
275 c->lbs[n].data = *(uint8_t **)data;
276 c->lbs[n].lb = nr;
277 return 1;
278 }
279 }
280 c->lb_num++;
281 c->lbs = realloc(c->lbs, c->lb_num * sizeof(struct lbudf));
282 /*
283 fprintf(stderr, "realloc lb: %d * %d = %d\n",
284 c->lb_num, sizeof(struct lbudf),
285 c->lb_num * sizeof(struct lbudf));
286 */
287 if(c->lbs == NULL) {
288 c->lb_num = 0;
289 return 0;
290 }
291 c->lbs[n].data = *(uint8_t **)data;
292 c->lbs[n].lb = nr;
293 break;
294 case MapCache:
295 for(n = 0; n < c->map_num; n++) {
296 if(c->maps[n].lbn == nr) {
297 /* replace with new data */
298 c->maps[n] = *(struct icbmap *)data;
299 c->maps[n].lbn = nr;
300 return 1;
301 }
302 }
303 c->map_num++;
304 c->maps = realloc(c->maps, c->map_num * sizeof(struct icbmap));
305 /*
306 fprintf(stderr, "realloc maps: %d * %d = %d\n",
307 c->map_num, sizeof(struct icbmap),
308 c->map_num * sizeof(struct icbmap));
309 */
310 if(c->maps == NULL) {
311 c->map_num = 0;
312 return 0;
313 }
314 c->maps[n] = *(struct icbmap *)data;
315 c->maps[n].lbn = nr;
316 break;
317 default:
318 return 0;
319 }
320
321 return 1;
322 }
323
324
325 /* For direct data access, LSB first */
326 #define GETN1(p) ((uint8_t)data[p])
327 #define GETN2(p) ((uint16_t)data[p] | ((uint16_t)data[(p) + 1] << 8))
328 #define GETN3(p) ((uint32_t)data[p] | ((uint32_t)data[(p) + 1] << 8) \
329 | ((uint32_t)data[(p) + 2] << 16))
330 #define GETN4(p) ((uint32_t)data[p] \
331 | ((uint32_t)data[(p) + 1] << 8) \
332 | ((uint32_t)data[(p) + 2] << 16) \
333 | ((uint32_t)data[(p) + 3] << 24))
334 /* This is wrong with regard to endianess */
335 #define GETN(p, n, target) memcpy(target, &data[p], n)
336
337 static int Unicodedecode( uint8_t *data, int len, char *target )
338 {
339 int p = 1, i = 0;
340
341 if( ( data[ 0 ] == 8 ) || ( data[ 0 ] == 16 ) ) do {
342 if( data[ 0 ] == 16 ) p++; /* Ignore MSB of unicode16 */
343 if( p < len ) {
344 target[ i++ ] = data[ p++ ];
345 }
346 } while( p < len );
347
348 target[ i ] = '\0';
349 return 0;
350 }
351
352 static int UDFDescriptor( uint8_t *data, uint16_t *TagID )
353 {
354 *TagID = GETN2(0);
355 // TODO: check CRC 'n stuff
356 return 0;
357 }
358
359 static int UDFExtentAD( uint8_t *data, uint32_t *Length, uint32_t *Location )
360 {
361 *Length = GETN4(0);
362 *Location = GETN4(4);
363 return 0;
364 }
365
366 static int UDFShortAD( uint8_t *data, struct AD *ad,
367 struct Partition *partition )
368 {
369 ad->Length = GETN4(0);
370 ad->Flags = ad->Length >> 30;
371 ad->Length &= 0x3FFFFFFF;
372 ad->Location = GETN4(4);
373 ad->Partition = partition->Number; // use number of current partition
374 return 0;
375 }
376
377 static int UDFLongAD( uint8_t *data, struct AD *ad )
378 {
379 ad->Length = GETN4(0);
380 ad->Flags = ad->Length >> 30;
381 ad->Length &= 0x3FFFFFFF;
382 ad->Location = GETN4(4);
383 ad->Partition = GETN2(8);
384 //GETN(10, 6, Use);
385 return 0;
386 }
387
388 static int UDFExtAD( uint8_t *data, struct AD *ad )
389 {
390 ad->Length = GETN4(0);
391 ad->Flags = ad->Length >> 30;
392 ad->Length &= 0x3FFFFFFF;
393 ad->Location = GETN4(12);
394 ad->Partition = GETN2(16);
395 //GETN(10, 6, Use);
396 return 0;
397 }
398
399 static int UDFICB( uint8_t *data, uint8_t *FileType, uint16_t *Flags )
400 {
401 *FileType = GETN1(11);
402 *Flags = GETN2(18);
403 return 0;
404 }
405
406
407 static int UDFPartition( uint8_t *data, uint16_t *Flags, uint16_t *Number,
408 char *Contents, uint32_t *Start, uint32_t *Length )
409 {
410 *Flags = GETN2(20);
411 *Number = GETN2(22);
412 GETN(24, 32, Contents);
413 *Start = GETN4(188);
414 *Length = GETN4(192);
415 return 0;
416 }
417
418 /**
419 * Reads the volume descriptor and checks the parameters. Returns 0 on OK, 1
420 * on error.
421 */
422 static int UDFLogVolume( uint8_t *data, char *VolumeDescriptor )
423 {
424 uint32_t lbsize, MT_L, N_PM;
425 Unicodedecode(&data[84], 128, VolumeDescriptor);
426 lbsize = GETN4(212); // should be 2048
427 MT_L = GETN4(264); // should be 6
428 N_PM = GETN4(268); // should be 1
429 if (lbsize != DVD_VIDEO_LB_LEN) return 1;
430 return 0;
431 }
432
433 static int UDFFileEntry( uint8_t *data, uint8_t *FileType,
434 struct Partition *partition, struct AD *ad )
435 {
436 uint16_t flags;
437 uint32_t L_EA, L_AD;
438 unsigned int p;
439
440 UDFICB( &data[ 16 ], FileType, &flags );
441
442 /* Init ad for an empty file (i.e. there isn't a AD, L_AD == 0 ) */
443 ad->Length = GETN4( 60 ); // Really 8 bytes a 56
444 ad->Flags = 0;
445 ad->Location = 0; // what should we put here?
446 ad->Partition = partition->Number; // use number of current partition
447
448 L_EA = GETN4( 168 );
449 L_AD = GETN4( 172 );
450 p = 176 + L_EA;
451 while( p < 176 + L_EA + L_AD ) {
452 switch( flags & 0x0007 ) {
453 case 0: UDFShortAD( &data[ p ], ad, partition ); p += 8; break;
454 case 1: UDFLongAD( &data[ p ], ad ); p += 16; break;
455 case 2: UDFExtAD( &data[ p ], ad ); p += 20; break;
456 case 3:
457 switch( L_AD ) {
458 case 8: UDFShortAD( &data[ p ], ad, partition ); break;
459 case 16: UDFLongAD( &data[ p ], ad ); break;
460 case 20: UDFExtAD( &data[ p ], ad ); break;
461 }
462 p += L_AD;
463 break;
464 default:
465 p += L_AD; break;
466 }
467 }
468 return 0;
469 }
470
471 static int UDFFileIdentifier( uint8_t *data, uint8_t *FileCharacteristics,
472 char *FileName, struct AD *FileICB )
473 {
474 uint8_t L_FI;
475 uint16_t L_IU;
476
477 *FileCharacteristics = GETN1(18);
478 L_FI = GETN1(19);
479 UDFLongAD(&data[20], FileICB);
480 L_IU = GETN2(36);
481 if (L_FI) Unicodedecode(&data[38 + L_IU], L_FI, FileName);
482 else FileName[0] = '\0';
483 return 4 * ((38 + L_FI + L_IU + 3) / 4);
484 }
485
486 /**
487 * Maps ICB to FileAD
488 * ICB: Location of ICB of directory to scan
489 * FileType: Type of the file
490 * File: Location of file the ICB is pointing to
491 * return 1 on success, 0 on error;
492 */
493 static int UDFMapICB( dvd_reader_t *device, struct AD ICB, uint8_t *FileType,
494 struct Partition *partition, struct AD *File )
495 {
496 uint8_t LogBlock[DVD_VIDEO_LB_LEN];
497 uint32_t lbnum;
498 uint16_t TagID;
499 struct icbmap tmpmap;
500
501 lbnum = partition->Start + ICB.Location;
502 tmpmap.lbn = lbnum;
503 if(GetUDFCache(device, MapCache, lbnum, &tmpmap)) {
504 *FileType = tmpmap.filetype;
505 *File = tmpmap.file;
506 return 1;
507 }
508
509 do {
510 if( DVDReadLBUDF( device, lbnum++, 1, LogBlock, 0 ) <= 0 ) {
511 TagID = 0;
512 } else {
513 UDFDescriptor( LogBlock, &TagID );
514 }
515
516 if( TagID == 261 ) {
517 UDFFileEntry( LogBlock, FileType, partition, File );
518 tmpmap.file = *File;
519 tmpmap.filetype = *FileType;
520 SetUDFCache(device, MapCache, tmpmap.lbn, &tmpmap);
521 return 1;
522 };
523 } while( ( lbnum <= partition->Start + ICB.Location + ( ICB.Length - 1 )
524 / DVD_VIDEO_LB_LEN ) && ( TagID != 261 ) );
525
526 return 0;
527 }
528
529 /**
530 * Dir: Location of directory to scan
531 * FileName: Name of file to look for
532 * FileICB: Location of ICB of the found file
533 * return 1 on success, 0 on error;
534 */
535 static int UDFScanDir( dvd_reader_t *device, struct AD Dir, char *FileName,
536 struct Partition *partition, struct AD *FileICB,
537 int cache_file_info)
538 {
539 char filename[ MAX_UDF_FILE_NAME_LEN ];
540 uint8_t directory[ 2 * DVD_VIDEO_LB_LEN ];
541 uint32_t lbnum;
542 uint16_t TagID;
543 uint8_t filechar;
544 unsigned int p;
545 uint8_t *cached_dir = NULL;
546 uint32_t dir_lba;
547 struct AD tmpICB;
548 int found = 0;
549 int in_cache = 0;
550
551 /* Scan dir for ICB of file */
552 lbnum = partition->Start + Dir.Location;
553
554 if(DVDUDFCacheLevel(device, -1) > 0) {
555 /* caching */
556
557 if(!GetUDFCache(device, LBUDFCache, lbnum, &cached_dir)) {
558 dir_lba = (Dir.Length + DVD_VIDEO_LB_LEN) / DVD_VIDEO_LB_LEN;
559 if((cached_dir = malloc(dir_lba * DVD_VIDEO_LB_LEN)) == NULL) {
560 return 0;
561 }
562 if( DVDReadLBUDF( device, lbnum, dir_lba, cached_dir, 0) <= 0 ) {
563 free(cached_dir);
564 cached_dir = NULL;
565 }
566 /*
567 if(cached_dir) {
568 fprintf(stderr, "malloc dir: %d\n",
569 dir_lba * DVD_VIDEO_LB_LEN);
570 }
571 */
572 SetUDFCache(device, LBUDFCache, lbnum, &cached_dir);
573 } else {
574 in_cache = 1;
575 }
576
577 if(cached_dir == NULL) {
578 return 0;
579 }
580
581 p = 0;
582
583 while( p < Dir.Length ) {
584 UDFDescriptor( &cached_dir[ p ], &TagID );
585 if( TagID == 257 ) {
586 p += UDFFileIdentifier( &cached_dir[ p ], &filechar,
587 filename, &tmpICB );
588 if(cache_file_info && !in_cache) {
589 uint8_t tmpFiletype;
590 struct AD tmpFile;
591
592 if( !strcasecmp( FileName, filename ) ) {
593 *FileICB = tmpICB;
594 found = 1;
595
596 }
597 UDFMapICB(device, tmpICB, &tmpFiletype,
598 partition, &tmpFile);
599 } else {
600 if( !strcasecmp( FileName, filename ) ) {
601 *FileICB = tmpICB;
602 return 1;
603 }
604 }
605 } else {
606 if(cache_file_info && (!in_cache) && found) {
607 return 1;
608 }
609 return 0;
610 }
611 }
612 if(cache_file_info && (!in_cache) && found) {
613 return 1;
614 }
615 return 0;
616 }
617
618 if( DVDReadLBUDF( device, lbnum, 2, directory, 0 ) <= 0 ) {
619 return 0;
620 }
621
622 p = 0;
623 while( p < Dir.Length ) {
624 if( p > DVD_VIDEO_LB_LEN ) {
625 ++lbnum;
626 p -= DVD_VIDEO_LB_LEN;
627 Dir.Length -= DVD_VIDEO_LB_LEN;
628 if( DVDReadLBUDF( device, lbnum, 2, directory, 0 ) <= 0 ) {
629 return 0;
630 }
631 }
632 UDFDescriptor( &directory[ p ], &TagID );
633 if( TagID == 257 ) {
634 p += UDFFileIdentifier( &directory[ p ], &filechar,
635 filename, FileICB );
636 if( !strcasecmp( FileName, filename ) ) {
637 return 1;
638 }
639 } else {
640 return 0;
641 }
642 }
643
644 return 0;
645 }
646
647
648 static int UDFGetAVDP( dvd_reader_t *device,
649 struct avdp_t *avdp)
650 {
651 uint8_t Anchor[ DVD_VIDEO_LB_LEN ];
652 uint32_t lbnum, MVDS_location, MVDS_length;
653 uint16_t TagID;
654 uint32_t lastsector;
655 int terminate;
656 struct avdp_t;
657
658 if(GetUDFCache(device, AVDPCache, 0, avdp)) {
659 return 1;
660 }
661
662 /* Find Anchor */
663 lastsector = 0;
664 lbnum = 256; /* Try #1, prime anchor */
665 terminate = 0;
666
667 for(;;) {
668 if( DVDReadLBUDF( device, lbnum, 1, Anchor, 0 ) > 0 ) {
669 UDFDescriptor( Anchor, &TagID );
670 } else {
671 TagID = 0;
672 }
673 if (TagID != 2) {
674 /* Not an anchor */
675 if( terminate ) return 0; /* Final try failed */
676
677 if( lastsector ) {
678
679 /* We already found the last sector. Try #3, alternative
680 * backup anchor. If that fails, don't try again.
681 */
682 lbnum = lastsector;
683 terminate = 1;
684 } else {
685 /* TODO: Find last sector of the disc (this is optional). */
686 if( lastsector ) {
687 /* Try #2, backup anchor */
688 lbnum = lastsector - 256;
689 } else {
690 /* Unable to find last sector */
691 return 0;
692 }
693 }
694 } else {
695 /* It's an anchor! We can leave */
696 break;
697 }
698 }
699 /* Main volume descriptor */
700 UDFExtentAD( &Anchor[ 16 ], &MVDS_length, &MVDS_location );
701 avdp->mvds.location = MVDS_location;
702 avdp->mvds.length = MVDS_length;
703
704 /* Backup volume descriptor */
705 UDFExtentAD( &Anchor[ 24 ], &MVDS_length, &MVDS_location );
706 avdp->rvds.location = MVDS_location;
707 avdp->rvds.length = MVDS_length;
708
709 SetUDFCache(device, AVDPCache, 0, avdp);
710
711 return 1;
712 }
713
714 /**
715 * Looks for partition on the disc. Returns 1 if partition found, 0 on error.
716 * partnum: Number of the partition, starting at 0.
717 * part: structure to fill with the partition information
718 */
719 static int UDFFindPartition( dvd_reader_t *device, int partnum,
720 struct Partition *part )
721 {
722 uint8_t LogBlock[ DVD_VIDEO_LB_LEN ];
723 uint32_t lbnum, MVDS_location, MVDS_length;
724 uint16_t TagID;
725 int i, volvalid;
726 struct avdp_t avdp;
727
728
729 if(!UDFGetAVDP(device, &avdp)) {
730 return 0;
731 }
732
733 /* Main volume descriptor */
734 MVDS_location = avdp.mvds.location;
735 MVDS_length = avdp.mvds.length;
736
737 part->valid = 0;
738 volvalid = 0;
739 part->VolumeDesc[ 0 ] = '\0';
740 i = 1;
741 do {
742 /* Find Volume Descriptor */
743 lbnum = MVDS_location;
744 do {
745
746 if( DVDReadLBUDF( device, lbnum++, 1, LogBlock, 0 ) <= 0 ) {
747 TagID = 0;
748 } else {
749 UDFDescriptor( LogBlock, &TagID );
750 }
751
752 if( ( TagID == 5 ) && ( !part->valid ) ) {
753 /* Partition Descriptor */
754 UDFPartition( LogBlock, &part->Flags, &part->Number,
755 part->Contents, &part->Start, &part->Length );
756 part->valid = ( partnum == part->Number );
757 } else if( ( TagID == 6 ) && ( !volvalid ) ) {
758 /* Logical Volume Descriptor */
759 if( UDFLogVolume( LogBlock, part->VolumeDesc ) ) {
760 /* TODO: sector size wrong! */
761 } else {
762 volvalid = 1;
763 }
764 }
765
766 } while( ( lbnum <= MVDS_location + ( MVDS_length - 1 )
767 / DVD_VIDEO_LB_LEN ) && ( TagID != 8 )
768 && ( ( !part->valid ) || ( !volvalid ) ) );
769
770 if( ( !part->valid) || ( !volvalid ) ) {
771 /* Backup volume descriptor */
772 MVDS_location = avdp.mvds.location;
773 MVDS_length = avdp.mvds.length;
774 }
775 } while( i-- && ( ( !part->valid ) || ( !volvalid ) ) );
776
777 /* We only care for the partition, not the volume */
778 return part->valid;
779 }
780
781 uint32_t UDFFindFile( dvd_reader_t *device, char *filename,
782 uint32_t *filesize )
783 {
784 uint8_t LogBlock[ DVD_VIDEO_LB_LEN ];
785 uint32_t lbnum;
786 uint16_t TagID;
787 struct Partition partition;
788 struct AD RootICB, File, ICB;
789 char tokenline[ MAX_UDF_FILE_NAME_LEN ];
790 char *token;
791 uint8_t filetype;
792
793 *filesize = 0;
794 tokenline[0] = '\0';
795 strcat( tokenline, filename );
796
797
798 if(!(GetUDFCache(device, PartitionCache, 0, &partition) &&
799 GetUDFCache(device, RootICBCache, 0, &RootICB))) {
800 /* Find partition, 0 is the standard location for DVD Video.*/
801 if( !UDFFindPartition( device, 0, &partition ) ) return 0;
802 SetUDFCache(device, PartitionCache, 0, &partition);
803
804 /* Find root dir ICB */
805 lbnum = partition.Start;
806 do {
807 if( DVDReadLBUDF( device, lbnum++, 1, LogBlock, 0 ) <= 0 ) {
808 TagID = 0;
809 } else {
810 UDFDescriptor( LogBlock, &TagID );
811 }
812
813 /* File Set Descriptor */
814 if( TagID == 256 ) { // File Set Descriptor
815 UDFLongAD( &LogBlock[ 400 ], &RootICB );
816 }
817 } while( ( lbnum < partition.Start + partition.Length )
818 && ( TagID != 8 ) && ( TagID != 256 ) );
819
820 /* Sanity checks. */
821 if( TagID != 256 ) return 0;
822 if( RootICB.Partition != 0 ) return 0;
823 SetUDFCache(device, RootICBCache, 0, &RootICB);
824 }
825
826 /* Find root dir */
827 if( !UDFMapICB( device, RootICB, &filetype, &partition, &File ) ) return 0;
828 if( filetype != 4 ) return 0; /* Root dir should be dir */
829
830 {
831 int cache_file_info = 0;
832 /* Tokenize filepath */
833 token = strtok(tokenline, "/");
834
835 while( token != NULL ) {
836
837 if( !UDFScanDir( device, File, token, &partition, &ICB,
838 cache_file_info)) {
839 return 0;
840 }
841 if( !UDFMapICB( device, ICB, &filetype, &partition, &File ) ) {
842 return 0;
843 }
844 if(!strcmp(token, "VIDEO_TS")) {
845 cache_file_info = 1;
846 }
847 token = strtok( NULL, "/" );
848 }
849 }
850
851 /* Sanity check. */
852 if( File.Partition != 0 ) return 0;
853
854 *filesize = File.Length;
855 /* Hack to not return partition.Start for empty files. */
856 if( !File.Location )
857 return 0;
858 else
859 return partition.Start + File.Location;
860 }
861
862
863
864 /**
865 * Gets a Descriptor .
866 * Returns 1 if descriptor found, 0 on error.
867 * id, tagid of descriptor
868 * bufsize, size of BlockBuf (must be >= DVD_VIDEO_LB_LEN).
869 */
870 static int UDFGetDescriptor( dvd_reader_t *device, int id,
871 uint8_t *descriptor, int bufsize)
872 {
873 uint32_t lbnum, MVDS_location, MVDS_length;
874 struct avdp_t avdp;
875 uint16_t TagID;
876 uint32_t lastsector;
877 int i, terminate;
878 int desc_found = 0;
879 /* Find Anchor */
880 lastsector = 0;
881 lbnum = 256; /* Try #1, prime anchor */
882 terminate = 0;
883 if(bufsize < DVD_VIDEO_LB_LEN) {
884 return 0;
885 }
886
887 if(!UDFGetAVDP(device, &avdp)) {
888 return 0;
889 }
890
891 /* Main volume descriptor */
892 MVDS_location = avdp.mvds.location;
893 MVDS_length = avdp.mvds.length;
894
895 i = 1;
896 do {
897 /* Find Descriptor */
898 lbnum = MVDS_location;
899 do {
900
901 if( DVDReadLBUDF( device, lbnum++, 1, descriptor, 0 ) <= 0 ) {
902 TagID = 0;
903 } else {
904 UDFDescriptor( descriptor, &TagID );
905 }
906
907 if( (TagID == id) && ( !desc_found ) ) {
908 /* Descriptor */
909 desc_found = 1;
910 }
911 } while( ( lbnum <= MVDS_location + ( MVDS_length - 1 )
912 / DVD_VIDEO_LB_LEN ) && ( TagID != 8 )
913 && ( !desc_found) );
914
915 if( !desc_found ) {
916 /* Backup volume descriptor */
917 MVDS_location = avdp.rvds.location;
918 MVDS_length = avdp.rvds.length;
919 }
920 } while( i-- && ( !desc_found ) );
921
922 return desc_found;
923 }
924
925
926 static int UDFGetPVD(dvd_reader_t *device, struct pvd_t *pvd)
927 {
928 uint8_t pvd_buf[DVD_VIDEO_LB_LEN];
929
930 if(GetUDFCache(device, PVDCache, 0, pvd)) {
931 return 1;
932 }
933
934 if(!UDFGetDescriptor( device, 1, pvd_buf, sizeof(pvd_buf))) {
935 return 0;
936 }
937
938 memcpy(pvd->VolumeIdentifier, &pvd_buf[24], 32);
939 memcpy(pvd->VolumeSetIdentifier, &pvd_buf[72], 128);
940 SetUDFCache(device, PVDCache, 0, pvd);
941
942 return 1;
943 }
944
945 /**
946 * Gets the Volume Identifier string, in 8bit unicode (latin-1)
947 * volid, place to put the string
948 * volid_size, size of the buffer volid points to
949 * returns the size of buffer needed for all data
950 */
951 int UDFGetVolumeIdentifier(dvd_reader_t *device, char *volid,
952 unsigned int volid_size)
953 {
954 struct pvd_t pvd;
955 unsigned int volid_len;
956
957 /* get primary volume descriptor */
958 if(!UDFGetPVD(device, &pvd)) {
959 return 0;
960 }
961
962 volid_len = pvd.VolumeIdentifier[31];
963 if(volid_len > 31) {
964 /* this field is only 32 bytes something is wrong */
965 volid_len = 31;
966 }
967 if(volid_size > volid_len) {
968 volid_size = volid_len;
969 }
970 Unicodedecode(pvd.VolumeIdentifier, volid_size, volid);
971
972 return volid_len;
973 }
974
975 /**
976 * Gets the Volume Set Identifier, as a 128-byte dstring (not decoded)
977 * WARNING This is not a null terminated string
978 * volsetid, place to put the data
979 * volsetid_size, size of the buffer volsetid points to
980 * the buffer should be >=128 bytes to store the whole volumesetidentifier
981 * returns the size of the available volsetid information (128)
982 * or 0 on error
983 */
984 int UDFGetVolumeSetIdentifier(dvd_reader_t *device, uint8_t *volsetid,
985 unsigned int volsetid_size)
986 {
987 struct pvd_t pvd;
988
989 /* get primary volume descriptor */
990 if(!UDFGetPVD(device, &pvd)) {
991 return 0;
992 }
993
994
995 if(volsetid_size > 128) {
996 volsetid_size = 128;
997 }
998
999 memcpy(volsetid, pvd.VolumeSetIdentifier, volsetid_size);
1000
1001 return 128;
1002 }