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