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.21 2002/06/01 12:31:59 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 *****************************************************************************/
31 /*****************************************************************************
33 *****************************************************************************/
42 #elif defined( _MSC_VER ) && defined( _WIN32 )
46 #ifdef STRNCASECMP_IN_STRINGS_H
51 # include "dummy_dvdcss.h"
53 # include <dvdcss/dvdcss.h>
63 typedef struct partition_s
66 u8 pi_volume_desc[128];
73 dvdcss_handle dvdhandle;
84 /* for direct data access, LSB first */
85 #define GETN1(p) ((u8)pi_data[p])
86 #define GETN2(p) ((u16)pi_data[p]|((u16)pi_data[(p)+1]<<8))
87 #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))
88 #define GETN(p,n,target) memcpy(target,&pi_data[p],n)
91 /*****************************************************************************
92 * UDFReadLB: reads absolute Logical Block of the disc
93 *****************************************************************************
94 * Returns number of read bytes on success, 0 on error
95 *****************************************************************************/
96 static int UDFReadLB( dvdcss_handle dvdhandle, off_t i_lba,
97 size_t i_block_count, u8 *pi_data )
99 if( dvdcss_seek( dvdhandle, i_lba, DVDCSS_NOFLAGS ) < 0 )
101 //X intf_ErrMsg( "dvd error: block %i not found", i_lba );
105 return dvdcss_read( dvdhandle, pi_data, i_block_count, DVDCSS_NOFLAGS );
109 /*****************************************************************************
110 * UDFDecode: decode unicode encoded udf data
111 *****************************************************************************/
112 static int UDFDecode( u8 * pi_data, int i_len, char * psz_target )
117 if( !( pi_data[0] & 0x18 ) )
119 psz_target[0] = '\0';
123 if( pi_data[0] & 0x10 )
125 /* ignore MSB of unicode16 */
130 psz_target[i++] = pi_data[p+=2];
137 psz_target[i++] = pi_data[p++];
151 int UDFEntity (u8 *data, u8 *Flags, char *Identifier)
154 strncpy (Identifier, &data[1], 5);
161 /*****************************************************************************
162 * UDFDescriptor: gives a tag ID from your data to find out what it refers to
163 *****************************************************************************/
164 static int UDFDescriptor( u8 * pi_data, u16 * pi_tag_id )
166 pi_tag_id[0] = GETN2( 0 );
167 /* TODO: check CRC 'n stuff */
173 /*****************************************************************************
174 * UDFExtendAD: main volume information
175 *****************************************************************************/
176 static int UDFExtentAD (u8 * pi_data, u32 * pi_length, u32 * pi_location)
178 pi_length[0] = GETN4( 0 );
179 pi_location[0] = GETN4( 4 );
185 /*****************************************************************************
186 * UDFAD: file set information
187 *****************************************************************************/
188 static int UDFAD( u8 * pi_data, struct ad_s * p_ad, u8 i_type,
189 struct partition_s partition )
191 p_ad->i_length = GETN4( 0 );
192 p_ad->i_flags = p_ad->i_length >> 30;
193 p_ad->i_length &= 0x3FFFFFFF;
198 p_ad->i_location = GETN4( 4 );
199 /* use number of current partition */
200 p_ad->i_partition = partition.i_number;
204 p_ad->i_location = GETN4( 4 );
205 p_ad->i_partition = GETN2( 8 );
209 p_ad->i_location = GETN4( 12 );
210 p_ad->i_partition = GETN2( 16 );
218 /*****************************************************************************
219 * UDFICB: takes Information Control Block from pi_data
220 *****************************************************************************/
221 static int UDFICB( u8 * pi_data, u8 * pi_file_type, u16 * pi_flags)
223 pi_file_type[0] = GETN1( 11 );
224 pi_flags[0] = GETN2( 18 );
230 /*****************************************************************************
231 * UDFPartition: gets partition descriptor
232 *****************************************************************************/
233 static int UDFPartition( u8 * pi_data, u16 * pi_flags, u16 * pi_nb,
234 char * ps_contents, u32 * pi_start, u32 * pi_length )
236 pi_flags[0] = GETN2( 20 );
237 pi_nb[0] = GETN2( 22 );
238 GETN( 24, 32, ps_contents );
239 pi_start[0] = GETN4( 188 );
240 pi_length[0] = GETN4( 192 );
246 /*****************************************************************************
247 * UDFLogVolume: reads the volume descriptor and checks the parameters
248 *****************************************************************************
249 * Returns 0 on OK, 1 on error
250 *****************************************************************************/
251 static int UDFLogVolume(u8 * pi_data, char * p_volume_descriptor )
257 UDFDecode( &pi_data[84], 128, p_volume_descriptor );
259 i_lb_size = GETN4( 212 ); // should be 2048
260 i_MT_L = GETN4( 264 ); // should be 6
261 i_N_PM = GETN4( 268 ); // should be 1
263 if( i_lb_size != DVD_LB_SIZE )
265 //X intf_ErrMsg( "dvd error: invalid UDF sector size (%d)", i_lb_size );
273 /*****************************************************************************
274 * UDFFileEntry: fills a ad_t struct with information at pi_data
275 *****************************************************************************/
276 static int UDFFileEntry( u8 * pi_data, u8 * pi_file_type, struct ad_s * p_ad,
277 struct partition_s partition )
285 UDFICB( &pi_data[16], &i_file_type, &i_flags );
287 pi_file_type[0] = i_file_type;
288 i_L_EA = GETN4( 168 );
289 i_L_AD = GETN4( 172 );
292 while( p < 176 + i_L_EA + i_L_AD )
294 switch( i_flags & 0x07 )
297 UDFAD( &pi_data[p], p_ad, UDFADshort, partition );
301 UDFAD( &pi_data[p], p_ad, UDFADlong, partition );
305 UDFAD( &pi_data[p], p_ad, UDFADext, partition );
312 UDFAD( &pi_data[p], p_ad, UDFADshort, partition );
315 UDFAD( &pi_data[p], p_ad, UDFADlong, partition );
318 UDFAD( &pi_data[p], p_ad, UDFADext, partition );
331 /*****************************************************************************
332 * UDFFileIdentifier: gives filename and characteristics of pi_data
333 *****************************************************************************/
334 static int UDFFileIdentifier( u8 * pi_data, u8 * pi_file_characteristics,
335 char * psz_filename, struct ad_s * p_file_icb,
336 struct partition_s partition )
341 pi_file_characteristics[0] = GETN1( 18 );
342 i_L_FI = GETN1( 19 );
343 UDFAD( &pi_data[20], p_file_icb, UDFADlong, partition );
344 i_L_IU = GETN2( 36 );
348 UDFDecode( &pi_data[38+i_L_IU], i_L_FI, psz_filename );
352 psz_filename[0]='\0';
355 return 4 * ( ( 38 + i_L_FI + i_L_IU + 3 ) / 4 );
359 /*****************************************************************************
360 * UDFMapICB: Maps ICB to FileAD
361 *****************************************************************************
362 * ICB: Location of ICB of directory to scan
363 * FileType: Type of the file
364 * File: Location of file the ICB is pointing to
365 * return 1 on success, 0 on error;
366 *****************************************************************************/
367 static int UDFMapICB( struct ad_s icb, u8 * pi_file_type, struct ad_s * p_file,
368 struct partition_s partition )
370 u8 pi_lb[DVD_LB_SIZE];
374 i_lba = partition.i_start + icb.i_location;
378 if( !UDFReadLB( partition.dvdhandle, i_lba++, 1, pi_lb ) )
384 UDFDescriptor( pi_lb , &i_tag_id );
387 if( i_tag_id == 261 )
389 UDFFileEntry( pi_lb, pi_file_type, p_file, partition );
393 } while( ( i_lba <= partition.i_start + icb.i_location +
394 ( icb.i_length - 1 ) / DVD_LB_SIZE ) && ( i_tag_id != 261 ) );
399 /*****************************************************************************
400 * UDFScanDir: serach filename in dir
401 *****************************************************************************
402 * Dir: Location of directory to scan
403 * FileName: Name of file to look for
404 * FileICB: Location of ICB of the found file
405 * return 1 on success, 0 on error;
406 *****************************************************************************/
407 static int UDFScanDir( struct ad_s dir, char * psz_filename,
408 struct ad_s * p_file_icb, struct partition_s partition )
410 u8 pi_lb[2*DVD_LB_SIZE];
414 char psz_temp[DVD_LB_SIZE];
417 /* Scan dir for ICB of file */
418 i_lba = partition.i_start + dir.i_location;
422 if( !UDFReadLB( partition.dvdhandle, i_lba++, 1, pi_lb ) )
429 while( p < DVD_LB_SIZE )
431 UDFDescriptor( &pi_lb[p], &i_tag_id );
433 if( i_tag_id == 257 )
435 p += UDFFileIdentifier( &pi_lb[p], &i_file_char,
436 psz_temp, p_file_icb, partition );
437 if( !strcasecmp( psz_filename, psz_temp ) )
450 partition.i_start + dir.i_location + ( dir.i_length - 1 ) / DVD_LB_SIZE );
454 if( UDFReadLB( partition.dvdhandle, i_lba, 2, pi_lb ) <= 0 ) {
459 while( p < dir.i_length )
461 if( p > DVD_LB_SIZE )
465 dir.i_length -= DVD_LB_SIZE;
466 if( UDFReadLB( partition.dvdhandle, i_lba, 2, pi_lb ) <= 0 )
472 UDFDescriptor( &pi_lb[p], &i_tag_id );
474 if( i_tag_id == 257 )
476 p += UDFFileIdentifier( &pi_lb[p], &i_file_char,
477 psz_temp, p_file_icb, partition );
478 if( !strcasecmp( psz_filename, psz_temp ) )
493 /*****************************************************************************
494 * UDFFindPartition: looks for a partition on the disc
495 *****************************************************************************
496 * partnum: number of the partition, starting at 0
497 * part: structure to fill with the partition information
498 * return 1 if partition found, 0 on error;
499 *****************************************************************************/
500 static int UDFFindPartition( int i_part_nb, struct partition_s *p_partition )
502 u8 pi_lb[DVD_LB_SIZE];
503 u8 pi_anchor[DVD_LB_SIZE];
510 vlc_bool_t b_vol_valid;
516 /* try #1, prime anchor */
520 /* Search anchor loop */
523 if( UDFReadLB( p_partition->dvdhandle, i_lba, 1, pi_anchor ) )
525 UDFDescriptor( pi_anchor, &i_tag_id );
537 /* final try failed */
543 /* we already found the last sector
544 * try #3, alternative backup anchor */
545 i_lba = i_last_sector;
547 /* but that's just about enough, then! */
552 /* TODO: find last sector of the disc (this is optional) */
555 /* try #2, backup anchor */
556 i_lba = i_last_sector - 256;
560 /* unable to find last sector */
567 /* it is an anchor! continue... */
572 /* main volume descriptor */
573 UDFExtentAD( &pi_anchor[16], &i_MVDS_length, &i_MVDS_location );
575 p_partition->b_valid = 0;
577 p_partition->pi_volume_desc[0] = '\0';
580 /* Find Volume Descriptor */
583 i_lba = i_MVDS_location;
587 if( !UDFReadLB( p_partition->dvdhandle, i_lba++, 1, pi_lb ) )
593 UDFDescriptor( pi_lb, &i_tag_id );
596 if( ( i_tag_id == 5 ) && ( !p_partition->b_valid ) )
598 /* Partition Descriptor */
600 &p_partition->i_flags,
601 &p_partition->i_number,
602 p_partition->pi_contents,
603 &p_partition->i_start,
604 &p_partition->i_length );
605 p_partition->b_valid = ( i_part_nb == p_partition->i_number );
607 else if( ( i_tag_id == 6 ) && ( !b_vol_valid) )
609 /* Logical Volume Descriptor */
610 if( UDFLogVolume( pi_lb , p_partition->pi_volume_desc ) )
612 /* TODO: sector size wrong! */
620 } while( ( i_lba <= i_MVDS_location +
621 ( i_MVDS_length - 1 ) / DVD_LB_SIZE )
623 && ( ( !p_partition->b_valid ) || ( !b_vol_valid ) ) );
625 if( ( !p_partition->b_valid ) || ( !b_vol_valid ) )
627 /* backup volume descriptor */
628 UDFExtentAD( &pi_anchor[24], &i_MVDS_length, &i_MVDS_location );
630 } while( i-- && ( ( !p_partition->b_valid ) || ( !b_vol_valid ) ) );
632 /* we only care for the partition, not the volume */
633 return( p_partition->b_valid);
637 /*****************************************************************************
638 * DVDUDFFindFile: looks for a file on the UDF disc/imagefile
639 *****************************************************************************
640 * Path has to be the absolute pathname on the UDF filesystem,
642 * returns absolute LB number, or 0 on error
643 *****************************************************************************/
644 u32 DVDUDFFindFile( dvdcss_handle dvdhandle, char * psz_path )
646 struct partition_s partition;
647 struct ad_s root_icb;
652 u8 pi_lb[DVD_LB_SIZE];
654 char psz_tokenline[DVD_LB_SIZE] = "";
658 strcat( psz_tokenline, psz_path );
660 /* Init file descriptor of UDF filesystem (== DVD) */
661 partition.dvdhandle = dvdhandle;
663 /* Find partition 0, standard partition for DVD-Video */
665 if( !UDFFindPartition( i_partition, &partition ) )
667 //X intf_ErrMsg( "dvd error: partition 0 not found" );
671 /* Find root dir ICB */
672 i_lba = partition.i_start;
676 if( !UDFReadLB( dvdhandle, i_lba++, 1, pi_lb ) )
682 UDFDescriptor( pi_lb, &i_tag_id );
685 if( i_tag_id == 256 )
687 /* File Set Descriptor */
688 UDFAD( &pi_lb[400], &root_icb, UDFADlong, partition );
691 } while( ( i_lba < partition.i_start + partition.i_length )
692 && ( i_tag_id != 8) && ( i_tag_id != 256 ) );
694 if( i_tag_id != 256 )
696 //X intf_ErrMsg( "dvd error: bad UDF descriptor" );
699 if( root_icb.i_partition != i_partition )
701 //X intf_ErrMsg( "dvd error: bad UDF partition" );
706 if( !UDFMapICB( root_icb, &i_file_type, &file, partition ) )
708 //X intf_ErrMsg( "dvd error: can't find root dir" );
712 /* root dir should be dir */
713 if( i_file_type != 4 )
715 //X intf_ErrMsg( "dvd error: root dir error" );
719 /* Tokenize filepath */
720 psz_token = strtok( psz_tokenline, "/" );
723 if( !UDFScanDir( file, psz_token, &icb, partition ) )
725 //X intf_ErrMsg( "dvd error: scan dir error" );
729 if( !UDFMapICB ( icb, &i_file_type, &file, partition ) )
731 //X intf_ErrMsg( "dvd error: ICB error" );
735 psz_token = strtok( NULL, "/" );
738 return partition.i_start + file.i_location;