Mercurial > mplayer.hg
annotate libmpdvdkit2/dvd_udf.c @ 15669:d283a96c0ecb
pass along audio extradata if present
author | nicodvb |
---|---|
date | Mon, 06 Jun 2005 20:49:55 +0000 |
parents | 25df9508f9a8 |
children | 483e955893b8 |
rev | line source |
---|---|
7029 | 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>. | |
10723 | 7 * Björn Englund <d4bjorn@dtek.chalmers.se>. |
8 * Joey Parrish <joey@nicewarrior.org>. | |
9 * - updated from libdvdread 0.9.4 and removed udf caching | |
7029 | 10 * |
14938
25df9508f9a8
Mark modified files as such to comply more closely with GPL ¡ø2a.
diego
parents:
10723
diff
changeset
|
11 * Modified for use with MPlayer, changes contained in libdvdread_changes.diff. |
25df9508f9a8
Mark modified files as such to comply more closely with GPL ¡ø2a.
diego
parents:
10723
diff
changeset
|
12 * detailed CVS changelog at http://www.mplayerhq.hu/cgi-bin/cvsweb.cgi/main/ |
25df9508f9a8
Mark modified files as such to comply more closely with GPL ¡ø2a.
diego
parents:
10723
diff
changeset
|
13 * $Id$ |
25df9508f9a8
Mark modified files as such to comply more closely with GPL ¡ø2a.
diego
parents:
10723
diff
changeset
|
14 * |
7029 | 15 * dvdudf: parse and read the UDF volume information of a DVD Video |
16 * Copyright (C) 1999 Christian Wolff for convergence integrated media | |
17 * GmbH The author can be reached at scarabaeus@convergence.de, the | |
18 * project's page is at http://linuxtv.org/dvd/ | |
19 * | |
20 * This program is free software; you can redistribute it and/or modify | |
21 * it under the terms of the GNU General Public License as published by | |
22 * the Free Software Foundation; either version 2 of the License, or (at | |
23 * your option) any later version. | |
24 * | |
25 * This program is distributed in the hope that it will be useful, but | |
26 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
28 * General Public License for more details. | |
29 * | |
30 * You should have received a copy of the GNU General Public License | |
31 * along with this program; if not, write to the Free Software | |
32 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | |
33 * 02111-1307, USA. Or, point your browser to | |
34 * http://www.gnu.org/copyleft/gpl.html | |
35 */ | |
36 | |
37 #include <stdio.h> | |
38 #include <stdlib.h> | |
39 #include <string.h> | |
7033 | 40 //#include <assert.h> |
9928 | 41 #ifndef __MINGW32__ |
7029 | 42 #include <sys/ioctl.h> |
9928 | 43 #endif |
7029 | 44 #include <sys/types.h> |
45 #include <sys/stat.h> | |
46 #include <unistd.h> | |
47 #include <inttypes.h> | |
48 | |
49 #include "dvd_reader.h" | |
50 #include "dvd_udf.h" | |
51 | |
52 /* Private but located in/shared with dvd_reader.c */ | |
53 extern int DVDReadBlocksUDFRaw( dvd_reader_t *device, uint32_t lb_number, | |
54 size_t block_count, unsigned char *data, | |
55 int encrypted ); | |
56 | |
57 /* It's required to either fail or deliver all the blocks asked for. */ | |
58 static int DVDReadLBUDF( dvd_reader_t *device, uint32_t lb_number, | |
59 size_t block_count, unsigned char *data, | |
60 int encrypted ) | |
61 { | |
62 int ret; | |
63 size_t count = block_count; | |
64 | |
65 while(count > 0) { | |
66 | |
67 ret = DVDReadBlocksUDFRaw(device, lb_number, count, data, encrypted); | |
68 | |
69 if(ret <= 0) { | |
70 /* One of the reads failed or nothing more to read, too bad. | |
71 * We won't even bother returning the reads that went ok. */ | |
72 return ret; | |
73 } | |
74 | |
75 count -= (size_t)ret; | |
76 lb_number += (uint32_t)ret; | |
77 } | |
78 | |
79 return block_count; | |
80 } | |
81 | |
82 | |
83 #ifndef NULL | |
84 #define NULL ((void *)0) | |
85 #endif | |
86 | |
87 struct Partition { | |
88 int valid; | |
89 char VolumeDesc[128]; | |
90 uint16_t Flags; | |
91 uint16_t Number; | |
92 char Contents[32]; | |
93 uint32_t AccessType; | |
94 uint32_t Start; | |
95 uint32_t Length; | |
96 }; | |
97 | |
98 struct AD { | |
99 uint32_t Location; | |
100 uint32_t Length; | |
101 uint8_t Flags; | |
102 uint16_t Partition; | |
103 }; | |
104 | |
10723 | 105 struct extent_ad { |
106 uint32_t location; | |
107 uint32_t length; | |
108 }; | |
109 | |
110 struct avdp_t { | |
111 struct extent_ad mvds; | |
112 struct extent_ad rvds; | |
113 }; | |
114 | |
115 struct pvd_t { | |
116 uint8_t VolumeIdentifier[32]; | |
117 uint8_t VolumeSetIdentifier[128]; | |
118 }; | |
119 | |
120 struct lbudf { | |
121 uint32_t lb; | |
122 uint8_t *data; | |
123 }; | |
124 | |
125 struct icbmap { | |
126 uint32_t lbn; | |
127 struct AD file; | |
128 uint8_t filetype; | |
129 }; | |
130 | |
7029 | 131 /* For direct data access, LSB first */ |
132 #define GETN1(p) ((uint8_t)data[p]) | |
133 #define GETN2(p) ((uint16_t)data[p] | ((uint16_t)data[(p) + 1] << 8)) | |
134 #define GETN3(p) ((uint32_t)data[p] | ((uint32_t)data[(p) + 1] << 8) \ | |
135 | ((uint32_t)data[(p) + 2] << 16)) | |
136 #define GETN4(p) ((uint32_t)data[p] \ | |
137 | ((uint32_t)data[(p) + 1] << 8) \ | |
138 | ((uint32_t)data[(p) + 2] << 16) \ | |
139 | ((uint32_t)data[(p) + 3] << 24)) | |
140 /* This is wrong with regard to endianess */ | |
141 #define GETN(p, n, target) memcpy(target, &data[p], n) | |
142 | |
143 static int Unicodedecode( uint8_t *data, int len, char *target ) | |
144 { | |
145 int p = 1, i = 0; | |
146 | |
147 if( ( data[ 0 ] == 8 ) || ( data[ 0 ] == 16 ) ) do { | |
148 if( data[ 0 ] == 16 ) p++; /* Ignore MSB of unicode16 */ | |
149 if( p < len ) { | |
150 target[ i++ ] = data[ p++ ]; | |
151 } | |
152 } while( p < len ); | |
153 | |
154 target[ i ] = '\0'; | |
155 return 0; | |
156 } | |
157 | |
158 static int UDFDescriptor( uint8_t *data, uint16_t *TagID ) | |
159 { | |
160 *TagID = GETN2(0); | |
161 // TODO: check CRC 'n stuff | |
162 return 0; | |
163 } | |
164 | |
165 static int UDFExtentAD( uint8_t *data, uint32_t *Length, uint32_t *Location ) | |
166 { | |
167 *Length = GETN4(0); | |
168 *Location = GETN4(4); | |
169 return 0; | |
170 } | |
171 | |
172 static int UDFShortAD( uint8_t *data, struct AD *ad, | |
173 struct Partition *partition ) | |
174 { | |
175 ad->Length = GETN4(0); | |
176 ad->Flags = ad->Length >> 30; | |
177 ad->Length &= 0x3FFFFFFF; | |
178 ad->Location = GETN4(4); | |
179 ad->Partition = partition->Number; // use number of current partition | |
180 return 0; | |
181 } | |
182 | |
183 static int UDFLongAD( uint8_t *data, struct AD *ad ) | |
184 { | |
185 ad->Length = GETN4(0); | |
186 ad->Flags = ad->Length >> 30; | |
187 ad->Length &= 0x3FFFFFFF; | |
188 ad->Location = GETN4(4); | |
189 ad->Partition = GETN2(8); | |
190 //GETN(10, 6, Use); | |
191 return 0; | |
192 } | |
193 | |
194 static int UDFExtAD( uint8_t *data, struct AD *ad ) | |
195 { | |
196 ad->Length = GETN4(0); | |
197 ad->Flags = ad->Length >> 30; | |
198 ad->Length &= 0x3FFFFFFF; | |
199 ad->Location = GETN4(12); | |
200 ad->Partition = GETN2(16); | |
201 //GETN(10, 6, Use); | |
202 return 0; | |
203 } | |
204 | |
205 static int UDFICB( uint8_t *data, uint8_t *FileType, uint16_t *Flags ) | |
206 { | |
207 *FileType = GETN1(11); | |
208 *Flags = GETN2(18); | |
209 return 0; | |
210 } | |
211 | |
212 | |
213 static int UDFPartition( uint8_t *data, uint16_t *Flags, uint16_t *Number, | |
214 char *Contents, uint32_t *Start, uint32_t *Length ) | |
215 { | |
216 *Flags = GETN2(20); | |
217 *Number = GETN2(22); | |
218 GETN(24, 32, Contents); | |
219 *Start = GETN4(188); | |
220 *Length = GETN4(192); | |
221 return 0; | |
222 } | |
223 | |
224 /** | |
225 * Reads the volume descriptor and checks the parameters. Returns 0 on OK, 1 | |
226 * on error. | |
227 */ | |
228 static int UDFLogVolume( uint8_t *data, char *VolumeDescriptor ) | |
229 { | |
230 uint32_t lbsize, MT_L, N_PM; | |
231 Unicodedecode(&data[84], 128, VolumeDescriptor); | |
232 lbsize = GETN4(212); // should be 2048 | |
233 MT_L = GETN4(264); // should be 6 | |
234 N_PM = GETN4(268); // should be 1 | |
235 if (lbsize != DVD_VIDEO_LB_LEN) return 1; | |
236 return 0; | |
237 } | |
238 | |
239 static int UDFFileEntry( uint8_t *data, uint8_t *FileType, | |
240 struct Partition *partition, struct AD *ad ) | |
241 { | |
242 uint16_t flags; | |
243 uint32_t L_EA, L_AD; | |
244 unsigned int p; | |
245 | |
246 UDFICB( &data[ 16 ], FileType, &flags ); | |
247 | |
248 /* Init ad for an empty file (i.e. there isn't a AD, L_AD == 0 ) */ | |
249 ad->Length = GETN4( 60 ); // Really 8 bytes a 56 | |
250 ad->Flags = 0; | |
251 ad->Location = 0; // what should we put here? | |
252 ad->Partition = partition->Number; // use number of current partition | |
253 | |
254 L_EA = GETN4( 168 ); | |
255 L_AD = GETN4( 172 ); | |
256 p = 176 + L_EA; | |
257 while( p < 176 + L_EA + L_AD ) { | |
258 switch( flags & 0x0007 ) { | |
259 case 0: UDFShortAD( &data[ p ], ad, partition ); p += 8; break; | |
260 case 1: UDFLongAD( &data[ p ], ad ); p += 16; break; | |
261 case 2: UDFExtAD( &data[ p ], ad ); p += 20; break; | |
262 case 3: | |
263 switch( L_AD ) { | |
264 case 8: UDFShortAD( &data[ p ], ad, partition ); break; | |
265 case 16: UDFLongAD( &data[ p ], ad ); break; | |
266 case 20: UDFExtAD( &data[ p ], ad ); break; | |
267 } | |
268 p += L_AD; | |
269 break; | |
270 default: | |
271 p += L_AD; break; | |
272 } | |
273 } | |
274 return 0; | |
275 } | |
276 | |
277 static int UDFFileIdentifier( uint8_t *data, uint8_t *FileCharacteristics, | |
278 char *FileName, struct AD *FileICB ) | |
279 { | |
280 uint8_t L_FI; | |
281 uint16_t L_IU; | |
282 | |
283 *FileCharacteristics = GETN1(18); | |
284 L_FI = GETN1(19); | |
285 UDFLongAD(&data[20], FileICB); | |
286 L_IU = GETN2(36); | |
287 if (L_FI) Unicodedecode(&data[38 + L_IU], L_FI, FileName); | |
288 else FileName[0] = '\0'; | |
289 return 4 * ((38 + L_FI + L_IU + 3) / 4); | |
290 } | |
291 | |
292 /** | |
293 * Maps ICB to FileAD | |
294 * ICB: Location of ICB of directory to scan | |
295 * FileType: Type of the file | |
296 * File: Location of file the ICB is pointing to | |
297 * return 1 on success, 0 on error; | |
298 */ | |
299 static int UDFMapICB( dvd_reader_t *device, struct AD ICB, uint8_t *FileType, | |
300 struct Partition *partition, struct AD *File ) | |
301 { | |
302 uint8_t LogBlock[DVD_VIDEO_LB_LEN]; | |
303 uint32_t lbnum; | |
304 uint16_t TagID; | |
305 | |
306 lbnum = partition->Start + ICB.Location; | |
307 do { | |
308 if( DVDReadLBUDF( device, lbnum++, 1, LogBlock, 0 ) <= 0 ) { | |
309 TagID = 0; | |
310 } else { | |
311 UDFDescriptor( LogBlock, &TagID ); | |
312 } | |
313 | |
314 if( TagID == 261 ) { | |
315 UDFFileEntry( LogBlock, FileType, partition, File ); | |
316 return 1; | |
317 }; | |
318 } while( ( lbnum <= partition->Start + ICB.Location + ( ICB.Length - 1 ) | |
319 / DVD_VIDEO_LB_LEN ) && ( TagID != 261 ) ); | |
320 | |
321 return 0; | |
322 } | |
323 | |
324 /** | |
325 * Dir: Location of directory to scan | |
326 * FileName: Name of file to look for | |
327 * FileICB: Location of ICB of the found file | |
328 * return 1 on success, 0 on error; | |
329 */ | |
330 static int UDFScanDir( dvd_reader_t *device, struct AD Dir, char *FileName, | |
331 struct Partition *partition, struct AD *FileICB ) | |
332 { | |
333 char filename[ MAX_UDF_FILE_NAME_LEN ]; | |
334 uint8_t directory[ 2 * DVD_VIDEO_LB_LEN ]; | |
335 uint32_t lbnum; | |
336 uint16_t TagID; | |
337 uint8_t filechar; | |
338 unsigned int p; | |
339 | |
340 /* Scan dir for ICB of file */ | |
341 lbnum = partition->Start + Dir.Location; | |
342 | |
343 if( DVDReadLBUDF( device, lbnum, 2, directory, 0 ) <= 0 ) { | |
344 return 0; | |
345 } | |
346 | |
347 p = 0; | |
348 while( p < Dir.Length ) { | |
349 if( p > DVD_VIDEO_LB_LEN ) { | |
350 ++lbnum; | |
351 p -= DVD_VIDEO_LB_LEN; | |
352 Dir.Length -= DVD_VIDEO_LB_LEN; | |
353 if( DVDReadLBUDF( device, lbnum, 2, directory, 0 ) <= 0 ) { | |
354 return 0; | |
355 } | |
356 } | |
357 UDFDescriptor( &directory[ p ], &TagID ); | |
358 if( TagID == 257 ) { | |
359 p += UDFFileIdentifier( &directory[ p ], &filechar, | |
360 filename, FileICB ); | |
361 if( !strcasecmp( FileName, filename ) ) { | |
362 return 1; | |
363 } | |
364 } else { | |
365 return 0; | |
366 } | |
367 } | |
368 | |
369 return 0; | |
370 } | |
371 | |
10723 | 372 |
373 static int UDFGetAVDP( dvd_reader_t *device, | |
374 struct avdp_t *avdp) | |
375 { | |
376 uint8_t Anchor[ DVD_VIDEO_LB_LEN ]; | |
377 uint32_t lbnum, MVDS_location, MVDS_length; | |
378 uint16_t TagID; | |
379 uint32_t lastsector; | |
380 int terminate; | |
381 struct avdp_t; | |
382 | |
383 /* Find Anchor */ | |
384 lastsector = 0; | |
385 lbnum = 256; /* Try #1, prime anchor */ | |
386 terminate = 0; | |
387 | |
388 for(;;) { | |
389 if( DVDReadLBUDF( device, lbnum, 1, Anchor, 0 ) > 0 ) { | |
390 UDFDescriptor( Anchor, &TagID ); | |
391 } else { | |
392 TagID = 0; | |
393 } | |
394 if (TagID != 2) { | |
395 /* Not an anchor */ | |
396 if( terminate ) return 0; /* Final try failed */ | |
397 | |
398 if( lastsector ) { | |
399 | |
400 /* We already found the last sector. Try #3, alternative | |
401 * backup anchor. If that fails, don't try again. | |
402 */ | |
403 lbnum = lastsector; | |
404 terminate = 1; | |
405 } else { | |
406 /* TODO: Find last sector of the disc (this is optional). */ | |
407 if( lastsector ) { | |
408 /* Try #2, backup anchor */ | |
409 lbnum = lastsector - 256; | |
410 } else { | |
411 /* Unable to find last sector */ | |
412 return 0; | |
413 } | |
414 } | |
415 } else { | |
416 /* It's an anchor! We can leave */ | |
417 break; | |
418 } | |
419 } | |
420 /* Main volume descriptor */ | |
421 UDFExtentAD( &Anchor[ 16 ], &MVDS_length, &MVDS_location ); | |
422 avdp->mvds.location = MVDS_location; | |
423 avdp->mvds.length = MVDS_length; | |
424 | |
425 /* Backup volume descriptor */ | |
426 UDFExtentAD( &Anchor[ 24 ], &MVDS_length, &MVDS_location ); | |
427 avdp->rvds.location = MVDS_location; | |
428 avdp->rvds.length = MVDS_length; | |
429 | |
430 return 1; | |
431 } | |
432 | |
7029 | 433 /** |
434 * Looks for partition on the disc. Returns 1 if partition found, 0 on error. | |
435 * partnum: Number of the partition, starting at 0. | |
436 * part: structure to fill with the partition information | |
437 */ | |
438 static int UDFFindPartition( dvd_reader_t *device, int partnum, | |
439 struct Partition *part ) | |
440 { | |
10723 | 441 uint8_t LogBlock[ DVD_VIDEO_LB_LEN ]; |
7029 | 442 uint32_t lbnum, MVDS_location, MVDS_length; |
443 uint16_t TagID; | |
10723 | 444 int i, volvalid; |
445 struct avdp_t avdp; | |
7029 | 446 |
10723 | 447 |
448 if(!UDFGetAVDP(device, &avdp)) { | |
449 return 0; | |
7029 | 450 } |
10723 | 451 |
7029 | 452 /* Main volume descriptor */ |
10723 | 453 MVDS_location = avdp.mvds.location; |
454 MVDS_length = avdp.mvds.length; | |
455 | |
7029 | 456 part->valid = 0; |
457 volvalid = 0; | |
458 part->VolumeDesc[ 0 ] = '\0'; | |
459 i = 1; | |
460 do { | |
461 /* Find Volume Descriptor */ | |
462 lbnum = MVDS_location; | |
463 do { | |
464 | |
465 if( DVDReadLBUDF( device, lbnum++, 1, LogBlock, 0 ) <= 0 ) { | |
466 TagID = 0; | |
467 } else { | |
468 UDFDescriptor( LogBlock, &TagID ); | |
469 } | |
470 | |
471 if( ( TagID == 5 ) && ( !part->valid ) ) { | |
472 /* Partition Descriptor */ | |
473 UDFPartition( LogBlock, &part->Flags, &part->Number, | |
474 part->Contents, &part->Start, &part->Length ); | |
475 part->valid = ( partnum == part->Number ); | |
476 } else if( ( TagID == 6 ) && ( !volvalid ) ) { | |
477 /* Logical Volume Descriptor */ | |
478 if( UDFLogVolume( LogBlock, part->VolumeDesc ) ) { | |
479 /* TODO: sector size wrong! */ | |
480 } else { | |
481 volvalid = 1; | |
482 } | |
483 } | |
484 | |
485 } while( ( lbnum <= MVDS_location + ( MVDS_length - 1 ) | |
486 / DVD_VIDEO_LB_LEN ) && ( TagID != 8 ) | |
487 && ( ( !part->valid ) || ( !volvalid ) ) ); | |
488 | |
489 if( ( !part->valid) || ( !volvalid ) ) { | |
10723 | 490 /* Backup volume descriptor */ |
491 MVDS_location = avdp.mvds.location; | |
492 MVDS_length = avdp.mvds.length; | |
7029 | 493 } |
494 } while( i-- && ( ( !part->valid ) || ( !volvalid ) ) ); | |
495 | |
496 /* We only care for the partition, not the volume */ | |
497 return part->valid; | |
498 } | |
499 | |
500 uint32_t UDFFindFile( dvd_reader_t *device, char *filename, | |
501 uint32_t *filesize ) | |
502 { | |
503 uint8_t LogBlock[ DVD_VIDEO_LB_LEN ]; | |
504 uint32_t lbnum; | |
505 uint16_t TagID; | |
506 struct Partition partition; | |
507 struct AD RootICB, File, ICB; | |
508 char tokenline[ MAX_UDF_FILE_NAME_LEN ]; | |
509 char *token; | |
510 uint8_t filetype; | |
10723 | 511 |
7029 | 512 *filesize = 0; |
513 tokenline[0] = '\0'; | |
514 strcat( tokenline, filename ); | |
515 | |
10723 | 516 |
517 /* Find partition, 0 is the standard location for DVD Video.*/ | |
518 if( !UDFFindPartition( device, 0, &partition ) ) return 0; | |
519 | |
520 /* Find root dir ICB */ | |
521 lbnum = partition.Start; | |
522 do { | |
7029 | 523 if( DVDReadLBUDF( device, lbnum++, 1, LogBlock, 0 ) <= 0 ) { |
524 TagID = 0; | |
525 } else { | |
526 UDFDescriptor( LogBlock, &TagID ); | |
527 } | |
528 | |
529 /* File Set Descriptor */ | |
530 if( TagID == 256 ) { // File Set Descriptor | |
531 UDFLongAD( &LogBlock[ 400 ], &RootICB ); | |
532 } | |
533 } while( ( lbnum < partition.Start + partition.Length ) | |
534 && ( TagID != 8 ) && ( TagID != 256 ) ); | |
535 | |
536 /* Sanity checks. */ | |
537 if( TagID != 256 ) return 0; | |
538 if( RootICB.Partition != 0 ) return 0; | |
10723 | 539 |
7029 | 540 /* Find root dir */ |
541 if( !UDFMapICB( device, RootICB, &filetype, &partition, &File ) ) return 0; | |
542 if( filetype != 4 ) return 0; /* Root dir should be dir */ | |
543 | |
10723 | 544 { |
545 /* Tokenize filepath */ | |
546 token = strtok(tokenline, "/"); | |
547 | |
548 while( token != NULL ) { | |
549 | |
550 if( !UDFScanDir( device, File, token, &partition, &ICB)) { | |
551 return 0; | |
552 } | |
553 if( !UDFMapICB( device, ICB, &filetype, &partition, &File ) ) { | |
554 return 0; | |
555 } | |
7029 | 556 token = strtok( NULL, "/" ); |
10723 | 557 } |
558 } | |
559 | |
7029 | 560 /* Sanity check. */ |
561 if( File.Partition != 0 ) return 0; | |
562 | |
563 *filesize = File.Length; | |
564 /* Hack to not return partition.Start for empty files. */ | |
565 if( !File.Location ) | |
566 return 0; | |
567 else | |
568 return partition.Start + File.Location; | |
569 } | |
10723 | 570 |
571 | |
572 | |
573 /** | |
574 * Gets a Descriptor . | |
575 * Returns 1 if descriptor found, 0 on error. | |
576 * id, tagid of descriptor | |
577 * bufsize, size of BlockBuf (must be >= DVD_VIDEO_LB_LEN). | |
578 */ | |
579 static int UDFGetDescriptor( dvd_reader_t *device, int id, | |
580 uint8_t *descriptor, int bufsize) | |
581 { | |
582 uint32_t lbnum, MVDS_location, MVDS_length; | |
583 struct avdp_t avdp; | |
584 uint16_t TagID; | |
585 uint32_t lastsector; | |
586 int i, terminate; | |
587 int desc_found = 0; | |
588 /* Find Anchor */ | |
589 lastsector = 0; | |
590 lbnum = 256; /* Try #1, prime anchor */ | |
591 terminate = 0; | |
592 if(bufsize < DVD_VIDEO_LB_LEN) { | |
593 return 0; | |
594 } | |
595 | |
596 if(!UDFGetAVDP(device, &avdp)) { | |
597 return 0; | |
598 } | |
599 | |
600 /* Main volume descriptor */ | |
601 MVDS_location = avdp.mvds.location; | |
602 MVDS_length = avdp.mvds.length; | |
603 | |
604 i = 1; | |
605 do { | |
606 /* Find Descriptor */ | |
607 lbnum = MVDS_location; | |
608 do { | |
609 | |
610 if( DVDReadLBUDF( device, lbnum++, 1, descriptor, 0 ) <= 0 ) { | |
611 TagID = 0; | |
612 } else { | |
613 UDFDescriptor( descriptor, &TagID ); | |
614 } | |
615 | |
616 if( (TagID == id) && ( !desc_found ) ) { | |
617 /* Descriptor */ | |
618 desc_found = 1; | |
619 } | |
620 } while( ( lbnum <= MVDS_location + ( MVDS_length - 1 ) | |
621 / DVD_VIDEO_LB_LEN ) && ( TagID != 8 ) | |
622 && ( !desc_found) ); | |
623 | |
624 if( !desc_found ) { | |
625 /* Backup volume descriptor */ | |
626 MVDS_location = avdp.rvds.location; | |
627 MVDS_length = avdp.rvds.length; | |
628 } | |
629 } while( i-- && ( !desc_found ) ); | |
630 | |
631 return desc_found; | |
632 } | |
633 | |
634 | |
635 static int UDFGetPVD(dvd_reader_t *device, struct pvd_t *pvd) | |
636 { | |
637 uint8_t pvd_buf[DVD_VIDEO_LB_LEN]; | |
638 | |
639 if(!UDFGetDescriptor( device, 1, pvd_buf, sizeof(pvd_buf))) { | |
640 return 0; | |
641 } | |
642 | |
643 memcpy(pvd->VolumeIdentifier, &pvd_buf[24], 32); | |
644 memcpy(pvd->VolumeSetIdentifier, &pvd_buf[72], 128); | |
645 | |
646 return 1; | |
647 } |