1 /*****************************************************************************
2 * dvd_udf.c: udf filesystem tools.
3 *****************************************************************************
4 * Mainly used to find asolute logical block adress of *.ifo files. It only
5 * contains the basic udf handling functions
6 *****************************************************************************
7 * Copyright (C) 1998-2001 VideoLAN
8 * $Id: dvd_udf.c,v 1.6 2001/04/28 03:36:25 sam Exp $
10 * Author: Stéphane Borel <stef@via.ecp.fr>
13 * - dvdudf by Christian Wolff <scarabaeus@convergence.de>
14 * - fixes by Billy Biggs <vektor@dumbterm.net>
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
29 *****************************************************************************/
37 #define MODULE_NAME dvd
39 #define MODULE_NAME dvdnocss
41 #include "modules_inner.h"
46 #ifdef STRNCASECMP_IN_STRINGS_H
55 #include "input_dvd.h"
61 typedef struct partition_s
64 u8 pi_volume_desc[128];
82 /* for direct data access, LSB first */
83 #define GETN1(p) ((u8)pi_data[p])
84 #define GETN2(p) ((u16)pi_data[p]|((u16)pi_data[(p)+1]<<8))
85 #define GETN4(p) ((u32)pi_data[p]|((u32)pi_data[(p)+1]<<8)|((u32)pi_data[(p)+2]<<16)|((u32)pi_data[(p)+3]<<24))
86 #define GETN(p,n,target) memcpy(target,&pi_data[p],n)
89 /*****************************************************************************
90 * UDFReadLB: reads absolute Logical Block of the disc
91 *****************************************************************************
92 * Returns number of read bytes on success, 0 on error
93 *****************************************************************************/
94 static int UDFReadLB( int i_fd, off_t i_lba, size_t i_block_count, u8 *pi_data )
101 if( lseek( i_fd, i_lba * (off_t) DVD_LB_SIZE, SEEK_SET ) < 0 )
103 intf_ErrMsg( "UDF: Postion not found" );
107 return read( i_fd, pi_data, i_block_count *DVD_LB_SIZE);
111 /*****************************************************************************
112 * UDFDecode: decode unicode encoded udf data
113 *****************************************************************************/
114 static int UDFDecode( u8 * pi_data, int i_len, char * psz_target )
119 if( !( pi_data[0] & 0x18 ) )
121 psz_target[0] = '\0';
125 if( pi_data[0] & 0x10 )
127 /* ignore MSB of unicode16 */
132 psz_target[i++] = pi_data[p+=2];
139 psz_target[i++] = pi_data[p++];
153 int UDFEntity (u8 *data, u8 *Flags, char *Identifier)
156 strncpy (Identifier, &data[1], 5);
163 /*****************************************************************************
164 * UDFDescriptor: gives a tag ID from your data to find out what it refers to
165 *****************************************************************************/
166 static int UDFDescriptor( u8 * pi_data, u16 * pi_tag_id )
168 pi_tag_id[0] = GETN2( 0 );
169 /* TODO: check CRC 'n stuff */
175 /*****************************************************************************
176 * UDFExtendAD: main volume information
177 *****************************************************************************/
178 static int UDFExtentAD (u8 * pi_data, u32 * pi_length, u32 * pi_location)
180 pi_length[0] = GETN4( 0 );
181 pi_location[0] = GETN4( 4 );
187 /*****************************************************************************
188 * UDFAD: file set information
189 *****************************************************************************/
190 static int UDFAD( u8 * pi_data, struct ad_s * p_ad, u8 i_type,
191 struct partition_s partition )
193 p_ad->i_length = GETN4( 0 );
194 p_ad->i_flags = p_ad->i_length >> 30;
195 p_ad->i_length &= 0x3FFFFFFF;
200 p_ad->i_location = GETN4( 4 );
201 /* use number of current partition */
202 p_ad->i_partition = partition.i_number;
206 p_ad->i_location = GETN4( 4 );
207 p_ad->i_partition = GETN2( 8 );
211 p_ad->i_location = GETN4( 12 );
212 p_ad->i_partition = GETN2( 16 );
220 /*****************************************************************************
221 * UDFICB: takes Information Control Block from pi_data
222 *****************************************************************************/
223 static int UDFICB( u8 * pi_data, u8 * pi_file_type, u16 * pi_flags)
225 pi_file_type[0] = GETN1( 11 );
226 pi_flags[0] = GETN2( 18 );
232 /*****************************************************************************
233 * UDFPartition: gets partition descriptor
234 *****************************************************************************/
235 static int UDFPartition( u8 * pi_data, u16 * pi_flags, u16 * pi_nb,
236 char * ps_contents, u32 * pi_start, u32 * pi_length )
238 pi_flags[0] = GETN2( 20 );
239 pi_nb[0] = GETN2( 22 );
240 GETN( 24, 32, ps_contents );
241 pi_start[0] = GETN4( 188 );
242 pi_length[0] = GETN4( 192 );
248 /*****************************************************************************
249 * UDFLogVolume: reads the volume descriptor and checks the parameters
250 *****************************************************************************
251 * Returns 0 on OK, 1 on error
252 *****************************************************************************/
253 static int UDFLogVolume(u8 * pi_data, char * p_volume_descriptor )
259 UDFDecode( &pi_data[84], 128, p_volume_descriptor );
261 i_lb_size = GETN4( 212 ); // should be 2048
262 i_MT_L = GETN4( 264 ); // should be 6
263 i_N_PM = GETN4( 268 ); // should be 1
265 if( i_lb_size != DVD_LB_SIZE )
267 intf_ErrMsg( "UDF: Non valid sector size (%d)", i_lb_size );
275 /*****************************************************************************
276 * UDFFileEntry: fills a ad_t struct with information at pi_data
277 *****************************************************************************/
278 static int UDFFileEntry( u8 * pi_data, u8 * pi_file_type, struct ad_s * p_ad,
279 struct partition_s partition )
287 UDFICB( &pi_data[16], &i_file_type, &i_flags );
289 pi_file_type[0] = i_file_type;
290 i_L_EA = GETN4( 168 );
291 i_L_AD = GETN4( 172 );
294 while( p < 176 + i_L_EA + i_L_AD )
296 switch( i_flags & 0x07 )
299 UDFAD( &pi_data[p], p_ad, UDFADshort, partition );
303 UDFAD( &pi_data[p], p_ad, UDFADlong, partition );
307 UDFAD( &pi_data[p], p_ad, UDFADext, partition );
314 UDFAD( &pi_data[p], p_ad, UDFADshort, partition );
317 UDFAD( &pi_data[p], p_ad, UDFADlong, partition );
320 UDFAD( &pi_data[p], p_ad, UDFADext, partition );
333 /*****************************************************************************
334 * UDFFileIdentifier: gives filename and characteristics of pi_data
335 *****************************************************************************/
336 static int UDFFileIdentifier( u8 * pi_data, u8 * pi_file_characteristics,
337 char * psz_filename, struct ad_s * p_file_icb,
338 struct partition_s partition )
343 pi_file_characteristics[0] = GETN1( 18 );
344 i_L_FI = GETN1( 19 );
345 UDFAD( &pi_data[20], p_file_icb, UDFADlong, partition );
346 i_L_IU = GETN2( 36 );
350 UDFDecode( &pi_data[38+i_L_IU], i_L_FI, psz_filename );
354 psz_filename[0]='\0';
357 return 4 * ( ( 38 + i_L_FI + i_L_IU + 3 ) / 4 );
361 /*****************************************************************************
362 * UDFMapICB: Maps ICB to FileAD
363 *****************************************************************************
364 * ICB: Location of ICB of directory to scan
365 * FileType: Type of the file
366 * File: Location of file the ICB is pointing to
367 * return 1 on success, 0 on error;
368 *****************************************************************************/
369 static int UDFMapICB( struct ad_s icb, u8 * pi_file_type, struct ad_s * p_file,
370 struct partition_s partition )
372 u8 pi_lb[DVD_LB_SIZE];
376 i_lba = partition.i_start + icb.i_location;
380 if( !UDFReadLB( partition.i_fd, i_lba++, 1, pi_lb ) )
386 UDFDescriptor( pi_lb , &i_tag_id );
389 if( i_tag_id == 261 )
391 UDFFileEntry( pi_lb, pi_file_type, p_file, partition );
395 } while( ( i_lba <= partition.i_start + icb.i_location +
396 ( icb.i_length - 1 ) / DVD_LB_SIZE ) && ( i_tag_id != 261 ) );
401 /*****************************************************************************
402 * UDFScanDir: serach filename in dir
403 *****************************************************************************
404 * Dir: Location of directory to scan
405 * FileName: Name of file to look for
406 * FileICB: Location of ICB of the found file
407 * return 1 on success, 0 on error;
408 *****************************************************************************/
409 static int UDFScanDir( struct ad_s dir, char * psz_filename,
410 struct ad_s * p_file_icb, struct partition_s partition )
412 u8 pi_lb[2*DVD_LB_SIZE];
416 char psz_temp[DVD_LB_SIZE];
419 /* Scan dir for ICB of file */
420 i_lba = partition.i_start + dir.i_location;
424 if( !UDFReadLB( partition.i_fd, i_lba++, 1, pi_lb ) )
431 while( p < DVD_LB_SIZE )
433 UDFDescriptor( &pi_lb[p], &i_tag_id );
435 if( i_tag_id == 257 )
437 p += UDFFileIdentifier( &pi_lb[p], &i_file_char,
438 psz_temp, p_file_icb, partition );
439 if( !strcasecmp( psz_filename, psz_temp ) )
452 partition.i_start + dir.i_location + ( dir.i_length - 1 ) / DVD_LB_SIZE );
456 if( UDFReadLB( partition.i_fd, i_lba, 2, pi_lb ) <= 0 ) {
461 while( p < dir.i_length )
463 if( p > DVD_LB_SIZE )
467 dir.i_length -= DVD_LB_SIZE;
468 if( UDFReadLB( partition.i_fd, i_lba, 2, pi_lb ) <= 0 )
474 UDFDescriptor( &pi_lb[p], &i_tag_id );
476 if( i_tag_id == 257 )
478 p += UDFFileIdentifier( &pi_lb[p], &i_file_char,
479 psz_temp, p_file_icb, partition );
480 if( !strcasecmp( psz_filename, psz_temp ) )
495 /*****************************************************************************
496 * UDFFindPartition: looks for a partition on the disc
497 *****************************************************************************
498 * partnum: number of the partition, starting at 0
499 * part: structure to fill with the partition information
500 * return 1 if partition found, 0 on error;
501 *****************************************************************************/
502 static int UDFFindPartition( int i_part_nb, struct partition_s *p_partition )
504 u8 pi_lb[DVD_LB_SIZE];
505 u8 pi_anchor[DVD_LB_SIZE];
512 boolean_t b_vol_valid;
518 /* try #1, prime anchor */
522 /* Search anchor loop */
525 if( UDFReadLB( p_partition->i_fd, i_lba, 1, pi_anchor ) )
527 UDFDescriptor( pi_anchor, &i_tag_id );
539 /* final try failed */
545 /* we already found the last sector
546 * try #3, alternative backup anchor */
547 i_lba = i_last_sector;
549 /* but that's just about enough, then! */
554 /* TODO: find last sector of the disc (this is optional) */
557 /* try #2, backup anchor */
558 i_lba = i_last_sector - 256;
562 /* unable to find last sector */
569 /* it is an anchor! continue... */
574 /* main volume descriptor */
575 UDFExtentAD( &pi_anchor[16], &i_MVDS_length, &i_MVDS_location );
577 p_partition->b_valid = 0;
579 p_partition->pi_volume_desc[0] = '\0';
582 /* Find Volume Descriptor */
585 i_lba = i_MVDS_location;
589 if( !UDFReadLB( p_partition->i_fd, i_lba++, 1, pi_lb ) )
595 UDFDescriptor( pi_lb, &i_tag_id );
598 if( ( i_tag_id == 5 ) && ( !p_partition->b_valid ) )
600 /* Partition Descriptor */
602 &p_partition->i_flags,
603 &p_partition->i_number,
604 p_partition->pi_contents,
605 &p_partition->i_start,
606 &p_partition->i_length );
607 p_partition->b_valid = ( i_part_nb == p_partition->i_number );
609 else if( ( i_tag_id == 6 ) && ( !b_vol_valid) )
611 /* Logical Volume Descriptor */
612 if( UDFLogVolume( pi_lb , p_partition->pi_volume_desc ) )
614 /* TODO: sector size wrong! */
622 } while( ( i_lba <= i_MVDS_location +
623 ( i_MVDS_length - 1 ) / DVD_LB_SIZE )
625 && ( ( !p_partition->b_valid ) || ( !b_vol_valid ) ) );
627 if( ( !p_partition->b_valid ) || ( !b_vol_valid ) )
629 /* backup volume descriptor */
630 UDFExtentAD( &pi_anchor[24], &i_MVDS_length, &i_MVDS_location );
632 } while( i-- && ( ( !p_partition->b_valid ) || ( !b_vol_valid ) ) );
634 /* we only care for the partition, not the volume */
635 return( p_partition->b_valid);
639 /*****************************************************************************
640 * UDFFindFile: looks for a file on the UDF disc/imagefile
641 *****************************************************************************
642 * Path has to be the absolute pathname on the UDF filesystem,
644 * returns absolute LB number, or 0 on error
645 *****************************************************************************/
646 u32 UDFFindFile( int i_fd, char * psz_path )
648 struct partition_s partition;
649 struct ad_s root_icb;
654 u8 pi_lb[DVD_LB_SIZE];
656 char psz_tokenline[DVD_LB_SIZE] = "";
660 strcat( psz_tokenline, psz_path );
662 /* Init file descriptor of UDF filesystem (== DVD) */
663 partition.i_fd = i_fd;
665 /* Find partition 0, standard partition for DVD-Video */
667 if( !UDFFindPartition( i_partition, &partition ) )
669 intf_ErrMsg( "UDF: Partition 0 not found" );
673 /* Find root dir ICB */
674 i_lba = partition.i_start;
678 if( !UDFReadLB( i_fd, i_lba++, 1, pi_lb ) )
684 UDFDescriptor( pi_lb, &i_tag_id );
687 if( i_tag_id == 256 )
689 /* File Set Descriptor */
690 UDFAD( &pi_lb[400], &root_icb, UDFADlong, partition );
693 } while( ( i_lba < partition.i_start + partition.i_length )
694 && ( i_tag_id != 8) && ( i_tag_id != 256 ) );
696 if( i_tag_id != 256 )
698 intf_ErrMsg( "UDF: Bad descriptor" );
701 if( root_icb.i_partition != i_partition )
703 intf_ErrMsg( "UDF: Bad partition" );
708 if( !UDFMapICB( root_icb, &i_file_type, &file, partition ) )
710 intf_ErrMsg( "UDF: Can't find root dir" );
714 /* root dir should be dir */
715 if( i_file_type != 4 )
717 intf_ErrMsg( "UDF: Root dir error" );
721 /* Tokenize filepath */
722 psz_token = strtok( psz_tokenline, "/" );
725 if( !UDFScanDir( file, psz_token, &icb, partition ) )
727 intf_ErrMsg( "UDF: Scan dir error" );
731 if( !UDFMapICB ( icb, &i_file_type, &file, partition ) )
733 intf_ErrMsg( "UDF: ICB error" );
737 psz_token = strtok( NULL, "/" );
740 return partition.i_start + file.i_location;