1 /*****************************************************************************
2 * dvd_ifo.c: Functions for ifo parsing
3 *****************************************************************************
4 * Copyright (C) 1999-2001 VideoLAN
5 * $Id: dvd_ifo.c,v 1.39 2001/11/07 03:37:27 stef Exp $
7 * Authors: Stéphane Borel <stef@via.ecp.fr>
8 * German Tischler <tanis@gaspode.franken.de>
11 * - libifo by Thomas Mirlacher <dent@cosy.sbg.ac.at>
12 * - IFO structure documentation by Thomas Mirlacher, Björn Englund,
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 /*****************************************************************************
32 *****************************************************************************/
41 #elif defined( _MSC_VER ) && defined( _WIN32 )
49 # include "dummy_dvdcss.h"
51 # include <videolan/dvdcss.h>
61 #include "input_dvd.h"
66 #include "modules_export.h"
68 /*****************************************************************************
70 *****************************************************************************/
71 void CommandRead ( command_desc_t );
72 static int ReadTitle ( ifo_t * , title_t *, int, int );
73 static int FreeTitle ( title_t * );
74 static int ReadUnitInf ( ifo_t * , unit_inf_t *, int, int );
75 static int FreeUnitInf ( unit_inf_t * );
76 static int ReadTitleUnit ( ifo_t * , title_unit_t *, int );
77 static int FreeTitleUnit ( title_unit_t * );
78 static int ReadVobuMap ( ifo_t * , vobu_map_t *, int );
79 static int FreeVobuMap ( vobu_map_t * );
80 static int ReadCellInf ( ifo_t * , cell_inf_t *, int );
81 static int FreeCellInf ( cell_inf_t * );
82 static int FreeTitleSet ( vts_t * );
84 static u8* FillBuffer ( ifo_t *, u8 *, int );
85 static u8 ReadByte ( ifo_t *, u8 *, u8 ** );
86 static void ReadBytes ( ifo_t *, u8 *, u8 **, u8 *, int );
87 static void DumpBytes ( ifo_t *, u8 *, u8 **, int );
88 static u16 ReadWord ( ifo_t *, u8 *, u8 ** );
89 static u32 ReadDouble ( ifo_t *, u8 *, u8 ** );
90 static u64 ReadQuad ( ifo_t *, u8 *, u8 ** );
96 /*****************************************************************************
97 * IfoCreate : Creates an ifo structure and prepares for parsing directly
99 *****************************************************************************/
100 int IfoCreate( thread_dvd_data_t * p_dvd )
102 p_dvd->p_ifo = malloc( sizeof(ifo_t) );
103 if( p_dvd->p_ifo == NULL )
105 intf_ErrMsg( "ifo error: unable to allocate memory. aborting" );
109 /* if we are here the dvd device has already been opened */
110 p_dvd->p_ifo->dvdhandle = p_dvd->dvdhandle;
115 /*****************************************************************************
116 * IfoInit : Reads information from the management table.
117 *****************************************************************************/
118 int IfoInit( ifo_t * p_ifo )
120 u8 p_buf[DVD_LB_SIZE];
126 /* find the start sector of video information on the dvd */
127 p_ifo->i_start = UDFFindFile( p_ifo->dvdhandle, "/VIDEO_TS/VIDEO_TS.IFO" );
128 if( !p_ifo->i_start ) return -1;
130 p_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_start );
131 //i_start = p_ifo->i_pos;
134 * read the video manager information table
136 #define MGINF p_ifo->vmg.manager_inf
137 //fprintf( stderr, "VMGI\n" );
139 ReadBytes( p_ifo, p_buf, &p_tmp, MGINF.psz_id, 12 );
140 MGINF.psz_id[12] = '\0';
141 MGINF.i_vmg_end_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
142 DumpBytes( p_ifo, p_buf, &p_tmp, 12 );
143 MGINF.i_vmg_inf_end_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
144 DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
145 MGINF.i_spec_ver = ReadByte( p_ifo, p_buf, &p_tmp );
146 MGINF.i_cat = ReadDouble( p_ifo, p_buf, &p_tmp );
147 MGINF.i_volume_nb = ReadWord( p_ifo, p_buf, &p_tmp );
148 MGINF.i_volume = ReadWord( p_ifo, p_buf, &p_tmp );
149 MGINF.i_disc_side = ReadByte( p_ifo, p_buf, &p_tmp );
150 DumpBytes( p_ifo, p_buf, &p_tmp, 19 );
151 MGINF.i_title_set_nb = ReadWord( p_ifo, p_buf, &p_tmp );
152 ReadBytes( p_ifo, p_buf, &p_tmp, MGINF.ps_provider_id, 32 );
153 MGINF.i_pos_code = ReadQuad( p_ifo, p_buf, &p_tmp );
154 DumpBytes( p_ifo, p_buf, &p_tmp, 24 );
155 MGINF.i_vmg_inf_end_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
156 MGINF.i_first_play_title_start_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
157 DumpBytes( p_ifo, p_buf, &p_tmp, 56 );
158 MGINF.i_vob_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
159 MGINF.i_title_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
160 MGINF.i_title_unit_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
161 MGINF.i_parental_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
162 MGINF.i_vts_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
163 MGINF.i_text_data_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
164 MGINF.i_cell_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
165 MGINF.i_vobu_map_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
166 DumpBytes( p_ifo, p_buf, &p_tmp, 32 );
167 DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
168 DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
169 MGINF.i_audio_nb = ReadByte( p_ifo, p_buf, &p_tmp );
170 //fprintf( stderr, "vmgi audio nb : %d\n", MGINF.i_audio_nb );
172 for( i = 0 ; i < 8 ; i++ )
174 i_temp = ReadQuad( p_ifo, p_buf, &p_tmp );
177 DumpBytes( p_ifo, p_buf, &p_tmp, 17 );
178 MGINF.i_spu_nb = ReadByte( p_ifo, p_buf, &p_tmp );
179 //fprintf( stderr, "vmgi subpic nb : %d\n", MGINF.i_spu_nb );
181 for( i = 0 ; i < MGINF.i_spu_nb ; i++ )
183 ReadBytes( p_ifo, p_buf, &p_tmp, (u8*)(&i_temp), 6 );
184 /* FIXME : take care of endianness */
188 * read first play title.
190 //fprintf(stderr,"readtitle %i\n", MGINF.i_first_play_title_start_byte & 0x7ff );
191 if( ReadTitle( p_ifo, &p_ifo->vmg.title, p_ifo->i_start
192 + OFF2LB( MGINF.i_first_play_title_start_byte ),
193 MGINF.i_first_play_title_start_byte & 0x7ff ) < 0 )
199 * fills the title information structure.
201 #define TITINF p_ifo->vmg.title_inf
202 if( MGINF.i_title_inf_start_sector )
204 p_tmp = FillBuffer( p_ifo, p_buf,
205 p_ifo->i_start + MGINF.i_title_inf_start_sector );
206 //fprintf( stderr, "title inf %d\n", p_ifo->i_pos );
208 TITINF.i_title_nb = ReadWord( p_ifo, p_buf, &p_tmp );
209 //fprintf( stderr, "title_inf: TTU nb %d\n", TITINF.i_title_nb );
210 DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
211 TITINF.i_end_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
213 /* parsing of title attributes */
214 TITINF.p_attr = malloc( TITINF.i_title_nb *sizeof(title_attr_t) );
215 if( TITINF.p_attr == NULL )
217 intf_ErrMsg( "ifo error: out of memory in IfoInit" );
221 for( i = 0 ; i < TITINF.i_title_nb ; i++ )
223 TITINF.p_attr[i].i_play_type = ReadByte( p_ifo, p_buf, &p_tmp );
224 TITINF.p_attr[i].i_angle_nb = ReadByte( p_ifo, p_buf, &p_tmp );
225 TITINF.p_attr[i].i_chapter_nb = ReadWord( p_ifo, p_buf, &p_tmp );
226 TITINF.p_attr[i].i_parental_id = ReadWord( p_ifo, p_buf, &p_tmp );
227 TITINF.p_attr[i].i_title_set_num = ReadByte( p_ifo, p_buf, &p_tmp );
228 TITINF.p_attr[i].i_title_num = ReadByte( p_ifo, p_buf, &p_tmp );
229 TITINF.p_attr[i].i_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
230 //fprintf( stderr, "title_inf: %d %d %d\n", TITINF.p_attr[i].i_chapter_nb, TITINF.p_attr[i].i_title_set_num, TITINF.p_attr[i].i_title_num );
235 TITINF.p_attr = NULL;
240 * fills the title unit structure.
242 if( MGINF.i_title_unit_start_sector )
244 if( ReadTitleUnit( p_ifo, &p_ifo->vmg.title_unit, p_ifo->i_start
245 + MGINF.i_title_unit_start_sector ) < 0 )
252 * fills the structure about parental information.
254 #define PARINF p_ifo->vmg.parental_inf
255 if( MGINF.i_parental_inf_start_sector )
257 p_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_start +
258 MGINF.i_parental_inf_start_sector );
259 i_start = p_ifo->i_pos;
261 //fprintf( stderr, "PTL\n" );
263 PARINF.i_country_nb = ReadWord( p_ifo, p_buf, &p_tmp );
264 PARINF.i_vts_nb = ReadWord( p_ifo, p_buf, &p_tmp );
265 PARINF.i_end_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
267 PARINF.p_parental_desc = malloc( PARINF.i_country_nb
268 * sizeof(parental_desc_t) );
269 if( PARINF.p_parental_desc == NULL )
271 intf_ErrMsg( "ifo error: out of memory in IfoInit" );
275 for( i = 0 ; i < PARINF.i_country_nb ; i++ )
277 ReadBytes( p_ifo, p_buf, &p_tmp,
278 PARINF.p_parental_desc[i].ps_country_code, 2 );
279 DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
280 PARINF.p_parental_desc[i].i_parental_mask_start_byte =
281 ReadWord( p_ifo, p_buf, &p_tmp );
282 DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
285 PARINF.p_parental_mask = malloc( PARINF.i_country_nb
286 * sizeof(parental_mask_t) );
287 if( PARINF.p_parental_mask == NULL )
289 intf_ErrMsg( "ifo error: out of memory in IfoInit" );
293 for( i = 0 ; i < PARINF.i_country_nb ; i++ )
295 p_tmp = FillBuffer( p_ifo, p_buf, i_start + OFF2LB(
296 PARINF.p_parental_desc[i].i_parental_mask_start_byte ) )
297 + (PARINF.p_parental_desc[i].i_parental_mask_start_byte & 0x7ff);
299 for( j = 0 ; j < 8 ; j++ )
301 PARINF.p_parental_mask[i].ppi_mask[j] =
302 malloc( ( PARINF.i_vts_nb + 1 ) * sizeof(u16) );
304 if( PARINF.p_parental_mask[i].ppi_mask[j] == NULL )
306 intf_ErrMsg( "ifo error: out of memory in IfoInit" );
310 for( k = 0 ; k < PARINF.i_vts_nb + 1 ; k++ )
312 PARINF.p_parental_mask[i].ppi_mask[j][k] =
313 ReadWord( p_ifo, p_buf, &p_tmp );
321 * information and attributes about for each vts.
323 #define VTSINF p_ifo->vmg.vts_inf
324 if( MGINF.i_vts_inf_start_sector )
328 p_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_start +
329 MGINF.i_vts_inf_start_sector );
330 i_start = p_ifo->i_pos;
332 //fprintf( stderr, "VTS ATTR\n" );
334 VTSINF.i_vts_nb = ReadWord( p_ifo, p_buf, &p_tmp );;
335 //fprintf( stderr, "VTS ATTR Nb: %d\n", VTSINF.i_vts_nb );
336 DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
337 VTSINF.i_end_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
338 VTSINF.pi_vts_attr_start_byte =
339 malloc( VTSINF.i_vts_nb * sizeof(u32) );
340 if( VTSINF.pi_vts_attr_start_byte == NULL )
342 intf_ErrMsg( "ifo error: out of memory in IfoInit" );
346 for( i = 0 ; i < VTSINF.i_vts_nb ; i++ )
348 VTSINF.pi_vts_attr_start_byte[i] =
349 ReadDouble( p_ifo, p_buf, &p_tmp );
352 VTSINF.p_vts_attr = malloc( VTSINF.i_vts_nb * sizeof(vts_attr_t) );
353 if( VTSINF.p_vts_attr == NULL )
355 intf_ErrMsg( "ifo error: out of memory in IfoInit" );
359 for( i = 0 ; i < VTSINF.i_vts_nb ; i++ )
361 p_tmp = FillBuffer( p_ifo, p_buf, i_start +
362 OFF2LB( VTSINF.pi_vts_attr_start_byte[i] ) )
363 + ( VTSINF.pi_vts_attr_start_byte[i] & 0x7ff );
365 VTSINF.p_vts_attr[i].i_end_byte =
366 ReadDouble( p_ifo, p_buf, &p_tmp );
367 VTSINF.p_vts_attr[i].i_cat_app_type =
368 ReadDouble( p_ifo, p_buf, &p_tmp );
369 DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
370 DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
371 VTSINF.p_vts_attr[i].i_vts_menu_audio_nb =
372 ReadByte( p_ifo, p_buf, &p_tmp );
373 //fprintf( stderr, "m audio nb : %d\n", VTSINF.p_vts_attr[i].i_vts_menu_audio_nb );
375 for( j = 0 ; j < 8 ; j++ )
377 i_temp = ReadQuad( p_ifo, p_buf, &p_tmp );
380 DumpBytes( p_ifo, p_buf, &p_tmp, 17 );
381 VTSINF.p_vts_attr[i].i_vts_menu_spu_nb =
382 ReadByte( p_ifo, p_buf, &p_tmp );
383 //fprintf( stderr, "m subp nb : %d\n", VTSINF.p_vts_attr[i].i_vts_menu_spu_nb );
385 for( j = 0 ; j < 28 ; j++ )
387 /* FIXME : Fix endianness issue here */
388 ReadBytes( p_ifo, p_buf, &p_tmp, (u8*)(&i_temp), 6 );
391 DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
392 DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
393 DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
394 VTSINF.p_vts_attr[i].i_vts_title_audio_nb =
395 ReadDouble( p_ifo, p_buf, &p_tmp );
396 //fprintf( stderr, "tt audio nb : %d\n", VTSINF.p_vts_attr[i].i_vts_title_audio_nb );
398 for( j = 0 ; j < 8 ; j++ )
400 i_temp = ReadQuad( p_ifo, p_buf, &p_tmp );;
403 DumpBytes( p_ifo, p_buf, &p_tmp, 17 );
404 VTSINF.p_vts_attr[i].i_vts_title_spu_nb =
405 ReadByte( p_ifo, p_buf, &p_tmp );
406 //fprintf( stderr, "tt subp nb : %d\n", VTSINF.p_vts_attr[i].i_vts_title_spu_nb );
408 for( j = 0 ; j < 28 /*VTSINF.p_vts_vts_inf[i].i_vtstt_subpic_nb*/ ; j++ )
410 /* FIXME : Fix endianness issue here */
411 ReadBytes( p_ifo, p_buf, &p_tmp, (u8*)(&i_temp), 6 );
420 if( MGINF.i_cell_inf_start_sector )
422 if( ReadCellInf( p_ifo, &p_ifo->vmg.cell_inf, p_ifo->i_start +
423 MGINF.i_cell_inf_start_sector ) < 0 )
430 * global vob unit map.
432 if( MGINF.i_vobu_map_start_sector )
434 if( ReadVobuMap( p_ifo, &p_ifo->vmg.vobu_map, p_ifo->i_start +
435 MGINF.i_vobu_map_start_sector ) < 0 )
442 p_ifo->vts.b_initialized = 0;
444 intf_WarnMsg( 2, "ifo info: vmg initialized" );
449 /*****************************************************************************
450 * IfoTitleSet: Parse vts*.ifo files to fill the Video Title Set structure.
451 *****************************************************************************/
452 int IfoTitleSet( ifo_t * p_ifo )
454 u8 p_buf[DVD_LB_SIZE];
462 if( p_ifo->vts.b_initialized )
464 FreeTitleSet( &p_ifo->vts );
467 i_off = p_ifo->vmg.title_inf.p_attr[p_ifo->i_title-1].i_start_sector
470 //fprintf(stderr, "offset: %d\n" , i_off );
472 p_tmp = FillBuffer( p_ifo, p_buf, i_off );
473 //i_start = p_ifo->i_pos;
474 p_ifo->vts.i_pos = p_ifo->i_pos;
476 #define MGINF p_ifo->vts.manager_inf
479 * read manager information
481 //fprintf( stderr, "VTSI\n" );
483 ReadBytes( p_ifo, p_buf, &p_tmp, MGINF.psz_id , 12 );
484 MGINF.psz_id[12] = '\0';
485 MGINF.i_end_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
486 DumpBytes( p_ifo, p_buf, &p_tmp, 12 );
487 MGINF.i_inf_end_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
488 DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
489 MGINF.i_spec_ver = ReadByte( p_ifo, p_buf, &p_tmp );
490 MGINF.i_cat = ReadDouble( p_ifo, p_buf, &p_tmp );
491 DumpBytes( p_ifo, p_buf, &p_tmp, 90 );
492 MGINF.i_inf_end_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
493 DumpBytes( p_ifo, p_buf, &p_tmp, 60 );
494 MGINF.i_menu_vob_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
495 MGINF.i_title_vob_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
496 MGINF.i_title_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
497 MGINF.i_title_unit_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
498 MGINF.i_menu_unit_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
499 MGINF.i_time_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
500 MGINF.i_menu_cell_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
501 MGINF.i_menu_vobu_map_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
502 MGINF.i_cell_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
503 MGINF.i_vobu_map_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
504 DumpBytes( p_ifo, p_buf, &p_tmp, 24 );
505 DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
506 DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
507 MGINF.i_menu_audio_nb = ReadByte( p_ifo, p_buf, &p_tmp );
509 for( i = 0 ; i < 8 ; i++ )
511 i_temp = ReadQuad( p_ifo, p_buf, &p_tmp );
514 DumpBytes( p_ifo, p_buf, &p_tmp, 17 );
515 MGINF.i_menu_spu_nb = ReadByte( p_ifo, p_buf, &p_tmp );
517 for( i = 0 ; i < 28 ; i++ )
519 /* FIXME : take care of endianness */
520 ReadBytes( p_ifo, p_buf, &p_tmp, (u8*)(&i_temp), 6 );
523 DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
525 i_short = ReadWord( p_ifo, p_buf, &p_tmp );
527 MGINF.video_attr.i_mode = i_short & 0x1;
529 MGINF.video_attr.i_letterboxed = i_short & 0x1;
531 MGINF.video_attr.i_source_res = i_short & 0x3;
533 MGINF.video_attr.i_line21_2 = i_short & 0x1;
535 MGINF.video_attr.i_line21_1 = i_short & 0x1;
537 MGINF.video_attr.i_perm_displ = i_short & 0x3;
539 MGINF.video_attr.i_ratio = i_short & 0x3;
541 MGINF.video_attr.i_system = i_short & 0x3;
543 MGINF.video_attr.i_compression = i_short & 0x3;
545 DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
546 MGINF.i_audio_nb = ReadByte( p_ifo, p_buf, &p_tmp );
547 //fprintf( stderr, "vtsi audio nb : %d\n", MGINF.i_audio_nb );
549 for( i = 0 ; i < 8 ; i++ )
551 i_temp = ReadQuad( p_ifo, p_buf, &p_tmp );
552 //fprintf( stderr, "Audio %d: %llx\n", i, i_temp );
554 MGINF.p_audio_attr[i].i_bar = i_temp & 0xff;
556 MGINF.p_audio_attr[i].i_caption = i_temp & 0xff;
558 MGINF.p_audio_attr[i].i_foo = i_temp & 0xff;
560 MGINF.p_audio_attr[i].i_lang_code = i_temp & 0xffff;
562 MGINF.p_audio_attr[i].i_num_channels = i_temp & 0x7;
564 MGINF.p_audio_attr[i].i_test = i_temp & 0x1;
566 MGINF.p_audio_attr[i].i_sample_freq = i_temp & 0x3;
568 MGINF.p_audio_attr[i].i_quantization = i_temp & 0x3;
570 MGINF.p_audio_attr[i].i_appl_mode = i_temp & 0x3;
572 MGINF.p_audio_attr[i].i_type = i_temp & 0x3;
574 MGINF.p_audio_attr[i].i_multichannel_extension = i_temp & 0x1;
576 MGINF.p_audio_attr[i].i_coding_mode = i_temp & 0x7;
579 DumpBytes( p_ifo, p_buf, &p_tmp, 17 );
580 MGINF.i_spu_nb = ReadByte( p_ifo, p_buf, &p_tmp );
581 //fprintf( stderr, "vtsi subpic nb : %d\n", MGINF.i_spu_nb );
583 for( i=0 ; i<MGINF.i_spu_nb ; i++ )
585 ReadBytes( p_ifo, p_buf, &p_tmp, (u8*)(&i_temp), 6 );
586 i_temp = hton64( i_temp ) >> 16;
587 //fprintf( stderr, "Subpic %d: %llx\n", i, i_temp );
588 MGINF.p_spu_attr[i].i_caption = i_temp & 0xff;
590 MGINF.p_spu_attr[i].i_foo = i_temp & 0xff;
592 MGINF.p_spu_attr[i].i_lang_code = i_temp & 0xffff;
594 MGINF.p_spu_attr[i].i_prefix = i_temp & 0xffff;
598 * read title information: set of pointers to title
600 #define TITINF p_ifo->vts.title_inf
601 if( MGINF.i_title_inf_start_sector )
603 p_tmp = FillBuffer( p_ifo, p_buf, p_ifo->vts.i_pos +
604 MGINF.i_title_inf_start_sector );
606 i_start = p_ifo->i_pos;
608 //fprintf( stderr, "VTS PTR\n" );
610 TITINF.i_title_nb = ReadWord( p_ifo, p_buf, &p_tmp );
611 //fprintf( stderr, "VTS title_inf nb: %d\n", TITINF.i_title_nb );
612 DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
613 TITINF.i_end_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
615 TITINF.pi_start_byte = malloc( TITINF.i_title_nb * sizeof(u32) );
616 if( TITINF.pi_start_byte == NULL )
618 intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" );
622 for( i = 0 ; i < TITINF.i_title_nb ; i++ )
624 TITINF.pi_start_byte[i] = ReadDouble( p_ifo, p_buf, &p_tmp );
628 TITINF.p_title_start = malloc( TITINF.i_title_nb
629 * sizeof(title_start_t) );
630 if( TITINF.p_title_start == NULL )
632 intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" );
636 for( i = 0 ; i < TITINF.i_title_nb ; i++ )
638 p_tmp = FillBuffer( p_ifo, p_buf, i_start +
639 OFF2LB( TITINF.pi_start_byte[i] ) )
640 + (TITINF.pi_start_byte[i] & 0x7ff);
642 TITINF.p_title_start[i].i_title_id =
643 ReadWord( p_ifo, p_buf, &p_tmp );
644 TITINF.p_title_start[i].i_chapter =
645 ReadWord( p_ifo, p_buf, &p_tmp );
651 * menu unit information
653 if( MGINF.i_menu_unit_start_sector )
655 if( ReadTitleUnit( p_ifo, &p_ifo->vts.menu_unit, p_ifo->vts.i_pos +
656 MGINF.i_menu_unit_start_sector ) < 0 )
663 * title unit information
665 if( MGINF.i_title_unit_start_sector )
667 if( ReadUnitInf( p_ifo, &p_ifo->vts.title_unit, p_ifo->vts.i_pos +
668 MGINF.i_title_unit_start_sector, 0 ) < 0 )
675 * time map information
677 #define TIMINF p_ifo->vts.time_inf
678 if( MGINF.i_time_inf_start_sector )
680 u8 p_buf[DVD_LB_SIZE];
682 p_tmp = FillBuffer( p_ifo, p_buf, p_ifo->vts.i_pos +
683 MGINF.i_time_inf_start_sector );
685 //fprintf( stderr, "TMAP\n" );
687 TIMINF.i_nb = ReadWord( p_ifo, p_buf, &p_tmp );;
688 DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
689 TIMINF.i_end_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
691 TIMINF.pi_start_byte = malloc( TIMINF.i_nb * sizeof(u32) );
692 if( TIMINF.pi_start_byte == NULL )
694 intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" );
698 for( i = 0 ; i < TIMINF.i_nb ; i++ )
700 TIMINF.pi_start_byte[i] = ReadDouble( p_ifo, p_buf, &p_tmp );
703 TIMINF.p_time_map = malloc( TIMINF.i_nb * sizeof(time_map_t) );
704 if( TIMINF.p_time_map == NULL )
706 intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" );
710 for( i = 0 ; i < TIMINF.i_nb ; i++ )
712 TIMINF.p_time_map[i].i_time_unit = ReadByte( p_ifo, p_buf, &p_tmp );
713 DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
714 TIMINF.p_time_map[i].i_entry_nb = ReadWord( p_ifo, p_buf, &p_tmp );
716 TIMINF.p_time_map[i].pi_sector =
717 malloc( TIMINF.p_time_map[i].i_entry_nb * sizeof(u32) );
718 if( TIMINF.p_time_map[i].pi_sector == NULL )
720 intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" );
724 for( j = 0 ; j < TIMINF.p_time_map[i].i_entry_nb ; j++ )
726 TIMINF.p_time_map[i].pi_sector[j] =
727 ReadDouble( p_ifo, p_buf, &p_tmp );
733 if( MGINF.i_menu_cell_inf_start_sector
734 && ReadCellInf( p_ifo, &p_ifo->vts.menu_cell_inf, p_ifo->vts.i_pos +
735 MGINF.i_menu_cell_inf_start_sector ) < 0 )
740 if( MGINF.i_menu_vobu_map_start_sector
741 && ReadVobuMap( p_ifo, &p_ifo->vts.menu_vobu_map, p_ifo->vts.i_pos +
742 MGINF.i_menu_vobu_map_start_sector ) < 0 )
747 if( MGINF.i_cell_inf_start_sector
748 && ReadCellInf( p_ifo, &p_ifo->vts.cell_inf, p_ifo->vts.i_pos +
749 MGINF.i_cell_inf_start_sector ) )
754 if( MGINF.i_vobu_map_start_sector
755 && ReadVobuMap( p_ifo, &p_ifo->vts.vobu_map, p_ifo->vts.i_pos +
756 MGINF.i_vobu_map_start_sector ) )
762 intf_WarnMsg( 2, "ifo info: vts %d initialized",
763 p_ifo->vmg.title_inf.p_attr[p_ifo->i_title-1].i_title_set_num );
765 p_ifo->vts.b_initialized = 1;
770 /*****************************************************************************
771 * FreeTitleSet : free all structures allocated by IfoTitleSet
772 *****************************************************************************/
773 static int FreeTitleSet( vts_t * p_vts )
777 if( p_vts->manager_inf.i_vobu_map_start_sector )
779 FreeVobuMap( &p_vts->vobu_map );
782 if( p_vts->manager_inf.i_cell_inf_start_sector )
784 FreeCellInf( &p_vts->cell_inf );
787 if( p_vts->manager_inf.i_menu_vobu_map_start_sector )
789 FreeVobuMap( &p_vts->menu_vobu_map );
792 if( p_vts->manager_inf.i_menu_cell_inf_start_sector )
794 FreeCellInf( &p_vts->menu_cell_inf );
797 if( p_vts->manager_inf.i_time_inf_start_sector )
799 for( i = 0 ; i < p_vts->time_inf.i_nb ; i++ )
801 free( p_vts->time_inf.p_time_map[i].pi_sector );
804 free( p_vts->time_inf.p_time_map );
805 free( p_vts->time_inf.pi_start_byte );
808 if( p_vts->manager_inf.i_title_unit_start_sector )
810 FreeUnitInf( &p_vts->title_unit );
813 if( p_vts->manager_inf.i_menu_unit_start_sector )
815 FreeTitleUnit( &p_vts->menu_unit );
818 if( p_vts->manager_inf.i_title_inf_start_sector )
820 free( p_vts->title_inf.pi_start_byte );
821 free( p_vts->title_inf.p_title_start );
824 p_vts->b_initialized = 0;
829 /*****************************************************************************
830 * IfoDestroy : Frees all the memory allocated to ifo structures
831 *****************************************************************************/
832 void IfoDestroy( ifo_t * p_ifo )
836 FreeTitleSet( &p_ifo->vts );
838 if( p_ifo->vmg.manager_inf.i_vobu_map_start_sector )
840 FreeVobuMap( &p_ifo->vmg.vobu_map );
843 if( p_ifo->vmg.manager_inf.i_cell_inf_start_sector )
845 FreeCellInf( &p_ifo->vmg.cell_inf );
848 if( p_ifo->vmg.manager_inf.i_vts_inf_start_sector )
850 free( p_ifo->vmg.vts_inf.p_vts_attr );
851 free( p_ifo->vmg.vts_inf.pi_vts_attr_start_byte );
854 /* free parental information structures */
855 if( p_ifo->vmg.manager_inf.i_parental_inf_start_sector )
857 for( i = 0 ; i < p_ifo->vmg.parental_inf.i_country_nb ; i++ )
859 for( j = 0 ; j < 8 ; j++ )
861 free( p_ifo->vmg.parental_inf.p_parental_mask[i].ppi_mask[j] );
865 free( p_ifo->vmg.parental_inf.p_parental_mask );
866 free( p_ifo->vmg.parental_inf.p_parental_desc );
869 if( p_ifo->vmg.manager_inf.i_title_unit_start_sector )
871 FreeTitleUnit( &p_ifo->vmg.title_unit );
874 if( p_ifo->vmg.manager_inf.i_title_inf_start_sector )
876 free( p_ifo->vmg.title_inf.p_attr );
879 FreeTitle( &p_ifo->vmg.title );
887 * Function common to Video Manager and Video Title set Processing
890 /*****************************************************************************
891 * ReadTitle : Fills the title structure.
892 *****************************************************************************
893 * Titles are logical stream units that correspond to a whole inside the dvd.
894 * Several title can point to the same part of the physical DVD, and give
895 * map to different anglesfor instance.
896 *****************************************************************************/
897 static int ReadTitle( ifo_t * p_ifo, title_t * p_title, int i_block, int i_bytes )
899 u8 p_buf[DVD_LB_SIZE];
906 p_tmp = FillBuffer( p_ifo, p_buf, i_block ) + i_bytes;
908 i_start = p_ifo->i_pos;
910 //fprintf( stderr, "PGC @ %d + %d\n", p_ifo->i_pos, i_bytes );
912 DumpBytes( p_ifo, p_buf, &p_tmp, 2);
913 p_title->i_chapter_nb = ReadByte( p_ifo, p_buf, &p_tmp );
914 p_title->i_cell_nb = ReadByte( p_ifo, p_buf, &p_tmp );
915 //fprintf( stderr, "title: Prg: %d Cell: %d\n",p_title->i_chapter_nb,p_title->i_cell_nb );
916 p_title->i_play_time = ReadDouble( p_ifo, p_buf, &p_tmp );
917 p_title->i_prohibited_user_op = ReadDouble( p_ifo, p_buf, &p_tmp );
919 for( i = 0 ; i < 8 ; i++ )
921 i_audio = ReadWord( p_ifo, p_buf, &p_tmp );
922 p_title->pi_audio_status[i].i_foo = i_audio & 0xff;
924 p_title->pi_audio_status[i].i_position = i_audio & 0x07;
926 p_title->pi_audio_status[i].i_available = i_audio;
929 for( i = 0 ; i < 32 ; i++ )
931 i_spu = ReadDouble( p_ifo, p_buf, &p_tmp );
932 p_title->pi_spu_status[i].i_position_pan = i_spu & 0x1f;
934 p_title->pi_spu_status[i].i_position_letter = i_spu & 0x1f;
936 p_title->pi_spu_status[i].i_position_wide = i_spu & 0x1f;
938 p_title->pi_spu_status[i].i_position_43 = i_spu & 0x1f;
940 p_title->pi_spu_status[i].i_available = i_spu;
943 p_title->i_next_title_num = ReadWord( p_ifo, p_buf, &p_tmp );
944 p_title->i_prev_title_num = ReadWord( p_ifo, p_buf, &p_tmp );
945 p_title->i_go_up_title_num = ReadWord( p_ifo, p_buf, &p_tmp );
946 p_title->i_still_time = ReadByte( p_ifo, p_buf, &p_tmp );
947 p_title->i_play_mode = ReadByte( p_ifo, p_buf, &p_tmp );
949 for( i = 0 ; i < 16 ; i++ )
951 /* FIXME : We have to erase the extra bit */
952 p_title->pi_yuv_color[i] = ReadDouble( p_ifo, p_buf, &p_tmp );
955 p_title->i_command_start_byte = ReadWord( p_ifo, p_buf, &p_tmp );
956 p_title->i_chapter_map_start_byte = ReadWord( p_ifo, p_buf, &p_tmp );
957 p_title->i_cell_play_start_byte = ReadWord( p_ifo, p_buf, &p_tmp );
958 p_title->i_cell_pos_start_byte = ReadWord( p_ifo, p_buf, &p_tmp );
960 /* parsing of command_t */
961 if( p_title->i_command_start_byte )
963 p_tmp = FillBuffer( p_ifo, p_buf, i_start +
964 OFF2LB( p_title->i_command_start_byte + i_bytes ) )
965 + ( (p_title->i_command_start_byte + i_bytes) & 0x7ff );
968 p_title->command.i_pre_command_nb = ReadWord( p_ifo, p_buf, &p_tmp );
969 p_title->command.i_post_command_nb = ReadWord( p_ifo, p_buf, &p_tmp );
970 p_title->command.i_cell_command_nb = ReadWord( p_ifo, p_buf, &p_tmp );
971 DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
973 /* pre-title commands */
974 if( p_title->command.i_pre_command_nb )
976 p_title->command.p_pre_command =
977 malloc( p_title->command.i_pre_command_nb
978 * sizeof(command_desc_t) );
980 if( p_title->command.p_pre_command == NULL )
982 intf_ErrMsg( "ifo error: out of memory in ReadTitle" );
986 for( i = 0 ; i < p_title->command.i_pre_command_nb ; i++ )
988 p_title->command.p_pre_command[i] =
989 ReadQuad( p_ifo, p_buf, &p_tmp );
994 p_title->command.p_pre_command = NULL;
997 /* post-title commands */
998 if( p_title->command.i_post_command_nb )
1000 p_title->command.p_post_command =
1001 malloc( p_title->command.i_post_command_nb
1002 * sizeof(command_desc_t) );
1004 if( p_title->command.p_post_command == NULL )
1006 intf_ErrMsg( "ifo error: out of memory in ReadTitle" );
1010 for( i = 0 ; i < p_title->command.i_post_command_nb ; i++ )
1012 p_title->command.p_post_command[i] =
1013 ReadQuad( p_ifo, p_buf, &p_tmp );
1018 p_title->command.p_post_command = NULL;
1022 if( p_title->command.i_cell_command_nb )
1024 p_title->command.p_cell_command =
1025 malloc( p_title->command.i_cell_command_nb
1026 * sizeof(command_desc_t) );
1028 if( p_title->command.p_cell_command == NULL )
1030 intf_ErrMsg( "ifo error: out of memory in ReadTitle" );
1034 for( i = 0 ; i < p_title->command.i_cell_command_nb ; i++ )
1036 p_title->command.p_cell_command[i] =
1037 ReadQuad( p_ifo, p_buf, &p_tmp );
1042 p_title->command.p_cell_command = NULL;
1046 /* parsing of chapter_map_t: it gives the entry cell for each chapter */
1047 if( p_title->i_chapter_map_start_byte )
1049 p_ifo->i_pos = dvdcss_seek( p_ifo->dvdhandle,
1050 OFF2LB( i_start + p_title->i_chapter_map_start_byte ),
1053 p_title->chapter_map.pi_start_cell =
1054 malloc( p_title->i_chapter_nb * sizeof(chapter_map_t) );
1056 if( p_title->chapter_map.pi_start_cell == NULL )
1058 intf_ErrMsg( "ifo error: out of memory in Read Title" );
1062 ReadBytes( p_ifo, p_buf, &p_tmp, p_title->chapter_map.pi_start_cell,
1063 p_title->i_chapter_nb );
1067 p_title->chapter_map.pi_start_cell = NULL;
1070 /* parsing of cell_play_t */
1071 if( p_title->i_cell_play_start_byte )
1073 p_tmp = FillBuffer( p_ifo, p_buf, i_start +
1074 OFF2LB( p_title->i_cell_play_start_byte+i_bytes ) )
1075 + ( (p_title->i_cell_play_start_byte+i_bytes) & 0x7ff );
1077 p_title->p_cell_play = malloc( p_title->i_cell_nb
1078 * sizeof(cell_play_t) );
1080 if( p_title->p_cell_play == NULL )
1082 intf_ErrMsg( "ifo error: out of memory in ReadTitle" );
1086 for( i = 0 ; i < p_title->i_cell_nb ; i++ )
1088 #define PLAY p_title->p_cell_play[i]
1089 PLAY.i_category = ReadWord( p_ifo, p_buf, &p_tmp );
1090 PLAY.i_still_time = ReadByte( p_ifo, p_buf, &p_tmp );
1091 PLAY.i_command_nb = ReadByte( p_ifo, p_buf, &p_tmp );
1092 PLAY.i_play_time = ReadDouble( p_ifo, p_buf, &p_tmp );
1093 PLAY.i_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
1094 PLAY.i_first_ilvu_vobu_esector = ReadDouble( p_ifo, p_buf, &p_tmp );
1095 PLAY.i_last_vobu_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
1096 PLAY.i_end_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
1101 /* Parsing of cell_pos_t */
1102 if( p_title->i_cell_pos_start_byte )
1104 p_tmp = FillBuffer( p_ifo, p_buf, i_start +
1105 OFF2LB( p_title->i_cell_pos_start_byte + i_bytes ) )
1106 + ( (p_title->i_cell_pos_start_byte + i_bytes) & 0x7ff );
1108 p_title->p_cell_pos = malloc( p_title->i_cell_nb
1109 * sizeof(cell_pos_t) );
1111 if( p_title->p_cell_pos == NULL )
1113 intf_ErrMsg( "ifo error: out of memory" );
1117 for( i = 0 ; i < p_title->i_cell_nb ; i++ )
1119 p_title->p_cell_pos[i].i_vob_id = ReadWord( p_ifo, p_buf, &p_tmp );
1120 DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
1121 p_title->p_cell_pos[i].i_cell_id = ReadByte( p_ifo, p_buf, &p_tmp );
1128 /*****************************************************************************
1129 * FreeTitle: frees alla structure allocated by a call to ReadTitle
1130 *****************************************************************************/
1131 static int FreeTitle( title_t * p_title )
1133 if( p_title->i_command_start_byte )
1135 if( p_title->command.i_pre_command_nb )
1137 free( p_title->command.p_pre_command );
1140 if( p_title->command.i_post_command_nb )
1142 free( p_title->command.p_post_command );
1145 if( p_title->command.i_cell_command_nb )
1147 free( p_title->command.p_cell_command );
1151 if( p_title->i_chapter_map_start_byte )
1153 free( p_title->chapter_map.pi_start_cell );
1156 if( p_title->i_cell_play_start_byte )
1158 free( p_title->p_cell_play );
1161 if( p_title->i_cell_pos_start_byte )
1163 free( p_title->p_cell_pos );
1169 /*****************************************************************************
1170 * ReadUnitInf : Fills Menu Language Unit Table/ PGC Info Table
1171 *****************************************************************************/
1172 static int ReadUnitInf( ifo_t * p_ifo, unit_inf_t * p_unit_inf,
1173 int i_block, int i_bytes )
1175 u8 p_buf[DVD_LB_SIZE];
1180 p_tmp = FillBuffer( p_ifo, p_buf, i_block ) + i_bytes;
1182 i_start = p_ifo->i_pos;
1183 //fprintf( stderr, "Unit\n" );
1185 p_unit_inf->i_title_nb = ReadWord( p_ifo, p_buf, &p_tmp );
1186 //fprintf( stderr, "Unit nb: %d\n", p_unit_inf->i_title_nb );
1187 DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
1188 p_unit_inf->i_end_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
1190 p_unit_inf->p_title =
1191 malloc( p_unit_inf->i_title_nb * sizeof(unit_title_t) );
1192 if( p_unit_inf->p_title == NULL )
1194 intf_ErrMsg( "ifo error: out of memory in ReadUnit" );
1198 for( i = 0 ; i < p_unit_inf->i_title_nb ; i++ )
1200 #define TITLE p_unit_inf->p_title[i]
1201 TITLE.i_category_mask = ReadByte( p_ifo, p_buf, &p_tmp );
1202 TITLE.i_category = ReadByte( p_ifo, p_buf, &p_tmp );
1203 //fprintf( stderr, "cat mask %d: %x cat %x\n", i, TITLE.i_category_mask, TITLE.i_category );
1204 TITLE.i_parental_mask = ReadWord( p_ifo, p_buf, &p_tmp );
1205 TITLE.i_title_start_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
1209 for( i = 0 ; i < p_unit_inf->i_title_nb ; i++ )
1211 //fprintf( stderr, "Unit: PGC %d @ %d\n", i, p_ifo->i_pos );
1212 ReadTitle( p_ifo, &p_unit_inf->p_title[i].title, i_start +
1213 OFF2LB( p_unit_inf->p_title[i].i_title_start_byte + i_bytes ),
1214 (p_unit_inf->p_title[i].i_title_start_byte+i_bytes) & 0x7ff );
1220 /*****************************************************************************
1221 * FreeUnitInf : frees a structure allocated by ReadUnit
1222 *****************************************************************************/
1223 static int FreeUnitInf( unit_inf_t * p_unit_inf )
1227 if( p_unit_inf->p_title != NULL )
1229 for( i = 0 ; i < p_unit_inf->i_title_nb ; i++ )
1231 FreeTitle( &p_unit_inf->p_title[i].title );
1234 free( p_unit_inf->p_title );
1241 /*****************************************************************************
1242 * ReadTitleUnit: Fills the Title Unit structure.
1243 *****************************************************************************/
1244 static int ReadTitleUnit( ifo_t * p_ifo, title_unit_t * p_title_unit,
1247 u8 p_buf[DVD_LB_SIZE];
1252 p_tmp = FillBuffer( p_ifo, p_buf, i_block );
1253 i_start = p_ifo->i_pos;
1254 //fprintf( stderr, "Unit Table\n" );
1256 p_title_unit->i_unit_nb = ReadWord( p_ifo, p_buf, &p_tmp );
1257 DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
1258 p_title_unit->i_end_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
1260 //fprintf(stderr, "Unit: nb %d end %d\n", p_title_unit->i_unit_nb, p_title_unit->i_end_byte );
1262 p_title_unit->p_unit = malloc( p_title_unit->i_unit_nb * sizeof(unit_t) );
1263 if( p_title_unit->p_unit == NULL )
1265 intf_ErrMsg( "ifo error: out of memory in ReadTitleUnit" );
1269 for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ )
1271 //ReadBytes( p_ifo, p_buf, &p_tmp, p_title_unit->p_unit[i].ps_lang_code, 2 );
1272 p_title_unit->p_unit[i].i_lang_code = ReadWord( p_ifo, p_buf, &p_tmp );
1273 //fprintf( stderr, "lang %d %x\n", i,p_title_unit->p_unit[i].i_lang_code );
1274 DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
1275 p_title_unit->p_unit[i].i_existence_mask =
1276 ReadByte( p_ifo, p_buf, &p_tmp );
1277 p_title_unit->p_unit[i].i_unit_inf_start_byte =
1278 ReadDouble( p_ifo, p_buf, &p_tmp );
1281 p_title_unit->p_unit_inf =
1282 malloc( p_title_unit->i_unit_nb * sizeof(unit_inf_t) );
1283 if( p_title_unit->p_unit_inf == NULL )
1285 intf_ErrMsg( "ifo error: out of memory in ReadTitleUnit" );
1289 for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ )
1291 ReadUnitInf( p_ifo, &p_title_unit->p_unit_inf[i], i_start +
1292 OFF2LB( p_title_unit->p_unit[i].i_unit_inf_start_byte ),
1293 p_title_unit->p_unit[i].i_unit_inf_start_byte & 0x7ff );
1299 /*****************************************************************************
1300 * FreeTitleUnit: frees a structure allocateed by ReadTitleUnit
1301 *****************************************************************************/
1302 static int FreeTitleUnit( title_unit_t * p_title_unit )
1306 if( p_title_unit->p_unit_inf != NULL )
1308 for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ )
1310 FreeUnitInf( &p_title_unit->p_unit_inf[i] );
1313 free( p_title_unit->p_unit_inf );
1319 /*****************************************************************************
1320 * ReadCellInf : Fills the Cell Information structure.
1321 *****************************************************************************/
1322 static int ReadCellInf( ifo_t * p_ifo, cell_inf_t * p_cell_inf, int i_block )
1324 u8 p_buf[DVD_LB_SIZE];
1329 p_tmp = FillBuffer( p_ifo, p_buf, i_block );
1330 i_start = p_ifo->i_pos;
1331 //fprintf( stderr, "CELL ADD\n" );
1333 p_cell_inf->i_vob_nb = ReadWord( p_ifo, p_buf, &p_tmp );
1334 DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
1335 p_cell_inf->i_end_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
1337 p_cell_inf->i_cell_nb = (p_cell_inf->i_end_byte/* - 7*/) / sizeof(cell_map_t);
1339 //fprintf( stderr, "Cell inf: vob %d end %d cell %d\n", p_cell_inf->i_vob_nb, p_cell_inf->i_end_byte, p_cell_inf->i_cell_nb );
1341 p_cell_inf->p_cell_map =
1342 malloc( p_cell_inf->i_cell_nb *sizeof(cell_map_t) );
1343 if( p_cell_inf->p_cell_map == NULL )
1345 intf_ErrMsg( "ifo error: out of memory in ReadCellInf" );
1349 for( i = 0 ; i < p_cell_inf->i_cell_nb ; i++ )
1351 #define MAP p_cell_inf->p_cell_map[i]
1352 MAP.i_vob_id = ReadWord( p_ifo, p_buf, &p_tmp );
1353 MAP.i_cell_id = ReadByte( p_ifo, p_buf, &p_tmp );
1354 DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
1355 MAP.i_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
1356 //fprintf(stderr, "sector[%d] %d (%d)\n", i,ntohl(*(u32*)(p_tmp)), p_ifo->i_pos);
1357 MAP.i_end_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
1364 /*****************************************************************************
1365 * FreeCellInf : frees structures allocated by ReadCellInf
1366 *****************************************************************************/
1367 static int FreeCellInf( cell_inf_t * p_cell_inf )
1369 free( p_cell_inf->p_cell_map );
1374 /*****************************************************************************
1375 * ReadVobuMap : Fills the VOBU Map structure.
1376 *****************************************************************************/
1377 static int ReadVobuMap( ifo_t * p_ifo, vobu_map_t * p_vobu_map, int i_block )
1379 u8 p_buf[DVD_LB_SIZE];
1384 p_tmp = FillBuffer( p_ifo, p_buf, i_block );
1385 i_start = p_ifo->i_pos;
1386 //fprintf( stderr, "VOBU ADMAP\n" );
1388 p_vobu_map->i_end_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
1389 i_max = ( i_start + p_vobu_map->i_end_byte + 1 - p_ifo->i_pos )
1392 p_vobu_map->pi_vobu_start_sector = malloc( i_max * sizeof(u32) );
1393 if( p_vobu_map->pi_vobu_start_sector == NULL )
1395 intf_ErrMsg( "ifo error: out of memory in ReadVobuMap" );
1399 for( i = 0 ; i < i_max ; i++ )
1401 p_vobu_map->pi_vobu_start_sector[i] = ReadDouble( p_ifo, p_buf, &p_tmp );
1407 /*****************************************************************************
1408 * FreeVobuMap: frees structures allocated by ReadVobuMap
1409 *****************************************************************************/
1410 static int FreeVobuMap( vobu_map_t * p_vobu_map )
1412 free( p_vobu_map->pi_vobu_start_sector );
1418 * IFO virtual machine : a set of commands that give the
1419 * interactive behaviour of the dvd
1423 #define OP_VAL_16(i) (ntoh16( com.data.pi_16[i]))
1424 #define OP_VAL_8(i) ((com.data.pi_8[i]))
1426 static char ifo_reg[][80]=
1428 "Menu_Language_Code",
1430 "SubPicture_Stream_#",
1436 "Highlighted_Button_#",
1439 "Karaoke_audio_mixing_mode",
1440 "Parental_mgmt_country_code",
1444 "Audio_language_code_setting",
1445 "Audio_language_extension_code",
1446 "SPU_language_code_setting",
1447 "SPU_language_extension_code",
1448 "?Player_Regional_Code",
1454 static char * IfoMath( char val )
1456 static char math_op[][10] =
1476 return (char *) math_op[val & 0x0f];
1480 char ifo_cmp[][10] =
1492 char ifo_parental[][10] =
1504 char ifo_menu_id[][80] =
1516 char * IfoMenuName( char index )
1518 return ifo_menu_id[index&0x07];
1521 static void IfoRegister( u16 i_data, u8 i_direct)
1525 if( 0/*isalpha( i_data >> 8 & 0xff )*/ )
1527 printf("'%c%c'", i_data>>8&0xff, i_data&0xff);
1531 printf("0x%02x", i_data);
1546 printf("s[%s]", ifo_reg[i_data]);
1559 printf("r[0x%02x]", i_data);
1565 static void IfoAdvanced( u8 *pi_code )
1567 u8 i_cmd = pi_code[0];
1573 printf( " Highlight button %d; ", pi_code[1]>>2 );
1578 printf( " Illegal " );
1583 printf( "ReSuME %d", pi_code[7] );
1585 else if( ( i_cmd & 0x06) == 0x02 )
1587 printf ("Link to %s cell ", ( i_cmd & 0x01 ) ? "prev" : "next");
1591 printf( "advanced (0x%02x) ", i_cmd );
1596 static void IfoJmp( ifo_command_t com )
1601 switch( com.i_sub_cmd )
1607 printf( "VTS 0x%02x", OP_VAL_8(3) );
1610 printf( "This VTS Title 0x%02x", OP_VAL_8(3) );
1613 printf( "This VTS Title 0x%02x Part 0x%04x",
1615 OP_VAL_8(0)<<8|OP_VAL_8(1));
1619 printf ("in SystemSpace ");
1620 switch (OP_VAL_8(3)>>4) {
1622 printf ("to play first PGC");
1625 printf ("to menu \"%s\"", decode_menuname (OP_VAL_8(3)));
1629 printf ("to VTS 0x%02x and TTN 0x%02x", OP_VAL_8(1), OP_VAL_8(2));
1632 printf ("to VMGM PGC number 0x%02x", OP_VAL_8(0)<<8 | OP_VAL_8(1));
1635 printf ("vts 0x%02x lu 0x%02x menu \"%s\"", OP_VAL_8(2), OP_VAL_8(1), decode_menuname (OP_VAL_8(3)));
1638 switch( OP_VAL_8(3)>>6 )
1641 printf( "to play first PGC" );
1644 printf( "to VMG title menu (?)" );
1647 printf( "vts 0x%02x lu 0x%02x menu \"%s\"",
1650 IfoMenuName( OP_VAL_8(3)&0xF ) );
1653 printf( "vmg pgc 0x%04x (?)", ( OP_VAL_8(0)<<8) | OP_VAL_8(1) );
1660 switch(OP_VAL_8(3)>>4) {
1662 printf ("system first pgc");
1665 printf ("system title menu");
1668 printf ("system menu \"%s\"", decode_menuname (OP_VAL_8(3)));
1671 printf ("system vmg pgc %02x ????", OP_VAL_8(0)<<8|OP_VAL_8(1));
1674 printf ("system lu 0x%02x menu \"%s\"", OP_VAL_8(2), decode_menuname (OP_VAL_8(3)));
1677 printf ("system vmg pgc 0x%02x", OP_VAL_8(0)<<8|OP_VAL_8(1));
1681 // OP_VAL_8(2) is number of cell
1682 // it is processed BEFORE switch
1683 // under some conditions, it is ignored
1684 // I don't understand exactly what it means
1685 printf( " ( spec cell 0x%02X ) ", OP_VAL_8(2) );
1687 switch( OP_VAL_8(3)>>6 )
1690 printf( "to FP PGC" );
1693 printf( "to VMG root menu (?)" );
1696 printf( "to VTS menu \"%s\" (?)",
1697 IfoMenuName(OP_VAL_8(3)&0xF) );
1700 printf( "vmg pgc 0x%02x (?)", (OP_VAL_8(0)<<8)|OP_VAL_8(1) );
1708 static void IfoLnk( ifo_command_t com )
1710 u16 i_button=OP_VAL_8(4)>>2;
1714 switch( com.i_sub_cmd )
1717 IfoAdvanced( &OP_VAL_8(4) );
1721 printf( "PGC 0x%02x", OP_VAL_16(2) );
1725 printf( "PTT 0x%02x", OP_VAL_16(2) );
1729 printf( "Program 0x%02x this PGC", OP_VAL_8(5) );
1733 printf( "Cell 0x%02x this PGC", OP_VAL_8(5) );
1741 printf( ", Highlight 0x%02x", OP_VAL_8(4)>>2 );
1746 void IfoSetSystem( ifo_command_t com )
1753 for( i=1; i<=3; i++ )
1755 if( OP_VAL_8(i)&0x80 )
1759 printf ("s[%s] = 0x%02x;", ifo_reg[i], OP_VAL_8(i)&0xf);
1763 printf ("s[%s] = r[0x%02x];", ifo_reg[i], OP_VAL_8(i)&0xf);
1769 if(OP_VAL_8(1]&0x80)
1770 printf ("s[%s] = 0x%02x;", reg_name[1], OP_VAL_8(1]&0xf);
1771 if(OP_VAL_8(2)&0x80)
1772 //DENT: lwhat about 0x7f here ???
1773 printf ("s[%s] = 0x%02x;", reg_name[2], OP_VAL_8(2)&0x7f);
1774 if(OP_VAL_8(3)&0x80)
1775 printf ("s[%s] = 0x%02x;", reg_name[3], OP_VAL_8(3)&0xf);
1777 if(OP_VAL_8(1)&0x80)
1778 printf ("s[%s] = r[0x%02x];", reg_name[1], OP_VAL_8(1)&0xf);
1779 if(OP_VAL_8(2)&0x80)
1780 printf ("s[%s] = r[0x%02x];", reg_name[2], OP_VAL_8(2)&0xf);
1781 if(OP_VAL_8(3)&0x80)
1782 printf ("s[%s] = r[0x%02x];", reg_name[3], OP_VAL_8(3)&0xf);
1790 printf( "s[%s] = 0x%02x", ifo_reg[9], OP_VAL_16(0) );
1794 printf( "s[%s] = r[0x%02x]", ifo_reg[9], OP_VAL_8(1)&0x0f );
1797 printf( "s[%s] = (s[%s]&0x7FFF)|0x%02x",
1798 ifo_reg[10], ifo_reg[10], OP_VAL_16(1)&0x8000);
1803 printf( "r[0x%02x] = 0x%02x", OP_VAL_8(3)&0x0f, OP_VAL_16(0) );
1807 printf ("r[r[0x%02x]] = r[0x%02x]",
1808 OP_VAL_8(3)&0x0f, OP_VAL_8(1)&0x0f);
1812 //actually only bits 00011100 00011100 are set
1815 printf ("s[%s] = 0x%02x", ifo_reg[11], OP_VAL_16(1));
1819 printf ("s[%s] = r[0x%02x]", ifo_reg[11], OP_VAL_8(3)&0x0f );
1824 //s[%s]=(r[%s]&0x3FF) | (0x%02x << 0xA);
1825 //but it is way too ugly
1828 printf( "s[%s] = 0x%02x", ifo_reg[8], OP_VAL_8(2)>>2 );
1832 printf( "s[%s] = r[0x%02x]", ifo_reg[8], OP_VAL_8(3)&0x0f );
1840 static void IfoSet( ifo_command_t com )
1842 IfoRegister( OP_VAL_16(0), 0 );
1843 printf( " %s ", IfoMath( com.i_cmd ) );
1844 IfoRegister( OP_VAL_16(1), com.i_direct );
1847 /*****************************************************************************
1848 * CommandRead : translates the command strings in ifo into command
1850 *****************************************************************************/
1851 void CommandRead( ifo_command_t com )
1853 u8* pi_code = (u8*)(&com);
1855 switch( com.i_type )
1868 printf ("if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
1869 ifo_cmp[com.i_cmp]);
1870 IfoRegister (OP_VAL_16(1), com.i_dir_cmp);
1875 switch( com.i_sub_cmd )
1878 printf( "goto Line 0x%02x", OP_VAL_16(2) );
1882 printf( "stop VM" );
1886 printf( "Set Parental Level To %s and goto Line 0x%02x",
1887 ifo_parental[OP_VAL_8(4)&0x7],
1892 printf( "Illegal" );
1911 printf( "if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f,
1912 ifo_cmp[com.i_cmp] );
1913 IfoRegister( OP_VAL_8(5), 0 );
1924 printf( "if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
1925 ifo_cmp[com.i_cmp] );
1926 IfoRegister( OP_VAL_16(1), com.i_dir_cmp );
1940 IfoSetSystem( com );
1942 else if( com.i_cmp && !com.i_sub_cmd )
1944 printf ("if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f, ifo_cmp[com.i_cmp]);
1945 IfoRegister( OP_VAL_8(5), 0 );
1947 IfoSetSystem( com );
1949 else if( !com.i_cmp && com.i_sub_cmd )
1952 IfoSetSystem( com );
1968 else if( com.i_cmp && !com.i_sub_cmd )
1970 printf ("if (r[0x%02x] %s ", OP_VAL_8(0)&0x0f, ifo_cmp[com.i_cmp]);
1971 IfoRegister( OP_VAL_16(2), com.i_dir_cmp );
1975 else if( !com.i_cmp && com.i_sub_cmd )
1989 * math command on r[opcode[1]] and
1990 * direct?be2me_16(OP_VAL_8(0)):reg[OP_VAL_8(1)] is executed
1991 * ( unless command is swap; then r[opcode[1]] and r[OP_VAL_8(1)]
1993 * boolean operation cmp on r[opcode[1]] and
1994 * dir_cmp?be2me_16(OP_VAL_8(1)[1]):reg[OP_VAL_8(3)] is executed
1995 * on true result, buttons(c[6], c[7]) is called
1996 * problem is 'what is buttons()'
1999 printf( "r[0x%X] ", pi_code[1] );
2000 printf( " %s ", IfoMath( com.i_cmd ) );
2001 if( com.i_cmd == 2 )
2003 printf( "r[0x%X] ", OP_VAL_8(1) );
2007 IfoRegister( OP_VAL_16(0), com.i_direct );
2011 printf( "if ( r[%d] %s ", pi_code[1], ifo_cmp[com.i_cmp] );
2012 IfoRegister( OP_VAL_8(1), com.i_dir_cmp );
2013 printf( " ) then {" );
2014 IfoAdvanced( &OP_VAL_8(4) );
2019 * opposite to case 4: boolean, math and buttons.
2025 if( !com.i_direct && com.i_dir_cmp )
2027 printf( "0x%X", OP_VAL_16(1) );
2031 IfoRegister( OP_VAL_8(3), 0 );
2032 if( OP_VAL_8(3)&0x80 )
2034 printf( "s[%s]", ifo_reg[OP_VAL_8(3)&0x1F] );
2038 printf( "r[0x%X]", OP_VAL_8(3)&0x1F);
2039 // 0x1F is either not a mistake,
2040 // or Microsoft programmer's mistake!!!
2044 printf( " %s r[0x%X] ", ifo_cmp[com.i_cmp],
2045 com.i_direct ? OP_VAL_8(2) : OP_VAL_8(1) );
2046 printf( " ) then {" );
2047 printf( "r[0x%X] ", pi_code[1] & 0xF );
2048 printf( " %s ", IfoMath( com.i_cmd ) );
2050 if( com.i_cmd == 0x02 ) // swap
2052 printf("r[0x%X] ", OP_VAL_8(0)&0x1F);
2058 printf( "0x%X", OP_VAL_16(0) );
2062 if( OP_VAL_8(0) & 0x80 )
2064 printf("s[%s]", ifo_reg[OP_VAL_8(0) & 0x1F] );
2068 printf("r[0x%X]", OP_VAL_8(0) & 0x1F );
2074 IfoAdvanced( &OP_VAL_8(4) );
2080 printf( "Unknown Command\n" );
2087 /*****************************************************************************
2088 * CommandPrint : print in clear text (I hope so !) what a command does
2089 *****************************************************************************/
2090 void CommandPrint( ifo_t ifo )
2097 /*****************************************************************************
2099 *****************************************************************************/
2100 static u8* FillBuffer( ifo_t* p_ifo, u8* p_buf, int i_pos )
2102 p_ifo->i_pos = dvdcss_seek( p_ifo->dvdhandle, i_pos, DVDCSS_NOFLAGS );
2103 dvdcss_read( p_ifo->dvdhandle, p_buf, 1, DVDCSS_NOFLAGS );
2108 static void ReadBytes( ifo_t* p_ifo, u8* p_buf, u8** pp_tmp,
2109 u8* pi_dest, int i_nb )
2111 if( i_nb > DVD_LB_SIZE )
2113 intf_ErrMsg( "ifo error: excessive ReadBytes call (%i)", i_nb );
2116 if( *pp_tmp + i_nb >= p_buf + DVD_LB_SIZE )
2118 int i_spare = (int)( (p_buf + DVD_LB_SIZE) - *pp_tmp );
2120 /* Copy the bytes remaining in the current buffer */
2121 memcpy( pi_dest, *pp_tmp, i_spare );
2125 /* Load the next buffer */
2126 *pp_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_pos + 1 );
2129 memcpy( pi_dest, *pp_tmp, i_nb );
2135 static void DumpBytes( ifo_t* p_ifo, u8* p_buf, u8** pp_tmp, int i_nb )
2137 if( i_nb > DVD_LB_SIZE )
2139 intf_ErrMsg( "ifo error: excessive DumpBytes call (%i)", i_nb );
2144 if( *pp_tmp >= p_buf + DVD_LB_SIZE )
2146 /* If we went too far, load the next buffer */
2147 *pp_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_pos + 1 )
2148 + (int)( (*pp_tmp) - (p_buf + DVD_LB_SIZE) );
2155 if( *pp_tmp >= p_buf + DVD_LB_SIZE ) \
2157 *pp_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_pos + 1 ); \
2159 i_ret <<= 8; i_ret |= **pp_tmp; (*pp_tmp)++;
2161 static u8 ReadByte( ifo_t * p_ifo, u8* p_buf, u8** pp_tmp )
2168 static u16 ReadWord( ifo_t * p_ifo, u8* p_buf, u8** pp_tmp )
2175 static u32 ReadDouble( ifo_t * p_ifo, u8* p_buf, u8** pp_tmp )
2178 ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE;
2182 static u64 ReadQuad( ifo_t * p_ifo, u8* p_buf, u8** pp_tmp )
2185 ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE;