1 /*****************************************************************************
2 * dvd_udf.c: udf filesystem tools.
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.3 2001/02/20 07:49:12 sam Exp $
10 * Author: Stéphane Borel <stef@via.ecp.fr>
13 * - dvdudf by Christian Wolff <scarabaeus@convergence.de>
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
28 *****************************************************************************/
30 #define MODULE_NAME dvd
31 #include "modules_inner.h"
47 #include "input_dvd.h"
53 typedef struct partition_s
56 u8 pi_volume_desc[128];
74 /* for direct data access, LSB first */
75 #define GETN1(p) ((u8)pi_data[p])
76 #define GETN2(p) ((u16)pi_data[p]|((u16)pi_data[(p)+1]<<8))
77 #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))
78 #define GETN(p,n,target) memcpy(target,&pi_data[p],n)
81 /*****************************************************************************
82 * UDFReadLB: reads absolute Logical Block of the disc
84 * returns number of read bytes on success, 0 on error
85 *****************************************************************************/
86 static int UDFReadLB( int i_fd, off_t i_lba, size_t i_block_count, u8 *pi_data )
93 if( lseek( i_fd, i_lba * (off_t) DVD_LB_SIZE, SEEK_SET ) < 0 )
95 intf_ErrMsg( "UDF: Postion not found" );
99 return read( i_fd, pi_data, i_block_count *DVD_LB_SIZE);
103 /*****************************************************************************
104 * UDFDecode: decode unicode encoded udf data
105 *****************************************************************************/
106 static int UDFDecode( u8 * pi_data, int i_len, char * psz_target )
111 if( !( pi_data[0] & 0x18 ) )
113 psz_target[0] = '\0';
117 if( pi_data[0] & 0x10 )
119 /* ignore MSB of unicode16 */
124 psz_target[i++] = pi_data[p+=2];
131 psz_target[i++] = pi_data[p++];
145 int UDFEntity (u8 *data, u8 *Flags, char *Identifier)
148 strncpy (Identifier, &data[1], 5);
155 /*****************************************************************************
156 * UDFDescriptor: gives a tag ID from your data to find out what it refers to
157 *****************************************************************************/
158 static int UDFDescriptor( u8 * pi_data, u16 * pi_tag_id )
160 pi_tag_id[0] = GETN2( 0 );
161 /* TODO: check CRC 'n stuff */
167 /*****************************************************************************
168 * UDFExtendAD: main volume information
169 *****************************************************************************/
170 static int UDFExtentAD (u8 * pi_data, u32 * pi_length, u32 * pi_location)
172 pi_length[0] = GETN4( 0 );
173 pi_location[0] = GETN4( 4 );
179 /*****************************************************************************
180 * UDFAD: file set information
181 *****************************************************************************/
182 static int UDFAD( u8 * pi_data, struct ad_s * p_ad, u8 i_type,
183 struct partition_s partition )
185 p_ad->i_length = GETN4( 0 );
186 p_ad->i_flags = p_ad->i_length >> 30;
187 p_ad->i_length &= 0x3FFFFFFF;
192 p_ad->i_location = GETN4( 4 );
193 /* use number of current partition */
194 p_ad->i_partition = partition.i_number;
198 p_ad->i_location = GETN4( 4 );
199 p_ad->i_partition = GETN2( 8 );
203 p_ad->i_location = GETN4( 12 );
204 p_ad->i_partition = GETN2( 16 );
212 /*****************************************************************************
213 * UDFICB: takes Information Control Block from pi_data
214 *****************************************************************************/
215 static int UDFICB( u8 * pi_data, u8 * pi_file_type, u16 * pi_flags)
217 pi_file_type[0] = GETN1( 11 );
218 pi_flags[0] = GETN2( 18 );
224 /*****************************************************************************
225 * UDFPartition: gets partition descriptor
226 *****************************************************************************/
227 static int UDFPartition( u8 * pi_data, u16 * pi_flags, u16 * pi_nb,
228 char * ps_contents, u32 * pi_start, u32 * pi_length )
230 pi_flags[0] = GETN2( 20 );
231 pi_nb[0] = GETN2( 22 );
232 GETN( 24, 32, ps_contents );
233 pi_start[0] = GETN4( 188 );
234 pi_length[0] = GETN4( 192 );
240 /*****************************************************************************
241 * UDFLogVolume: reads the volume descriptor and checks the parameters
243 * returns 0 on OK, 1 on error
244 *****************************************************************************/
245 static int UDFLogVolume(u8 * pi_data, char * p_volume_descriptor )
251 UDFDecode( &pi_data[84], 128, p_volume_descriptor );
253 i_lb_size = GETN4( 212 ); // should be 2048
254 i_MT_L = GETN4( 264 ); // should be 6
255 i_N_PM = GETN4( 268 ); // should be 1
257 if( i_lb_size != DVD_LB_SIZE )
259 intf_ErrMsg( "UDF: Non valid sector size (%d)", i_lb_size );
267 /*****************************************************************************
268 * UDFFileEntry: fills a ad_t struct with information at pi_data
269 *****************************************************************************/
270 static int UDFFileEntry( u8 * pi_data, u8 * pi_file_type, struct ad_s * p_ad,
271 struct partition_s partition )
279 UDFICB( &pi_data[16], &i_file_type, &i_flags );
281 pi_file_type[0] = i_file_type;
282 i_L_EA = GETN4( 168 );
283 i_L_AD = GETN4( 172 );
286 while( p < 176 + i_L_EA + i_L_AD )
288 switch( i_flags & 0x07 )
291 UDFAD( &pi_data[p], p_ad, UDFADshort, partition );
295 UDFAD( &pi_data[p], p_ad, UDFADlong, partition );
299 UDFAD( &pi_data[p], p_ad, UDFADext, partition );
306 UDFAD( &pi_data[p], p_ad, UDFADshort, partition );
309 UDFAD( &pi_data[p], p_ad, UDFADlong, partition );
312 UDFAD( &pi_data[p], p_ad, UDFADext, partition );
325 /*****************************************************************************
326 * UDFFileIdentifier: gives filename and characteristics of pi_data
327 *****************************************************************************/
328 static int UDFFileIdentifier( u8 * pi_data, u8 * pi_file_characteristics,
329 char * psz_filename, struct ad_s * p_file_icb,
330 struct partition_s partition )
335 pi_file_characteristics[0] = GETN1( 18 );
336 i_L_FI = GETN1( 19 );
337 UDFAD( &pi_data[20], p_file_icb, UDFADlong, partition );
338 i_L_IU = GETN2( 36 );
342 UDFDecode( &pi_data[38+i_L_IU], i_L_FI, psz_filename );
346 psz_filename[0]='\0';
349 return 4 * ( ( 38 + i_L_FI + i_L_IU + 3 ) / 4 );
353 /*****************************************************************************
354 * UDFMapICB: Maps ICB to FileAD
356 * ICB: Location of ICB of directory to scan
357 * FileType: Type of the file
358 * File: Location of file the ICB is pointing to
359 * return 1 on success, 0 on error;
360 *****************************************************************************/
361 static int UDFMapICB( struct ad_s icb, u8 * pi_file_type, struct ad_s * p_file,
362 struct partition_s partition )
364 u8 pi_lb[DVD_LB_SIZE];
368 i_lba = partition.i_start + icb.i_location;
372 if( !UDFReadLB( partition.i_fd, i_lba++, 1, pi_lb ) )
378 UDFDescriptor( pi_lb , &i_tag_id );
381 if( i_tag_id == 261 )
383 UDFFileEntry( pi_lb, pi_file_type, p_file, partition );
387 } while( ( i_lba <= partition.i_start + icb.i_location +
388 ( icb.i_length - 1 ) / DVD_LB_SIZE ) && ( i_tag_id != 261 ) );
393 /*****************************************************************************
394 * UDFScanDir: serach filename in dir
396 * Dir: Location of directory to scan
397 * FileName: Name of file to look for
398 * FileICB: Location of ICB of the found file
399 * return 1 on success, 0 on error;
400 *****************************************************************************/
401 static int UDFScanDir( struct ad_s dir, char * psz_filename,
402 struct ad_s * p_file_icb, struct partition_s partition )
404 u8 pi_lb[DVD_LB_SIZE];
408 char psz_temp[DVD_LB_SIZE];
411 /* Scan dir for ICB of file */
412 i_lba = partition.i_start + dir.i_location;
416 if( !UDFReadLB( partition.i_fd, i_lba++, 1, pi_lb ) )
423 while( p < DVD_LB_SIZE )
425 UDFDescriptor( &pi_lb[p], &i_tag_id );
427 if( i_tag_id == 257 )
429 p += UDFFileIdentifier( &pi_lb[p], &i_file_char,
430 psz_temp, p_file_icb, partition );
431 if( !strcasecmp( psz_filename, psz_temp ) )
444 partition.i_start + dir.i_location + ( dir.i_length - 1 ) / DVD_LB_SIZE );
450 /******************************************************************************
451 * UDFFindPartition: looks for a partition on the disc
453 * partnum: number of the partition, starting at 0
454 * part: structure to fill with the partition information
455 * return 1 if partition found, 0 on error;
456 ******************************************************************************/
457 static int UDFFindPartition( int i_part_nb, struct partition_s *p_partition )
459 u8 pi_lb[DVD_LB_SIZE];
460 u8 pi_anchor[DVD_LB_SIZE];
467 boolean_t b_vol_valid;
473 /* try #1, prime anchor */
477 /* Search anchor loop */
480 if( UDFReadLB( p_partition->i_fd, i_lba, 1, pi_anchor ) )
482 UDFDescriptor( pi_anchor, &i_tag_id );
494 /* final try failed */
500 /* we already found the last sector
501 * try #3, alternative backup anchor */
502 i_lba = i_last_sector;
504 /* but that's just about enough, then! */
509 /* TODO: find last sector of the disc (this is optional) */
512 /* try #2, backup anchor */
513 i_lba = i_last_sector - 256;
517 /* unable to find last sector */
524 /* it is an anchor! continue... */
529 /* main volume descriptor */
530 UDFExtentAD( &pi_anchor[16], &i_MVDS_length, &i_MVDS_location );
532 p_partition->b_valid = 0;
534 p_partition->pi_volume_desc[0] = '\0';
537 /* Find Volume Descriptor */
540 i_lba = i_MVDS_location;
544 if( !UDFReadLB( p_partition->i_fd, i_lba++, 1, pi_lb ) )
550 UDFDescriptor( pi_lb, &i_tag_id );
553 if( ( i_tag_id == 5 ) && ( !p_partition->b_valid ) )
555 /* Partition Descriptor */
557 &p_partition->i_flags,
558 &p_partition->i_number,
559 p_partition->pi_contents,
560 &p_partition->i_start,
561 &p_partition->i_length );
562 p_partition->b_valid = ( i_part_nb == p_partition->i_number );
564 else if( ( i_tag_id == 6 ) && ( !b_vol_valid) )
566 /* Logical Volume Descriptor */
567 if( UDFLogVolume( pi_lb , p_partition->pi_volume_desc ) )
569 /* TODO: sector size wrong! */
577 } while( ( i_lba <= i_MVDS_location +
578 ( i_MVDS_length - 1 ) / DVD_LB_SIZE )
580 && ( ( !p_partition->b_valid ) || ( !b_vol_valid ) ) );
582 if( ( !p_partition->b_valid ) || ( !b_vol_valid ) )
584 /* backup volume descriptor */
585 UDFExtentAD( &pi_anchor[24], &i_MVDS_length, &i_MVDS_location );
587 } while( i-- && ( ( !p_partition->b_valid ) || ( !b_vol_valid ) ) );
589 /* we only care for the partition, not the volume */
590 return( p_partition->b_valid);
594 /******************************************************************************
595 * UDFFindFile: looks for a file on the UDF disc/imagefile
597 * Path has to be the absolute pathname on the UDF filesystem,
599 * returns absolute LB number, or 0 on error
600 ******************************************************************************/
601 u32 UDFFindFile( int i_fd, char * psz_path )
603 struct partition_s partition;
604 struct ad_s root_icb;
609 u8 pi_lb[DVD_LB_SIZE];
611 char psz_tokenline[DVD_LB_SIZE] = "";
615 strcat( psz_tokenline, psz_path );
617 /* Init file descriptor of UDF filesystem (== DVD) */
618 partition.i_fd = i_fd;
620 /* Find partition 0, standard partition for DVD-Video */
622 if( !UDFFindPartition( i_partition, &partition ) )
624 intf_ErrMsg( "UDF: Partition 0 not found" );
628 /* Find root dir ICB */
629 i_lba = partition.i_start;
633 if( !UDFReadLB( i_fd, i_lba++, 1, pi_lb ) )
639 UDFDescriptor( pi_lb, &i_tag_id );
642 if( i_tag_id == 256 )
644 /* File Set Descriptor */
645 UDFAD( &pi_lb[400], &root_icb, UDFADlong, partition );
648 } while( ( i_lba < partition.i_start + partition.i_length )
649 && ( i_tag_id != 8) && ( i_tag_id != 256 ) );
651 if( i_tag_id != 256 )
653 intf_ErrMsg( "UDF: Bad descriptor" );
656 if( root_icb.i_partition != i_partition )
658 intf_ErrMsg( "UDF: Bad partition" );
663 if( !UDFMapICB( root_icb, &i_file_type, &file, partition ) )
665 intf_ErrMsg( "UDF: Can't find root dir" );
669 /* root dir should be dir */
670 if( i_file_type != 4 )
672 intf_ErrMsg( "UDF: Root dir error" );
676 /* Tokenize filepath */
677 psz_token = strtok( psz_tokenline, "/" );
680 if( !UDFScanDir( file, psz_token, &icb, partition ) )
682 intf_ErrMsg( "UDF: Scan dir error" );
686 if( !UDFMapICB ( icb, &i_file_type, &file, partition ) )
688 intf_ErrMsg( "UDF: ICB error" );
692 psz_token = strtok( NULL, "/" );
695 return partition.i_start + file.i_location;