1 /*****************************************************************************
2 * ifo.c: Functions for ifo parsing
3 *****************************************************************************
4 * Copyright (C) 1999-2001 VideoLAN
5 * $Id: ifo.c,v 1.5 2003/03/03 14:21:08 gbazin 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 *****************************************************************************/
48 # include <dvdcss/dvdcss.h>
55 /*****************************************************************************
57 *****************************************************************************/
58 void CommandRead ( command_desc_t );
59 static int ReadTitle ( ifo_t * , title_t *, int, int );
60 static int FreeTitle ( title_t * );
61 static int ReadUnitInf ( ifo_t * , unit_inf_t *, int, int );
62 static int FreeUnitInf ( unit_inf_t * );
63 static int ReadTitleUnit ( ifo_t * , title_unit_t *, int );
64 static int FreeTitleUnit ( title_unit_t * );
65 static int ReadVobuMap ( ifo_t * , vobu_map_t *, int );
66 static int FreeVobuMap ( vobu_map_t * );
67 static int ReadCellInf ( ifo_t * , cell_inf_t *, int );
68 static int FreeCellInf ( cell_inf_t * );
69 static int FreeTitleSet ( vts_t * );
71 static u8* FillBuffer ( ifo_t *, u8 *, int );
72 static u8 ReadByte ( ifo_t *, u8 *, u8 ** );
73 static void ReadBytes ( ifo_t *, u8 *, u8 **, u8 *, int );
74 static void DumpBytes ( ifo_t *, u8 *, u8 **, int );
75 static u16 ReadWord ( ifo_t *, u8 *, u8 ** );
76 static u32 ReadDouble ( ifo_t *, u8 *, u8 ** );
77 static u64 ReadQuad ( ifo_t *, u8 *, u8 ** );
83 /*****************************************************************************
84 * IfoCreate : Creates an ifo structure and prepares for parsing directly
86 *****************************************************************************/
87 int IfoCreate( thread_dvd_data_t * p_dvd )
89 p_dvd->p_ifo = malloc( sizeof(ifo_t) );
90 if( p_dvd->p_ifo == NULL )
94 /* memset to 0 to avoid crashing on deallocation later */
95 memset( p_dvd->p_ifo, 0, sizeof(ifo_t) );
97 /* if we are here the dvd device has already been opened */
98 p_dvd->p_ifo->dvdhandle = p_dvd->dvdhandle;
103 /*****************************************************************************
104 * IfoInit : Reads information from the management table.
105 *****************************************************************************/
106 int IfoInit( ifo_t * p_ifo )
108 u8 p_buf[DVD_LB_SIZE];
114 /* find the start sector of video information on the dvd */
115 p_ifo->i_start = DVDUDFFindFile( p_ifo->dvdhandle, "/VIDEO_TS/VIDEO_TS.IFO" );
116 if( !p_ifo->i_start ) return -1;
118 p_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_start );
119 /*i_start = p_ifo->i_pos; */
122 * read the video manager information table
124 #define MGINF p_ifo->vmg.manager_inf
125 /*fprintf( stderr, "VMGI\n" ); */
127 ReadBytes( p_ifo, p_buf, &p_tmp, MGINF.psz_id, 12 );
128 MGINF.psz_id[12] = '\0';
129 MGINF.i_vmg_end_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
130 DumpBytes( p_ifo, p_buf, &p_tmp, 12 );
131 MGINF.i_vmg_inf_end_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
132 DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
133 MGINF.i_spec_ver = ReadByte( p_ifo, p_buf, &p_tmp );
134 MGINF.i_cat = ReadDouble( p_ifo, p_buf, &p_tmp );
135 MGINF.i_volume_nb = ReadWord( p_ifo, p_buf, &p_tmp );
136 MGINF.i_volume = ReadWord( p_ifo, p_buf, &p_tmp );
137 MGINF.i_disc_side = ReadByte( p_ifo, p_buf, &p_tmp );
138 DumpBytes( p_ifo, p_buf, &p_tmp, 19 );
139 MGINF.i_title_set_nb = ReadWord( p_ifo, p_buf, &p_tmp );
140 ReadBytes( p_ifo, p_buf, &p_tmp, MGINF.ps_provider_id, 32 );
141 MGINF.i_pos_code = ReadQuad( p_ifo, p_buf, &p_tmp );
142 DumpBytes( p_ifo, p_buf, &p_tmp, 24 );
143 MGINF.i_vmg_inf_end_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
144 MGINF.i_first_play_title_start_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
145 DumpBytes( p_ifo, p_buf, &p_tmp, 56 );
146 MGINF.i_vob_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
147 MGINF.i_title_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
148 MGINF.i_title_unit_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
149 MGINF.i_parental_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
150 MGINF.i_vts_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
151 MGINF.i_text_data_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
152 MGINF.i_cell_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
153 MGINF.i_vobu_map_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
154 DumpBytes( p_ifo, p_buf, &p_tmp, 32 );
155 DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
156 DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
157 MGINF.i_audio_nb = ReadByte( p_ifo, p_buf, &p_tmp );
158 /*fprintf( stderr, "vmgi audio nb : %d\n", MGINF.i_audio_nb ); */
160 for( i = 0 ; i < 8 ; i++ )
162 i_temp = ReadQuad( p_ifo, p_buf, &p_tmp );
165 DumpBytes( p_ifo, p_buf, &p_tmp, 17 );
166 MGINF.i_spu_nb = ReadByte( p_ifo, p_buf, &p_tmp );
167 /*fprintf( stderr, "vmgi subpic nb : %d\n", MGINF.i_spu_nb ); */
169 for( i = 0 ; i < MGINF.i_spu_nb ; i++ )
171 ReadBytes( p_ifo, p_buf, &p_tmp, (u8*)(&i_temp), 6 );
172 /* FIXME : take care of endianness */
176 * read first play title.
178 /*fprintf(stderr,"readtitle %i\n", MGINF.i_first_play_title_start_byte & 0x7ff ); */
179 if( ReadTitle( p_ifo, &p_ifo->vmg.title, p_ifo->i_start
180 + OFF2LB( MGINF.i_first_play_title_start_byte ),
181 MGINF.i_first_play_title_start_byte & 0x7ff ) < 0 )
187 * fills the title information structure.
189 #define TITINF p_ifo->vmg.title_inf
190 if( MGINF.i_title_inf_start_sector )
192 p_tmp = FillBuffer( p_ifo, p_buf,
193 p_ifo->i_start + MGINF.i_title_inf_start_sector );
194 /*fprintf( stderr, "title inf %d\n", p_ifo->i_pos ); */
196 TITINF.i_title_nb = ReadWord( p_ifo, p_buf, &p_tmp );
197 /*fprintf( stderr, "title_inf: TTU nb %d\n", TITINF.i_title_nb ); */
198 DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
199 TITINF.i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
201 /* parsing of title attributes */
202 TITINF.p_attr = malloc( TITINF.i_title_nb *sizeof(title_attr_t) );
203 if( TITINF.p_attr == NULL )
208 for( i = 0 ; i < TITINF.i_title_nb ; i++ )
210 TITINF.p_attr[i].i_play_type = ReadByte( p_ifo, p_buf, &p_tmp );
211 TITINF.p_attr[i].i_angle_nb = ReadByte( p_ifo, p_buf, &p_tmp );
212 TITINF.p_attr[i].i_chapter_nb = ReadWord( p_ifo, p_buf, &p_tmp );
213 TITINF.p_attr[i].i_parental_id = ReadWord( p_ifo, p_buf, &p_tmp );
214 TITINF.p_attr[i].i_title_set_num = ReadByte( p_ifo, p_buf, &p_tmp );
215 TITINF.p_attr[i].i_title_num = ReadByte( p_ifo, p_buf, &p_tmp );
216 TITINF.p_attr[i].i_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
217 /*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 ); */
222 TITINF.p_attr = NULL;
227 * fills the title unit structure.
229 if( MGINF.i_title_unit_start_sector )
231 if( ReadTitleUnit( p_ifo, &p_ifo->vmg.title_unit, p_ifo->i_start
232 + MGINF.i_title_unit_start_sector ) < 0 )
239 * fills the structure about parental information.
241 #define PARINF p_ifo->vmg.parental_inf
242 if( MGINF.i_parental_inf_start_sector )
244 p_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_start +
245 MGINF.i_parental_inf_start_sector );
246 i_start = p_ifo->i_pos;
248 /*fprintf( stderr, "PTL\n" ); */
250 PARINF.i_country_nb = ReadWord( p_ifo, p_buf, &p_tmp );
251 PARINF.i_vts_nb = ReadWord( p_ifo, p_buf, &p_tmp );
252 PARINF.i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
254 PARINF.p_parental_desc = malloc( PARINF.i_country_nb
255 * sizeof(parental_desc_t) );
256 if( PARINF.p_parental_desc == NULL )
261 for( i = 0 ; i < PARINF.i_country_nb ; i++ )
263 ReadBytes( p_ifo, p_buf, &p_tmp,
264 PARINF.p_parental_desc[i].ps_country_code, 2 );
265 DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
266 PARINF.p_parental_desc[i].i_parental_mask_start_byte =
267 ReadWord( p_ifo, p_buf, &p_tmp );
268 DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
271 PARINF.p_parental_mask = malloc( PARINF.i_country_nb
272 * sizeof(parental_mask_t) );
273 if( PARINF.p_parental_mask == NULL )
278 for( i = 0 ; i < PARINF.i_country_nb ; i++ )
280 p_tmp = FillBuffer( p_ifo, p_buf, i_start + OFF2LB(
281 PARINF.p_parental_desc[i].i_parental_mask_start_byte ) )
282 + (PARINF.p_parental_desc[i].i_parental_mask_start_byte & 0x7ff);
284 for( j = 0 ; j < 8 ; j++ )
286 PARINF.p_parental_mask[i].ppi_mask[j] =
287 malloc( ( PARINF.i_vts_nb + 1 ) * sizeof(u16) );
289 if( PARINF.p_parental_mask[i].ppi_mask[j] == NULL )
294 for( k = 0 ; k < PARINF.i_vts_nb + 1 ; k++ )
296 PARINF.p_parental_mask[i].ppi_mask[j][k] =
297 ReadWord( p_ifo, p_buf, &p_tmp );
305 * information and attributes about for each vts.
307 #define VTSINF p_ifo->vmg.vts_inf
308 if( MGINF.i_vts_inf_start_sector )
312 p_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_start +
313 MGINF.i_vts_inf_start_sector );
314 i_start = p_ifo->i_pos;
316 /*fprintf( stderr, "VTS ATTR\n" ); */
318 VTSINF.i_vts_nb = ReadWord( p_ifo, p_buf, &p_tmp );;
319 /*fprintf( stderr, "VTS ATTR Nb: %d\n", VTSINF.i_vts_nb ); */
320 DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
321 VTSINF.i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
322 VTSINF.pi_vts_attr_start_byte =
323 malloc( VTSINF.i_vts_nb * sizeof(u32) );
324 if( VTSINF.pi_vts_attr_start_byte == NULL )
329 for( i = 0 ; i < VTSINF.i_vts_nb ; i++ )
331 VTSINF.pi_vts_attr_start_byte[i] =
332 ReadDouble( p_ifo, p_buf, &p_tmp );
335 VTSINF.p_vts_attr = malloc( VTSINF.i_vts_nb * sizeof(vts_attr_t) );
336 if( VTSINF.p_vts_attr == NULL )
341 for( i = 0 ; i < VTSINF.i_vts_nb ; i++ )
343 p_tmp = FillBuffer( p_ifo, p_buf, i_start +
344 OFF2LB( VTSINF.pi_vts_attr_start_byte[i] ) )
345 + ( VTSINF.pi_vts_attr_start_byte[i] & 0x7ff );
347 VTSINF.p_vts_attr[i].i_last_byte =
348 ReadDouble( p_ifo, p_buf, &p_tmp );
349 VTSINF.p_vts_attr[i].i_cat_app_type =
350 ReadDouble( p_ifo, p_buf, &p_tmp );
351 DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
352 DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
353 VTSINF.p_vts_attr[i].i_vts_menu_audio_nb =
354 ReadByte( p_ifo, p_buf, &p_tmp );
355 /*fprintf( stderr, "m audio nb : %d\n", VTSINF.p_vts_attr[i].i_vts_menu_audio_nb ); */
357 for( j = 0 ; j < 8 ; j++ )
359 i_temp = ReadQuad( p_ifo, p_buf, &p_tmp );
362 DumpBytes( p_ifo, p_buf, &p_tmp, 17 );
363 VTSINF.p_vts_attr[i].i_vts_menu_spu_nb =
364 ReadByte( p_ifo, p_buf, &p_tmp );
365 /*fprintf( stderr, "m subp nb : %d\n", VTSINF.p_vts_attr[i].i_vts_menu_spu_nb ); */
367 for( j = 0 ; j < 28 ; j++ )
369 /* FIXME : Fix endianness issue here */
370 ReadBytes( p_ifo, p_buf, &p_tmp, (u8*)(&i_temp), 6 );
373 DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
374 DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
375 DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
376 VTSINF.p_vts_attr[i].i_vts_title_audio_nb =
377 ReadDouble( p_ifo, p_buf, &p_tmp );
378 /*fprintf( stderr, "tt audio nb : %d\n", VTSINF.p_vts_attr[i].i_vts_title_audio_nb ); */
380 for( j = 0 ; j < 8 ; j++ )
382 i_temp = ReadQuad( p_ifo, p_buf, &p_tmp );;
385 DumpBytes( p_ifo, p_buf, &p_tmp, 17 );
386 VTSINF.p_vts_attr[i].i_vts_title_spu_nb =
387 ReadByte( p_ifo, p_buf, &p_tmp );
388 /*fprintf( stderr, "tt subp nb : %d\n", VTSINF.p_vts_attr[i].i_vts_title_spu_nb ); */
390 for( j = 0 ; j < 28 /*VTSINF.p_vts_vts_inf[i].i_vtstt_subpic_nb*/ ; j++ )
392 /* FIXME : Fix endianness issue here */
393 ReadBytes( p_ifo, p_buf, &p_tmp, (u8*)(&i_temp), 6 );
402 if( MGINF.i_cell_inf_start_sector )
404 if( ReadCellInf( p_ifo, &p_ifo->vmg.cell_inf, p_ifo->i_start +
405 MGINF.i_cell_inf_start_sector ) < 0 )
412 * global vob unit map.
414 if( MGINF.i_vobu_map_start_sector )
416 if( ReadVobuMap( p_ifo, &p_ifo->vmg.vobu_map, p_ifo->i_start +
417 MGINF.i_vobu_map_start_sector ) < 0 )
424 p_ifo->vts.b_initialized = 0;
429 /*****************************************************************************
430 * IfoTitleSet: Parse vts*.ifo files to fill the Video Title Set structure.
431 *****************************************************************************/
432 int IfoTitleSet( ifo_t * p_ifo, int i_title )
434 u8 p_buf[DVD_LB_SIZE];
442 if( p_ifo->vts.b_initialized )
444 FreeTitleSet( &p_ifo->vts );
447 i_off = p_ifo->vmg.title_inf.p_attr[i_title-1].i_start_sector
450 /*fprintf(stderr, "offset: %d\n" , i_off ); */
452 p_tmp = FillBuffer( p_ifo, p_buf, i_off );
453 /*i_start = p_ifo->i_pos; */
454 p_ifo->vts.i_pos = p_ifo->i_pos;
456 #define MGINF p_ifo->vts.manager_inf
459 * read manager information
461 /*fprintf( stderr, "VTSI\n" ); */
463 ReadBytes( p_ifo, p_buf, &p_tmp, MGINF.psz_id , 12 );
464 MGINF.psz_id[12] = '\0';
465 MGINF.i_last_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
466 DumpBytes( p_ifo, p_buf, &p_tmp, 12 );
467 MGINF.i_inf_last_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
468 DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
469 MGINF.i_spec_ver = ReadByte( p_ifo, p_buf, &p_tmp );
470 MGINF.i_cat = ReadDouble( p_ifo, p_buf, &p_tmp );
471 DumpBytes( p_ifo, p_buf, &p_tmp, 90 );
472 MGINF.i_inf_end_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
473 DumpBytes( p_ifo, p_buf, &p_tmp, 60 );
474 MGINF.i_menu_vob_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
475 MGINF.i_title_vob_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
476 MGINF.i_title_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
477 MGINF.i_title_unit_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
478 MGINF.i_menu_unit_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
479 MGINF.i_time_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
480 MGINF.i_menu_cell_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
481 MGINF.i_menu_vobu_map_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
482 MGINF.i_cell_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
483 MGINF.i_vobu_map_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
484 DumpBytes( p_ifo, p_buf, &p_tmp, 24 );
485 DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
486 DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
487 MGINF.i_menu_audio_nb = ReadByte( p_ifo, p_buf, &p_tmp );
489 for( i = 0 ; i < 8 ; i++ )
491 i_temp = ReadQuad( p_ifo, p_buf, &p_tmp );
494 DumpBytes( p_ifo, p_buf, &p_tmp, 17 );
495 MGINF.i_menu_spu_nb = ReadByte( p_ifo, p_buf, &p_tmp );
497 for( i = 0 ; i < 28 ; i++ )
499 /* FIXME : take care of endianness */
500 ReadBytes( p_ifo, p_buf, &p_tmp, (u8*)(&i_temp), 6 );
503 DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
505 i_short = ReadWord( p_ifo, p_buf, &p_tmp );
507 MGINF.video_attr.i_mode = i_short & 0x1;
509 MGINF.video_attr.i_letterboxed = i_short & 0x1;
511 MGINF.video_attr.i_source_res = i_short & 0x3;
513 MGINF.video_attr.i_line21_2 = i_short & 0x1;
515 MGINF.video_attr.i_line21_1 = i_short & 0x1;
517 MGINF.video_attr.i_perm_displ = i_short & 0x3;
519 MGINF.video_attr.i_ratio = i_short & 0x3;
521 MGINF.video_attr.i_system = i_short & 0x3;
523 MGINF.video_attr.i_compression = i_short & 0x3;
525 DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
526 MGINF.i_audio_nb = ReadByte( p_ifo, p_buf, &p_tmp );
527 /*fprintf( stderr, "vtsi audio nb : %d\n", MGINF.i_audio_nb ); */
529 for( i = 0 ; i < 8 ; i++ )
531 i_temp = ReadQuad( p_ifo, p_buf, &p_tmp );
532 /*fprintf( stderr, "Audio %d: "I64Fx"\n", i, i_temp ); */
534 MGINF.p_audio_attr[i].i_bar = i_temp & 0xff;
536 MGINF.p_audio_attr[i].i_caption = i_temp & 0xff;
538 MGINF.p_audio_attr[i].i_foo = i_temp & 0xff;
540 MGINF.p_audio_attr[i].i_lang_code = i_temp & 0xffff;
542 MGINF.p_audio_attr[i].i_num_channels = i_temp & 0x7;
544 MGINF.p_audio_attr[i].i_test = i_temp & 0x1;
546 MGINF.p_audio_attr[i].i_sample_freq = i_temp & 0x3;
548 MGINF.p_audio_attr[i].i_quantization = i_temp & 0x3;
550 MGINF.p_audio_attr[i].i_appl_mode = i_temp & 0x3;
552 MGINF.p_audio_attr[i].i_type = i_temp & 0x3;
554 MGINF.p_audio_attr[i].i_multichannel_extension = i_temp & 0x1;
556 MGINF.p_audio_attr[i].i_coding_mode = i_temp & 0x7;
559 DumpBytes( p_ifo, p_buf, &p_tmp, 17 );
560 MGINF.i_spu_nb = ReadByte( p_ifo, p_buf, &p_tmp );
561 /*fprintf( stderr, "vtsi subpic nb : %d\n", MGINF.i_spu_nb ); */
563 for( i=0 ; i<MGINF.i_spu_nb ; i++ )
565 ReadBytes( p_ifo, p_buf, &p_tmp, (u8*)(&i_temp), 6 );
566 i_temp = hton64( i_temp ) >> 16;
567 /*fprintf( stderr, "Subpic %d: "I64Fx"\n", i, i_temp ); */
568 MGINF.p_spu_attr[i].i_caption = i_temp & 0xff;
570 MGINF.p_spu_attr[i].i_foo = i_temp & 0xff;
572 MGINF.p_spu_attr[i].i_lang_code = i_temp & 0xffff;
574 MGINF.p_spu_attr[i].i_prefix = i_temp & 0xffff;
578 * read title information: set of pointers to title
580 #define TITINF p_ifo->vts.title_inf
581 if( MGINF.i_title_inf_start_sector )
583 p_tmp = FillBuffer( p_ifo, p_buf, p_ifo->vts.i_pos +
584 MGINF.i_title_inf_start_sector );
586 i_start = p_ifo->i_pos;
588 /*fprintf( stderr, "VTS PTR\n" ); */
590 TITINF.i_title_nb = ReadWord( p_ifo, p_buf, &p_tmp );
591 /*fprintf( stderr, "VTS title_inf nb: %d\n", TITINF.i_title_nb ); */
592 DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
593 TITINF.i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
595 TITINF.pi_start_byte = malloc( TITINF.i_title_nb * sizeof(u32) );
596 if( TITINF.pi_start_byte == NULL )
601 for( i = 0 ; i < TITINF.i_title_nb ; i++ )
603 TITINF.pi_start_byte[i] = ReadDouble( p_ifo, p_buf, &p_tmp );
607 TITINF.p_title_start = malloc( TITINF.i_title_nb
608 * sizeof(title_start_t) );
609 if( TITINF.p_title_start == NULL )
614 for( i = 0 ; i < TITINF.i_title_nb ; i++ )
616 p_tmp = FillBuffer( p_ifo, p_buf, i_start +
617 OFF2LB( TITINF.pi_start_byte[i] ) )
618 + (TITINF.pi_start_byte[i] & 0x7ff);
620 TITINF.p_title_start[i].i_title_id =
621 ReadWord( p_ifo, p_buf, &p_tmp );
622 TITINF.p_title_start[i].i_chapter =
623 ReadWord( p_ifo, p_buf, &p_tmp );
629 * menu unit information
631 if( MGINF.i_menu_unit_start_sector )
633 if( ReadTitleUnit( p_ifo, &p_ifo->vts.menu_unit, p_ifo->vts.i_pos +
634 MGINF.i_menu_unit_start_sector ) < 0 )
641 * title unit information
643 if( MGINF.i_title_unit_start_sector )
645 if( ReadUnitInf( p_ifo, &p_ifo->vts.title_unit, p_ifo->vts.i_pos +
646 MGINF.i_title_unit_start_sector, 0 ) < 0 )
653 * time map information
655 #define TIMINF p_ifo->vts.time_inf
656 if( MGINF.i_time_inf_start_sector )
658 u8 p_buf[DVD_LB_SIZE];
660 p_tmp = FillBuffer( p_ifo, p_buf, p_ifo->vts.i_pos +
661 MGINF.i_time_inf_start_sector );
663 /*fprintf( stderr, "TMAP\n" ); */
665 TIMINF.i_nb = ReadWord( p_ifo, p_buf, &p_tmp );;
666 DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
667 TIMINF.i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
669 TIMINF.pi_start_byte = malloc( TIMINF.i_nb * sizeof(u32) );
670 if( TIMINF.pi_start_byte == NULL )
675 for( i = 0 ; i < TIMINF.i_nb ; i++ )
677 TIMINF.pi_start_byte[i] = ReadDouble( p_ifo, p_buf, &p_tmp );
680 TIMINF.p_time_map = malloc( TIMINF.i_nb * sizeof(time_map_t) );
681 if( TIMINF.p_time_map == NULL )
686 for( i = 0 ; i < TIMINF.i_nb ; i++ )
688 TIMINF.p_time_map[i].i_time_unit = ReadByte( p_ifo, p_buf, &p_tmp );
689 DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
690 TIMINF.p_time_map[i].i_entry_nb = ReadWord( p_ifo, p_buf, &p_tmp );
692 if( TIMINF.p_time_map[i].i_entry_nb )
694 TIMINF.p_time_map[i].pi_sector =
695 malloc( TIMINF.p_time_map[i].i_entry_nb * sizeof(u32) );
696 if( TIMINF.p_time_map[i].pi_sector == NULL )
701 for( j = 0 ; j < TIMINF.p_time_map[i].i_entry_nb ; j++ )
703 TIMINF.p_time_map[i].pi_sector[j] =
704 ReadDouble( p_ifo, p_buf, &p_tmp );
711 if( MGINF.i_menu_cell_inf_start_sector
712 && ReadCellInf( p_ifo, &p_ifo->vts.menu_cell_inf, p_ifo->vts.i_pos +
713 MGINF.i_menu_cell_inf_start_sector ) < 0 )
718 if( MGINF.i_menu_vobu_map_start_sector
719 && ReadVobuMap( p_ifo, &p_ifo->vts.menu_vobu_map, p_ifo->vts.i_pos +
720 MGINF.i_menu_vobu_map_start_sector ) < 0 )
725 if( MGINF.i_cell_inf_start_sector
726 && ReadCellInf( p_ifo, &p_ifo->vts.cell_inf, p_ifo->vts.i_pos +
727 MGINF.i_cell_inf_start_sector ) )
732 if( MGINF.i_vobu_map_start_sector
733 && ReadVobuMap( p_ifo, &p_ifo->vts.vobu_map, p_ifo->vts.i_pos +
734 MGINF.i_vobu_map_start_sector ) )
741 intf_Warn( p_input, 4, "vts %d initialized",
742 p_ifo->vmg.title_inf.p_attr[i_title-1].i_title_set_num );
745 p_ifo->vts.b_initialized = 1;
750 /*****************************************************************************
751 * FreeTitleSet : free all structures allocated by IfoTitleSet
752 *****************************************************************************/
753 static int FreeTitleSet( vts_t * p_vts )
757 if( p_vts->manager_inf.i_vobu_map_start_sector )
759 FreeVobuMap( &p_vts->vobu_map );
762 if( p_vts->manager_inf.i_cell_inf_start_sector )
764 FreeCellInf( &p_vts->cell_inf );
767 if( p_vts->manager_inf.i_menu_vobu_map_start_sector )
769 FreeVobuMap( &p_vts->menu_vobu_map );
772 if( p_vts->manager_inf.i_menu_cell_inf_start_sector )
774 FreeCellInf( &p_vts->menu_cell_inf );
777 if( p_vts->manager_inf.i_time_inf_start_sector )
779 for( i = 0 ; i < p_vts->time_inf.i_nb ; i++ )
781 if( p_vts->time_inf.p_time_map[i].i_entry_nb )
783 free( p_vts->time_inf.p_time_map[i].pi_sector );
787 free( p_vts->time_inf.p_time_map );
788 free( p_vts->time_inf.pi_start_byte );
791 if( p_vts->manager_inf.i_title_unit_start_sector )
793 FreeUnitInf( &p_vts->title_unit );
796 if( p_vts->manager_inf.i_menu_unit_start_sector )
798 FreeTitleUnit( &p_vts->menu_unit );
801 if( p_vts->manager_inf.i_title_inf_start_sector )
803 free( p_vts->title_inf.pi_start_byte );
804 free( p_vts->title_inf.p_title_start );
807 p_vts->b_initialized = 0;
812 /*****************************************************************************
813 * IfoDestroy : Frees all the memory allocated to ifo structures
814 *****************************************************************************/
815 void IfoDestroy( ifo_t * p_ifo )
819 FreeTitleSet( &p_ifo->vts );
821 if( p_ifo->vmg.manager_inf.i_vobu_map_start_sector )
823 FreeVobuMap( &p_ifo->vmg.vobu_map );
826 if( p_ifo->vmg.manager_inf.i_cell_inf_start_sector )
828 FreeCellInf( &p_ifo->vmg.cell_inf );
831 if( p_ifo->vmg.manager_inf.i_vts_inf_start_sector )
833 free( p_ifo->vmg.vts_inf.p_vts_attr );
834 free( p_ifo->vmg.vts_inf.pi_vts_attr_start_byte );
837 /* free parental information structures */
838 if( p_ifo->vmg.manager_inf.i_parental_inf_start_sector )
840 for( i = 0 ; i < p_ifo->vmg.parental_inf.i_country_nb ; i++ )
842 for( j = 0 ; j < 8 ; j++ )
844 if ( p_ifo->vmg.parental_inf.p_parental_mask[i].ppi_mask[j] != NULL )
845 free( p_ifo->vmg.parental_inf.p_parental_mask[i].ppi_mask[j] );
849 if ( p_ifo->vmg.parental_inf.p_parental_mask != NULL )
850 free( p_ifo->vmg.parental_inf.p_parental_mask );
851 if ( p_ifo->vmg.parental_inf.p_parental_desc != NULL )
852 free( p_ifo->vmg.parental_inf.p_parental_desc );
855 if( p_ifo->vmg.manager_inf.i_title_unit_start_sector )
857 FreeTitleUnit( &p_ifo->vmg.title_unit );
860 if( p_ifo->vmg.manager_inf.i_title_inf_start_sector )
862 free( p_ifo->vmg.title_inf.p_attr );
865 FreeTitle( &p_ifo->vmg.title );
873 * Function common to Video Manager and Video Title set Processing
876 /*****************************************************************************
877 * ReadTitle : Fills the title structure.
878 *****************************************************************************
879 * Titles are logical stream units that correspond to a whole inside the dvd.
880 * Several title can point to the same part of the physical DVD, and give
881 * map to different anglesfor instance.
882 *****************************************************************************/
883 static int ReadTitle( ifo_t * p_ifo, title_t * p_title, int i_block, int i_bytes )
885 u8 p_buf[DVD_LB_SIZE];
892 p_tmp = FillBuffer( p_ifo, p_buf, i_block ) + i_bytes;
894 i_start = p_ifo->i_pos;
896 /*fprintf( stderr, "PGC @ %d + %d\n", p_ifo->i_pos, i_bytes ); */
898 DumpBytes( p_ifo, p_buf, &p_tmp, 2);
899 p_title->i_chapter_nb = ReadByte( p_ifo, p_buf, &p_tmp );
900 p_title->i_cell_nb = ReadByte( p_ifo, p_buf, &p_tmp );
901 /*fprintf( stderr, "title: Prg: %d Cell: %d\n",p_title->i_chapter_nb,p_title->i_cell_nb ); */
902 p_title->i_play_time = ReadDouble( p_ifo, p_buf, &p_tmp );
903 p_title->i_prohibited_user_op = ReadDouble( p_ifo, p_buf, &p_tmp );
905 for( i = 0 ; i < 8 ; i++ )
907 i_audio = ReadWord( p_ifo, p_buf, &p_tmp );
908 p_title->pi_audio_status[i].i_foo = i_audio & 0xff;
910 p_title->pi_audio_status[i].i_position = i_audio & 0x07;
912 p_title->pi_audio_status[i].i_available = i_audio;
915 for( i = 0 ; i < 32 ; i++ )
917 i_spu = ReadDouble( p_ifo, p_buf, &p_tmp );
918 p_title->pi_spu_status[i].i_position_pan = i_spu & 0x1f;
920 p_title->pi_spu_status[i].i_position_letter = i_spu & 0x1f;
922 p_title->pi_spu_status[i].i_position_wide = i_spu & 0x1f;
924 p_title->pi_spu_status[i].i_position_43 = i_spu & 0x1f;
926 p_title->pi_spu_status[i].i_available = i_spu;
929 p_title->i_next_title_num = ReadWord( p_ifo, p_buf, &p_tmp );
930 p_title->i_prev_title_num = ReadWord( p_ifo, p_buf, &p_tmp );
931 p_title->i_go_up_title_num = ReadWord( p_ifo, p_buf, &p_tmp );
932 p_title->i_still_time = ReadByte( p_ifo, p_buf, &p_tmp );
933 p_title->i_play_mode = ReadByte( p_ifo, p_buf, &p_tmp );
935 for( i = 0 ; i < 16 ; i++ )
937 /* FIXME : We have to erase the extra bit */
938 p_title->pi_yuv_color[i] = ReadDouble( p_ifo, p_buf, &p_tmp );
941 p_title->i_command_start_byte = ReadWord( p_ifo, p_buf, &p_tmp );
942 p_title->i_chapter_map_start_byte = ReadWord( p_ifo, p_buf, &p_tmp );
943 p_title->i_cell_play_start_byte = ReadWord( p_ifo, p_buf, &p_tmp );
944 p_title->i_cell_pos_start_byte = ReadWord( p_ifo, p_buf, &p_tmp );
946 /* parsing of command_t */
947 if( p_title->i_command_start_byte )
949 p_tmp = FillBuffer( p_ifo, p_buf, i_start +
950 OFF2LB( p_title->i_command_start_byte + i_bytes ) )
951 + ( (p_title->i_command_start_byte + i_bytes) & 0x7ff );
954 p_title->command.i_pre_command_nb = ReadWord( p_ifo, p_buf, &p_tmp );
955 p_title->command.i_post_command_nb = ReadWord( p_ifo, p_buf, &p_tmp );
956 p_title->command.i_cell_command_nb = ReadWord( p_ifo, p_buf, &p_tmp );
957 DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
959 /* pre-title commands */
960 if( p_title->command.i_pre_command_nb )
962 p_title->command.p_pre_command =
963 malloc( p_title->command.i_pre_command_nb
964 * sizeof(command_desc_t) );
966 if( p_title->command.p_pre_command == NULL )
971 for( i = 0 ; i < p_title->command.i_pre_command_nb ; i++ )
973 p_title->command.p_pre_command[i] =
974 ReadQuad( p_ifo, p_buf, &p_tmp );
979 p_title->command.p_pre_command = NULL;
982 /* post-title commands */
983 if( p_title->command.i_post_command_nb )
985 p_title->command.p_post_command =
986 malloc( p_title->command.i_post_command_nb
987 * sizeof(command_desc_t) );
989 if( p_title->command.p_post_command == NULL )
994 for( i = 0 ; i < p_title->command.i_post_command_nb ; i++ )
996 p_title->command.p_post_command[i] =
997 ReadQuad( p_ifo, p_buf, &p_tmp );
1002 p_title->command.p_post_command = NULL;
1006 if( p_title->command.i_cell_command_nb )
1008 p_title->command.p_cell_command =
1009 malloc( p_title->command.i_cell_command_nb
1010 * sizeof(command_desc_t) );
1012 if( p_title->command.p_cell_command == NULL )
1017 for( i = 0 ; i < p_title->command.i_cell_command_nb ; i++ )
1019 p_title->command.p_cell_command[i] =
1020 ReadQuad( p_ifo, p_buf, &p_tmp );
1025 p_title->command.p_cell_command = NULL;
1029 /* parsing of chapter_map_t: it gives the entry cell for each chapter */
1030 if( p_title->i_chapter_map_start_byte )
1032 p_ifo->i_pos = dvdcss_seek( p_ifo->dvdhandle,
1033 OFF2LB( i_start + p_title->i_chapter_map_start_byte ),
1036 p_title->chapter_map.pi_start_cell =
1037 malloc( p_title->i_chapter_nb * sizeof(chapter_map_t) );
1039 if( p_title->chapter_map.pi_start_cell == NULL )
1044 ReadBytes( p_ifo, p_buf, &p_tmp, p_title->chapter_map.pi_start_cell,
1045 p_title->i_chapter_nb );
1049 p_title->chapter_map.pi_start_cell = NULL;
1052 /* parsing of cell_play_t */
1053 if( p_title->i_cell_play_start_byte )
1055 p_tmp = FillBuffer( p_ifo, p_buf, i_start +
1056 OFF2LB( p_title->i_cell_play_start_byte+i_bytes ) )
1057 + ( (p_title->i_cell_play_start_byte+i_bytes) & 0x7ff );
1059 p_title->p_cell_play = malloc( p_title->i_cell_nb
1060 * sizeof(cell_play_t) );
1062 if( p_title->p_cell_play == NULL )
1067 for( i = 0 ; i < p_title->i_cell_nb ; i++ )
1069 #define PLAY p_title->p_cell_play[i]
1070 PLAY.i_category = ReadWord( p_ifo, p_buf, &p_tmp );
1071 PLAY.i_still_time = ReadByte( p_ifo, p_buf, &p_tmp );
1072 PLAY.i_command_nb = ReadByte( p_ifo, p_buf, &p_tmp );
1073 PLAY.i_play_time = ReadDouble( p_ifo, p_buf, &p_tmp );
1074 PLAY.i_first_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
1075 PLAY.i_first_ilvu_vobu_esector = ReadDouble( p_ifo, p_buf, &p_tmp );
1076 PLAY.i_last_vobu_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
1077 PLAY.i_last_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
1082 /* Parsing of cell_pos_t */
1083 if( p_title->i_cell_pos_start_byte )
1085 p_tmp = FillBuffer( p_ifo, p_buf, i_start +
1086 OFF2LB( p_title->i_cell_pos_start_byte + i_bytes ) )
1087 + ( (p_title->i_cell_pos_start_byte + i_bytes) & 0x7ff );
1089 p_title->p_cell_pos = malloc( p_title->i_cell_nb
1090 * sizeof(cell_pos_t) );
1092 if( p_title->p_cell_pos == NULL )
1097 for( i = 0 ; i < p_title->i_cell_nb ; i++ )
1099 p_title->p_cell_pos[i].i_vob_id = ReadWord( p_ifo, p_buf, &p_tmp );
1100 DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
1101 p_title->p_cell_pos[i].i_cell_id = ReadByte( p_ifo, p_buf, &p_tmp );
1108 /*****************************************************************************
1109 * FreeTitle: frees alla structure allocated by a call to ReadTitle
1110 *****************************************************************************/
1111 static int FreeTitle( title_t * p_title )
1113 if( p_title->i_command_start_byte )
1115 if( p_title->command.i_pre_command_nb )
1117 free( p_title->command.p_pre_command );
1120 if( p_title->command.i_post_command_nb )
1122 free( p_title->command.p_post_command );
1125 if( p_title->command.i_cell_command_nb )
1127 free( p_title->command.p_cell_command );
1131 if( p_title->i_chapter_map_start_byte )
1133 free( p_title->chapter_map.pi_start_cell );
1136 if( p_title->i_cell_play_start_byte )
1138 free( p_title->p_cell_play );
1141 if( p_title->i_cell_pos_start_byte )
1143 free( p_title->p_cell_pos );
1149 /*****************************************************************************
1150 * ReadUnitInf : Fills Menu Language Unit Table/ PGC Info Table
1151 *****************************************************************************/
1152 static int ReadUnitInf( ifo_t * p_ifo, unit_inf_t * p_unit_inf,
1153 int i_block, int i_bytes )
1155 u8 p_buf[DVD_LB_SIZE];
1160 p_tmp = FillBuffer( p_ifo, p_buf, i_block ) + i_bytes;
1162 i_start = p_ifo->i_pos;
1163 /*fprintf( stderr, "Unit\n" ); */
1165 p_unit_inf->i_title_nb = ReadWord( p_ifo, p_buf, &p_tmp );
1166 /*fprintf( stderr, "Unit nb: %d\n", p_unit_inf->i_title_nb ); */
1167 DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
1168 p_unit_inf->i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
1170 p_unit_inf->p_title =
1171 malloc( p_unit_inf->i_title_nb * sizeof(unit_title_t) );
1172 if( p_unit_inf->p_title == NULL )
1177 for( i = 0 ; i < p_unit_inf->i_title_nb ; i++ )
1179 #define TITLE p_unit_inf->p_title[i]
1180 TITLE.i_category_mask = ReadByte( p_ifo, p_buf, &p_tmp );
1181 TITLE.i_category = ReadByte( p_ifo, p_buf, &p_tmp );
1182 /*fprintf( stderr, "cat mask %d: %x cat %x\n", i, TITLE.i_category_mask, TITLE.i_category ); */
1183 TITLE.i_parental_mask = ReadWord( p_ifo, p_buf, &p_tmp );
1184 TITLE.i_title_start_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
1188 for( i = 0 ; i < p_unit_inf->i_title_nb ; i++ )
1190 /*fprintf( stderr, "Unit: PGC %d @ %d\n", i, p_ifo->i_pos ); */
1191 ReadTitle( p_ifo, &p_unit_inf->p_title[i].title, i_start +
1192 OFF2LB( p_unit_inf->p_title[i].i_title_start_byte + i_bytes ),
1193 (p_unit_inf->p_title[i].i_title_start_byte+i_bytes) & 0x7ff );
1199 /*****************************************************************************
1200 * FreeUnitInf : frees a structure allocated by ReadUnit
1201 *****************************************************************************/
1202 static int FreeUnitInf( unit_inf_t * p_unit_inf )
1206 if( p_unit_inf->p_title != NULL )
1208 for( i = 0 ; i < p_unit_inf->i_title_nb ; i++ )
1210 FreeTitle( &p_unit_inf->p_title[i].title );
1213 free( p_unit_inf->p_title );
1220 /*****************************************************************************
1221 * ReadTitleUnit: Fills the Title Unit structure.
1222 *****************************************************************************/
1223 static int ReadTitleUnit( ifo_t * p_ifo, title_unit_t * p_title_unit,
1226 u8 p_buf[DVD_LB_SIZE];
1231 p_tmp = FillBuffer( p_ifo, p_buf, i_block );
1232 i_start = p_ifo->i_pos;
1233 /*fprintf( stderr, "Unit Table\n" ); */
1235 p_title_unit->i_unit_nb = ReadWord( p_ifo, p_buf, &p_tmp );
1236 DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
1237 p_title_unit->i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
1239 /*fprintf(stderr, "Unit: nb %d last %d\n", p_title_unit->i_unit_nb, p_title_unit->i_last_byte ); */
1241 p_title_unit->p_unit = malloc( p_title_unit->i_unit_nb * sizeof(unit_t) );
1242 if( p_title_unit->p_unit == NULL )
1247 for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ )
1249 /*ReadBytes( p_ifo, p_buf, &p_tmp, p_title_unit->p_unit[i].ps_lang_code, 2 ); */
1250 p_title_unit->p_unit[i].i_lang_code = ReadWord( p_ifo, p_buf, &p_tmp );
1251 /*fprintf( stderr, "lang %d %x\n", i,p_title_unit->p_unit[i].i_lang_code ); */
1252 DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
1253 p_title_unit->p_unit[i].i_existence_mask =
1254 ReadByte( p_ifo, p_buf, &p_tmp );
1255 p_title_unit->p_unit[i].i_unit_inf_start_byte =
1256 ReadDouble( p_ifo, p_buf, &p_tmp );
1259 p_title_unit->p_unit_inf =
1260 malloc( p_title_unit->i_unit_nb * sizeof(unit_inf_t) );
1261 if( p_title_unit->p_unit_inf == NULL )
1266 for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ )
1268 ReadUnitInf( p_ifo, &p_title_unit->p_unit_inf[i], i_start +
1269 OFF2LB( p_title_unit->p_unit[i].i_unit_inf_start_byte ),
1270 p_title_unit->p_unit[i].i_unit_inf_start_byte & 0x7ff );
1276 /*****************************************************************************
1277 * FreeTitleUnit: frees a structure allocateed by ReadTitleUnit
1278 *****************************************************************************/
1279 static int FreeTitleUnit( title_unit_t * p_title_unit )
1283 if( p_title_unit->p_unit_inf != NULL )
1285 for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ )
1287 FreeUnitInf( &p_title_unit->p_unit_inf[i] );
1290 free( p_title_unit->p_unit_inf );
1296 /*****************************************************************************
1297 * ReadCellInf : Fills the Cell Information structure.
1298 *****************************************************************************/
1299 static int ReadCellInf( ifo_t * p_ifo, cell_inf_t * p_cell_inf, int i_block )
1301 u8 p_buf[DVD_LB_SIZE];
1306 p_tmp = FillBuffer( p_ifo, p_buf, i_block );
1307 i_start = p_ifo->i_pos;
1308 /* fprintf( stderr, "CELL ADD\n" ); */
1310 p_cell_inf->i_vob_nb = ReadWord( p_ifo, p_buf, &p_tmp );
1311 DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
1312 p_cell_inf->i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
1314 p_cell_inf->i_cell_nb = (p_cell_inf->i_last_byte + 1/* - 7*/) / sizeof(cell_map_t);
1316 /* fprintf( stderr, "Cell inf: vob %d, %d cells, last byte %d\n", p_cell_inf->i_vob_nb, p_cell_inf->i_cell_nb, p_cell_inf->i_last_byte );
1318 p_cell_inf->p_cell_map =
1319 malloc( p_cell_inf->i_cell_nb *sizeof(cell_map_t) );
1320 if( p_cell_inf->p_cell_map == NULL )
1325 for( i = 0 ; i < p_cell_inf->i_cell_nb ; i++ )
1327 #define MAP p_cell_inf->p_cell_map[i]
1328 MAP.i_vob_id = ReadWord( p_ifo, p_buf, &p_tmp );
1329 MAP.i_cell_id = ReadByte( p_ifo, p_buf, &p_tmp );
1330 DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
1331 MAP.i_first_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
1332 /* fprintf(stderr, "sector[%d] %d (%d)\n", i,ntohl(*(u32*)(p_tmp)), p_ifo->i_pos);*/
1333 MAP.i_last_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
1340 /*****************************************************************************
1341 * FreeCellInf : frees structures allocated by ReadCellInf
1342 *****************************************************************************/
1343 static int FreeCellInf( cell_inf_t * p_cell_inf )
1345 free( p_cell_inf->p_cell_map );
1350 /*****************************************************************************
1351 * ReadVobuMap : Fills the VOBU Map structure.
1352 *****************************************************************************/
1353 static int ReadVobuMap( ifo_t * p_ifo, vobu_map_t * p_vobu_map, int i_block )
1355 u8 p_buf[DVD_LB_SIZE];
1360 p_tmp = FillBuffer( p_ifo, p_buf, i_block );
1361 i_start = p_ifo->i_pos;
1362 /*fprintf( stderr, "VOBU ADMAP\n" ); */
1364 p_vobu_map->i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
1365 i_max = ( i_start + p_vobu_map->i_last_byte + 1 - p_ifo->i_pos )
1368 p_vobu_map->pi_vobu_start_sector = malloc( i_max * sizeof(u32) );
1369 if( p_vobu_map->pi_vobu_start_sector == NULL )
1374 for( i = 0 ; i < i_max ; i++ )
1376 p_vobu_map->pi_vobu_start_sector[i] = ReadDouble( p_ifo, p_buf, &p_tmp );
1382 /*****************************************************************************
1383 * FreeVobuMap: frees structures allocated by ReadVobuMap
1384 *****************************************************************************/
1385 static int FreeVobuMap( vobu_map_t * p_vobu_map )
1387 free( p_vobu_map->pi_vobu_start_sector );
1393 * IFO virtual machine : a set of commands that give the
1394 * interactive behaviour of the dvd
1398 #define OP_VAL_16(i) (ntoh16( com.data.pi_16[i]))
1399 #define OP_VAL_8(i) ((com.data.pi_8[i]))
1401 static char ifo_reg[][80]=
1403 "Menu_Language_Code",
1405 "SubPicture_Stream_#",
1411 "Highlighted_Button_#",
1414 "Karaoke_audio_mixing_mode",
1415 "Parental_mgmt_country_code",
1419 "Audio_language_code_setting",
1420 "Audio_language_extension_code",
1421 "SPU_language_code_setting",
1422 "SPU_language_extension_code",
1423 "?Player_Regional_Code",
1429 static char * IfoMath( char val )
1431 static char math_op[][10] =
1451 return (char *) math_op[val & 0x0f];
1455 char ifo_cmp[][10] =
1467 char ifo_parental[][10] =
1479 char ifo_menu_id[][80] =
1491 char * IfoMenuName( char index )
1493 return ifo_menu_id[index&0x07];
1496 static void IfoRegister( u16 i_data, u8 i_direct)
1500 if( 0/*isalpha( i_data >> 8 & 0xff )*/ )
1502 printf("'%c%c'", i_data>>8&0xff, i_data&0xff);
1506 printf("0x%02x", i_data);
1521 printf("s[%s]", ifo_reg[i_data]);
1534 printf("r[0x%02x]", i_data);
1540 static void IfoAdvanced( u8 *pi_code )
1542 u8 i_cmd = pi_code[0];
1548 printf( " Highlight button %d; ", pi_code[1]>>2 );
1553 printf( " Illegal " );
1558 printf( "ReSuME %d", pi_code[7] );
1560 else if( ( i_cmd & 0x06) == 0x02 )
1562 printf ("Link to %s cell ", ( i_cmd & 0x01 ) ? "prev" : "next");
1566 printf( "advanced (0x%02x) ", i_cmd );
1571 static void IfoJmp( ifo_command_t com )
1576 switch( com.i_sub_cmd )
1582 printf( "VTS 0x%02x", OP_VAL_8(3) );
1585 printf( "This VTS Title 0x%02x", OP_VAL_8(3) );
1588 printf( "This VTS Title 0x%02x Part 0x%04x",
1590 OP_VAL_8(0)<<8|OP_VAL_8(1));
1594 printf ("in SystemSpace ");
1595 switch (OP_VAL_8(3)>>4) {
1597 printf ("to play first PGC");
1600 printf ("to menu \"%s\"", decode_menuname (OP_VAL_8(3)));
1604 printf ("to VTS 0x%02x and TTN 0x%02x", OP_VAL_8(1), OP_VAL_8(2));
1607 printf ("to VMGM PGC number 0x%02x", OP_VAL_8(0)<<8 | OP_VAL_8(1));
1610 printf ("vts 0x%02x lu 0x%02x menu \"%s\"", OP_VAL_8(2), OP_VAL_8(1), decode_menuname (OP_VAL_8(3)));
1613 switch( OP_VAL_8(3)>>6 )
1616 printf( "to play first PGC" );
1619 printf( "to VMG title menu (?)" );
1622 printf( "vts 0x%02x lu 0x%02x menu \"%s\"",
1625 IfoMenuName( OP_VAL_8(3)&0xF ) );
1628 printf( "vmg pgc 0x%04x (?)", ( OP_VAL_8(0)<<8) | OP_VAL_8(1) );
1635 switch(OP_VAL_8(3)>>4) {
1637 printf ("system first pgc");
1640 printf ("system title menu");
1643 printf ("system menu \"%s\"", decode_menuname (OP_VAL_8(3)));
1646 printf ("system vmg pgc %02x ????", OP_VAL_8(0)<<8|OP_VAL_8(1));
1649 printf ("system lu 0x%02x menu \"%s\"", OP_VAL_8(2), decode_menuname (OP_VAL_8(3)));
1652 printf ("system vmg pgc 0x%02x", OP_VAL_8(0)<<8|OP_VAL_8(1));
1656 /* OP_VAL_8(2) is number of cell */
1657 /* it is processed BEFORE switch */
1658 /* under some conditions, it is ignored */
1659 /* I don't understand exactly what it means */
1660 printf( " ( spec cell 0x%02X ) ", OP_VAL_8(2) );
1662 switch( OP_VAL_8(3)>>6 )
1665 printf( "to FP PGC" );
1668 printf( "to VMG root menu (?)" );
1671 printf( "to VTS menu \"%s\" (?)",
1672 IfoMenuName(OP_VAL_8(3)&0xF) );
1675 printf( "vmg pgc 0x%02x (?)", (OP_VAL_8(0)<<8)|OP_VAL_8(1) );
1683 static void IfoLnk( ifo_command_t com )
1685 u16 i_button=OP_VAL_8(4)>>2;
1689 switch( com.i_sub_cmd )
1692 IfoAdvanced( &OP_VAL_8(4) );
1696 printf( "PGC 0x%02x", OP_VAL_16(2) );
1700 printf( "PTT 0x%02x", OP_VAL_16(2) );
1704 printf( "Program 0x%02x this PGC", OP_VAL_8(5) );
1708 printf( "Cell 0x%02x this PGC", OP_VAL_8(5) );
1716 printf( ", Highlight 0x%02x", OP_VAL_8(4)>>2 );
1721 void IfoSetSystem( ifo_command_t com )
1728 for( i=1; i<=3; i++ )
1730 if( OP_VAL_8(i)&0x80 )
1734 printf ("s[%s] = 0x%02x;", ifo_reg[i], OP_VAL_8(i)&0xf);
1738 printf ("s[%s] = r[0x%02x];", ifo_reg[i], OP_VAL_8(i)&0xf);
1744 if(OP_VAL_8(1]&0x80)
1745 printf ("s[%s] = 0x%02x;", reg_name[1], OP_VAL_8(1]&0xf);
1746 if(OP_VAL_8(2)&0x80)
1747 /*DENT: lwhat about 0x7f here ??? */
1748 printf ("s[%s] = 0x%02x;", reg_name[2], OP_VAL_8(2)&0x7f);
1749 if(OP_VAL_8(3)&0x80)
1750 printf ("s[%s] = 0x%02x;", reg_name[3], OP_VAL_8(3)&0xf);
1752 if(OP_VAL_8(1)&0x80)
1753 printf ("s[%s] = r[0x%02x];", reg_name[1], OP_VAL_8(1)&0xf);
1754 if(OP_VAL_8(2)&0x80)
1755 printf ("s[%s] = r[0x%02x];", reg_name[2], OP_VAL_8(2)&0xf);
1756 if(OP_VAL_8(3)&0x80)
1757 printf ("s[%s] = r[0x%02x];", reg_name[3], OP_VAL_8(3)&0xf);
1765 printf( "s[%s] = 0x%02x", ifo_reg[9], OP_VAL_16(0) );
1769 printf( "s[%s] = r[0x%02x]", ifo_reg[9], OP_VAL_8(1)&0x0f );
1772 printf( "s[%s] = (s[%s]&0x7FFF)|0x%02x",
1773 ifo_reg[10], ifo_reg[10], OP_VAL_16(1)&0x8000);
1778 printf( "r[0x%02x] = 0x%02x", OP_VAL_8(3)&0x0f, OP_VAL_16(0) );
1782 printf ("r[r[0x%02x]] = r[0x%02x]",
1783 OP_VAL_8(3)&0x0f, OP_VAL_8(1)&0x0f);
1787 /*actually only bits 00011100 00011100 are set */
1790 printf ("s[%s] = 0x%02x", ifo_reg[11], OP_VAL_16(1));
1794 printf ("s[%s] = r[0x%02x]", ifo_reg[11], OP_VAL_8(3)&0x0f );
1799 /*s[%s]=(r[%s]&0x3FF) | (0x%02x << 0xA); */
1800 /*but it is way too ugly */
1803 printf( "s[%s] = 0x%02x", ifo_reg[8], OP_VAL_8(2)>>2 );
1807 printf( "s[%s] = r[0x%02x]", ifo_reg[8], OP_VAL_8(3)&0x0f );
1815 static void IfoSet( ifo_command_t com )
1817 IfoRegister( OP_VAL_16(0), 0 );
1818 printf( " %s ", IfoMath( com.i_cmd ) );
1819 IfoRegister( OP_VAL_16(1), com.i_direct );
1822 /*****************************************************************************
1823 * CommandRead : translates the command strings in ifo into command
1825 *****************************************************************************/
1826 void CommandRead( ifo_command_t com )
1828 u8* pi_code = (u8*)(&com);
1830 switch( com.i_type )
1843 printf ("if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
1844 ifo_cmp[com.i_cmp]);
1845 IfoRegister (OP_VAL_16(1), com.i_dir_cmp);
1850 switch( com.i_sub_cmd )
1853 printf( "goto Line 0x%02x", OP_VAL_16(2) );
1857 printf( "stop VM" );
1861 printf( "Set Parental Level To %s and goto Line 0x%02x",
1862 ifo_parental[OP_VAL_8(4)&0x7],
1867 printf( "Illegal" );
1886 printf( "if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f,
1887 ifo_cmp[com.i_cmp] );
1888 IfoRegister( OP_VAL_8(5), 0 );
1899 printf( "if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
1900 ifo_cmp[com.i_cmp] );
1901 IfoRegister( OP_VAL_16(1), com.i_dir_cmp );
1915 IfoSetSystem( com );
1917 else if( com.i_cmp && !com.i_sub_cmd )
1919 printf ("if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f, ifo_cmp[com.i_cmp]);
1920 IfoRegister( OP_VAL_8(5), 0 );
1922 IfoSetSystem( com );
1924 else if( !com.i_cmp && com.i_sub_cmd )
1927 IfoSetSystem( com );
1943 else if( com.i_cmp && !com.i_sub_cmd )
1945 printf ("if (r[0x%02x] %s ", OP_VAL_8(0)&0x0f, ifo_cmp[com.i_cmp]);
1946 IfoRegister( OP_VAL_16(2), com.i_dir_cmp );
1950 else if( !com.i_cmp && com.i_sub_cmd )
1964 * math command on r[opcode[1]] and
1965 * direct?be2me_16(OP_VAL_8(0)):reg[OP_VAL_8(1)] is executed
1966 * ( unless command is swap; then r[opcode[1]] and r[OP_VAL_8(1)]
1968 * boolean operation cmp on r[opcode[1]] and
1969 * dir_cmp?be2me_16(OP_VAL_8(1)[1]):reg[OP_VAL_8(3)] is executed
1970 * on true result, buttons(c[6], c[7]) is called
1971 * problem is 'what is buttons()'
1974 printf( "r[0x%X] ", pi_code[1] );
1975 printf( " %s ", IfoMath( com.i_cmd ) );
1976 if( com.i_cmd == 2 )
1978 printf( "r[0x%X] ", OP_VAL_8(1) );
1982 IfoRegister( OP_VAL_16(0), com.i_direct );
1986 printf( "if ( r[%d] %s ", pi_code[1], ifo_cmp[com.i_cmp] );
1987 IfoRegister( OP_VAL_8(1), com.i_dir_cmp );
1988 printf( " ) then {" );
1989 IfoAdvanced( &OP_VAL_8(4) );
1994 * opposite to case 4: boolean, math and buttons.
2000 if( !com.i_direct && com.i_dir_cmp )
2002 printf( "0x%X", OP_VAL_16(1) );
2006 IfoRegister( OP_VAL_8(3), 0 );
2007 if( OP_VAL_8(3)&0x80 )
2009 printf( "s[%s]", ifo_reg[OP_VAL_8(3)&0x1F] );
2013 printf( "r[0x%X]", OP_VAL_8(3)&0x1F);
2014 /* 0x1F is either not a mistake, */
2015 /* or Microsoft programmer's mistake!!! */
2019 printf( " %s r[0x%X] ", ifo_cmp[com.i_cmp],
2020 com.i_direct ? OP_VAL_8(2) : OP_VAL_8(1) );
2021 printf( " ) then {" );
2022 printf( "r[0x%X] ", pi_code[1] & 0xF );
2023 printf( " %s ", IfoMath( com.i_cmd ) );
2025 if( com.i_cmd == 0x02 ) /* swap */
2027 printf("r[0x%X] ", OP_VAL_8(0)&0x1F);
2033 printf( "0x%X", OP_VAL_16(0) );
2037 if( OP_VAL_8(0) & 0x80 )
2039 printf("s[%s]", ifo_reg[OP_VAL_8(0) & 0x1F] );
2043 printf("r[0x%X]", OP_VAL_8(0) & 0x1F );
2049 IfoAdvanced( &OP_VAL_8(4) );
2055 printf( "Unknown Command\n" );
2062 /*****************************************************************************
2063 * CommandPrint : print in clear text (I hope so !) what a command does
2064 *****************************************************************************/
2065 void CommandPrint( ifo_t ifo )
2072 /*****************************************************************************
2074 *****************************************************************************/
2075 static u8* FillBuffer( ifo_t* p_ifo, u8* p_buf, int i_pos )
2077 p_ifo->i_pos = dvdcss_seek( p_ifo->dvdhandle, i_pos, DVDCSS_NOFLAGS );
2078 dvdcss_read( p_ifo->dvdhandle, p_buf, 1, DVDCSS_NOFLAGS );
2083 static void ReadBytes( ifo_t* p_ifo, u8* p_buf, u8** pp_tmp,
2084 u8* pi_dest, int i_nb )
2086 if( i_nb > DVD_LB_SIZE )
2089 intf_Err( p_input, "excessive ReadBytes call (%i)", i_nb );
2093 if( *pp_tmp + i_nb >= p_buf + DVD_LB_SIZE )
2095 int i_spare = (int)( (p_buf + DVD_LB_SIZE) - *pp_tmp );
2097 /* Copy the bytes remaining in the current buffer */
2098 memcpy( pi_dest, *pp_tmp, i_spare );
2102 /* Load the next buffer */
2103 *pp_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_pos + 1 );
2106 memcpy( pi_dest, *pp_tmp, i_nb );
2112 static void DumpBytes( ifo_t* p_ifo, u8* p_buf, u8** pp_tmp, int i_nb )
2114 if( i_nb > DVD_LB_SIZE )
2117 intf_Err( p_input, "excessive DumpBytes call (%i)", i_nb );
2123 if( *pp_tmp >= p_buf + DVD_LB_SIZE )
2125 /* If we went too far, load the next buffer */
2126 *pp_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_pos + 1 )
2127 + (int)( (*pp_tmp) - (p_buf + DVD_LB_SIZE) );
2134 if( *pp_tmp >= p_buf + DVD_LB_SIZE ) \
2136 *pp_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_pos + 1 ); \
2138 i_ret <<= 8; i_ret |= **pp_tmp; (*pp_tmp)++;
2140 static u8 ReadByte( ifo_t * p_ifo, u8* p_buf, u8** pp_tmp )
2147 static u16 ReadWord( ifo_t * p_ifo, u8* p_buf, u8** pp_tmp )
2154 static u32 ReadDouble( ifo_t * p_ifo, u8* p_buf, u8** pp_tmp )
2157 ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE;
2161 static u64 ReadQuad( ifo_t * p_ifo, u8* p_buf, u8** pp_tmp )
2164 ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE;