1 /*****************************************************************************
2 * dvd_ifo.c: Functions for ifo parsing
3 *****************************************************************************
4 * Copyright (C) 1999-2001 VideoLAN
5 * $Id: dvd_ifo.c,v 1.28 2001/05/31 01:37:08 sam Exp $
7 * Author: Stéphane Borel <stef@via.ecp.fr>
10 * - libifo by Thomas Mirlacher <dent@cosy.sbg.ac.at>
11 * - IFO structure documentation by Thomas Mirlacher, Björn Englund,
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
27 *****************************************************************************/
29 /*****************************************************************************
31 *****************************************************************************/
40 #elif defined( _MSC_VER ) && defined( _WIN32 )
52 #include "input_dvd.h"
57 void CommandRead ( command_desc_t
);
58 static int ReadTitle ( ifo_t
* , title_t
*, off_t
);
59 static int FreeTitle ( title_t
* );
60 static int ReadUnitInf ( ifo_t
* , unit_inf_t
*, off_t
);
61 static int FreeUnitInf ( unit_inf_t
* );
62 static int ReadTitleUnit ( ifo_t
* , title_unit_t
*, off_t
);
63 static int FreeTitleUnit ( title_unit_t
* );
64 static int ReadVobuMap ( ifo_t
* , vobu_map_t
*, off_t
);
65 static int FreeVobuMap ( vobu_map_t
* );
66 static int ReadCellInf ( ifo_t
* , cell_inf_t
*, off_t
);
67 static int FreeCellInf ( cell_inf_t
* );
68 static int FreeTitleSet ( vts_t
* );
70 /*****************************************************************************
72 *****************************************************************************/
73 static __inline__ u8
* FillBuffer( ifo_t
* p_ifo
, u8
* pi_buffer
, off_t i_pos
)
75 memset( pi_buffer
, 0, DVD_LB_SIZE
);
76 p_ifo
->i_pos
= lseek( p_ifo
->i_fd
, i_pos
, SEEK_SET
);
77 read( p_ifo
->i_fd
, pi_buffer
, DVD_LB_SIZE
);
82 static __inline__ u8
ReadByte( ifo_t
* p_ifo
, u8
* pi_buffer
, u8
** pp_current
)
86 if( *pp_current
> pi_buffer
+ DVD_LB_SIZE
)
88 *pp_current
= FillBuffer( p_ifo
, pi_buffer
, p_ifo
->i_pos
+ DVD_LB_SIZE
);
91 i_ret
= *(*pp_current
)++;
96 static __inline__ u16
ReadWord( ifo_t
* p_ifo
, u8
* pi_buffer
, u8
** pp_current
)
100 if( *pp_current
> pi_buffer
+ DVD_LB_SIZE
- 2 )
102 *pp_current
= FillBuffer( p_ifo
, pi_buffer
, p_ifo
->i_pos
+ DVD_LB_SIZE
);
105 i_ret
= U16_AT(*pp_current
);
111 static __inline__ u32
ReadDouble( ifo_t
* p_ifo
, u8
* pi_buffer
,
116 if( *pp_current
> pi_buffer
+ DVD_LB_SIZE
- 4 )
118 *pp_current
= FillBuffer( p_ifo
, pi_buffer
, p_ifo
->i_pos
+ DVD_LB_SIZE
);
119 // intf_WarnMsg( 1, "new buffer in double @ %lld", p_ifo->i_pos );
122 i_ret
= U32_AT(*pp_current
);
128 static __inline__ u64
ReadQuad( ifo_t
* p_ifo
, u8
* pi_buffer
, u8
** pp_current
)
132 if( *pp_current
> pi_buffer
+ DVD_LB_SIZE
- 8 )
134 *pp_current
= FillBuffer( p_ifo
, pi_buffer
, p_ifo
->i_pos
+ DVD_LB_SIZE
);
137 i_ret
= U64_AT(*pp_current
);
143 static __inline__
void ReadBits( ifo_t
* p_ifo
, u8
* pi_buffer
, u8
** pp_current
,
144 u8
* pi_dest
, int i_nb
)
146 if( *pp_current
> pi_buffer
+ DVD_LB_SIZE
- i_nb
)
148 *pp_current
= FillBuffer( p_ifo
, pi_buffer
, p_ifo
->i_pos
+ DVD_LB_SIZE
);
151 memcpy( pi_dest
, *pp_current
, i_nb
);
157 static __inline__
void DumpBits( ifo_t
* p_ifo
, u8
* pi_buffer
,
158 u8
** pp_current
, int i_nb
)
160 if( *pp_current
> pi_buffer
+ DVD_LB_SIZE
- i_nb
)
162 *pp_current
= FillBuffer( p_ifo
, pi_buffer
, p_ifo
->i_pos
+ DVD_LB_SIZE
);
173 /*****************************************************************************
174 * IfoCreate : Creates an ifo structure and prepares for parsing directly
176 *****************************************************************************/
177 int IfoCreate( thread_dvd_data_t
* p_dvd
)
179 p_dvd
->p_ifo
= malloc( sizeof(ifo_t
) );
180 if( p_dvd
->p_ifo
== NULL
)
182 intf_ErrMsg( "ifo error: unable to allocate memory. aborting" );
186 /* if we are here the dvd device has already been opened */
187 p_dvd
->p_ifo
->i_fd
= p_dvd
->i_fd
;
192 /*****************************************************************************
193 * IfoInit : Reads information from the management table.
194 *****************************************************************************/
195 int IfoInit( ifo_t
* p_ifo
)
197 u8 pi_buffer
[DVD_LB_SIZE
];
204 /* find the start sector of video information on the dvd */
205 i_lba
= UDFFindFile( p_ifo
->i_fd
, "/VIDEO_TS/VIDEO_TS.IFO");
207 p_ifo
->i_off
= (off_t
)(i_lba
) * DVD_LB_SIZE
;
209 p_current
= FillBuffer( p_ifo
, pi_buffer
, p_ifo
->i_off
);
210 //i_start = p_ifo->i_pos;
212 * read the video manager information table
214 #define manager_inf p_ifo->vmg.manager_inf
215 //fprintf( stderr, "VMGI\n" );
217 ReadBits( p_ifo
, pi_buffer
, &p_current
, manager_inf
.psz_id
, 12 );
218 manager_inf
.psz_id
[12] = '\0';
219 manager_inf
.i_vmg_end_sector
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
220 DumpBits( p_ifo
, pi_buffer
, &p_current
, 12 );
221 manager_inf
.i_vmg_inf_end_sector
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
222 DumpBits( p_ifo
, pi_buffer
, &p_current
, 1 );
223 manager_inf
.i_spec_ver
= ReadByte( p_ifo
, pi_buffer
, &p_current
);
224 manager_inf
.i_cat
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
225 manager_inf
.i_volume_nb
= ReadWord( p_ifo
, pi_buffer
, &p_current
);
226 manager_inf
.i_volume
= ReadWord( p_ifo
, pi_buffer
, &p_current
);
227 manager_inf
.i_disc_side
= ReadByte( p_ifo
, pi_buffer
, &p_current
);
228 DumpBits( p_ifo
, pi_buffer
, &p_current
, 19 );
229 manager_inf
.i_title_set_nb
= ReadWord( p_ifo
, pi_buffer
, &p_current
);
230 ReadBits( p_ifo
, pi_buffer
, &p_current
, manager_inf
.ps_provider_id
, 32 );
231 manager_inf
.i_pos_code
= ReadQuad( p_ifo
, pi_buffer
, &p_current
);
232 DumpBits( p_ifo
, pi_buffer
, &p_current
, 24 );
233 manager_inf
.i_vmg_inf_end_byte
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
234 manager_inf
.i_first_play_title_start_byte
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
235 DumpBits( p_ifo
, pi_buffer
, &p_current
, 56 );
236 manager_inf
.i_vob_start_sector
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
237 manager_inf
.i_title_inf_start_sector
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
238 manager_inf
.i_title_unit_start_sector
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
239 manager_inf
.i_parental_inf_start_sector
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
240 manager_inf
.i_vts_inf_start_sector
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
241 manager_inf
.i_text_data_start_sector
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
242 manager_inf
.i_cell_inf_start_sector
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
243 manager_inf
.i_vobu_map_start_sector
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
244 DumpBits( p_ifo
, pi_buffer
, &p_current
, 32 );
245 // GETS( &manager_inf.video_atrt );
246 DumpBits( p_ifo
, pi_buffer
, &p_current
, 2 );
247 DumpBits( p_ifo
, pi_buffer
, &p_current
, 1 );
248 manager_inf
.i_audio_nb
= ReadByte( p_ifo
, pi_buffer
, &p_current
);
249 //fprintf( stderr, "vmgi audio nb : %d\n", manager_inf.i_audio_nb );
250 for( i
=0 ; i
< 8 ; i
++ )
252 i_temp
= ReadQuad( p_ifo
, pi_buffer
, &p_current
);
254 DumpBits( p_ifo
, pi_buffer
, &p_current
, 17 );
255 manager_inf
.i_spu_nb
= ReadByte( p_ifo
, pi_buffer
, &p_current
);
256 //fprintf( stderr, "vmgi subpic nb : %d\n", manager_inf.i_spu_nb );
257 for( i
=0 ; i
< manager_inf
.i_spu_nb
; i
++ )
259 ReadBits( p_ifo
, pi_buffer
, &p_current
, (u8
*)(&i_temp
), 6 );
260 /* FIXME : take care of endianness */
264 * read first play title.
266 if( ReadTitle( p_ifo
, &p_ifo
->vmg
.title
, p_ifo
->i_off
+
267 manager_inf
.i_first_play_title_start_byte
) < 0 )
273 * fills the title information structure.
275 #define title_inf p_ifo->vmg.title_inf
276 if( manager_inf
.i_title_inf_start_sector
)
278 p_current
= FillBuffer( p_ifo
, pi_buffer
, p_ifo
->i_off
+
279 manager_inf
.i_title_inf_start_sector
*DVD_LB_SIZE
);
280 //fprintf( stderr, "title inf %lld\n", p_ifo->i_pos );
282 title_inf
.i_title_nb
= ReadWord( p_ifo
, pi_buffer
, &p_current
);
283 //fprintf( stderr, "title_inf: TTU nb %d\n", title_inf.i_title_nb );
284 DumpBits( p_ifo
, pi_buffer
, &p_current
, 2 );
285 title_inf
.i_end_byte
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
287 /* parsing of title attributes */
288 title_inf
.p_attr
= malloc( title_inf
.i_title_nb
*sizeof(title_attr_t
) );
289 if( title_inf
.p_attr
== NULL
)
291 intf_ErrMsg( "ifo error: out of memory in IfoInit" );
295 for( i
= 0 ; i
< title_inf
.i_title_nb
; i
++ )
297 title_inf
.p_attr
[i
].i_play_type
= ReadByte( p_ifo
, pi_buffer
, &p_current
);
298 title_inf
.p_attr
[i
].i_angle_nb
= ReadByte( p_ifo
, pi_buffer
, &p_current
);
299 title_inf
.p_attr
[i
].i_chapter_nb
= ReadWord( p_ifo
, pi_buffer
, &p_current
);
300 title_inf
.p_attr
[i
].i_parental_id
= ReadWord( p_ifo
, pi_buffer
, &p_current
);
301 title_inf
.p_attr
[i
].i_title_set_num
= ReadByte( p_ifo
, pi_buffer
, &p_current
);
302 title_inf
.p_attr
[i
].i_title_num
= ReadByte( p_ifo
, pi_buffer
, &p_current
);
303 title_inf
.p_attr
[i
].i_start_sector
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
304 //fprintf( stderr, "title_inf: %d %d %d\n",title_inf.p_attr[i].i_chapter_nb ,title_inf.p_attr[i].i_title_set_num,title_inf.p_attr[i].i_title_num );
309 title_inf
.p_attr
= NULL
;
314 * fills the title unit structure.
316 if( manager_inf
.i_title_unit_start_sector
)
318 if( ReadTitleUnit( p_ifo
, &p_ifo
->vmg
.title_unit
, p_ifo
->i_off
+
319 manager_inf
.i_title_unit_start_sector
*DVD_LB_SIZE
) < 0 )
326 * fills the structure about parental information.
328 #define parental p_ifo->vmg.parental_inf
329 if( manager_inf
.i_parental_inf_start_sector
)
331 p_current
= FillBuffer( p_ifo
, pi_buffer
, p_ifo
->i_off
+
332 manager_inf
.i_parental_inf_start_sector
*DVD_LB_SIZE
);
333 i_start
= p_ifo
->i_pos
;
335 //fprintf( stderr, "PTL\n" );
337 parental
.i_country_nb
= ReadWord( p_ifo
, pi_buffer
, &p_current
);
338 parental
.i_vts_nb
= ReadWord( p_ifo
, pi_buffer
, &p_current
);
339 parental
.i_end_byte
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
341 parental
.p_parental_desc
= malloc( parental
.i_country_nb
*
342 sizeof(parental_desc_t
) );
343 if( parental
.p_parental_desc
== NULL
)
345 intf_ErrMsg( "ifo error: out of memory in IfoInit" );
349 for( i
= 0 ; i
< parental
.i_country_nb
; i
++ )
351 ReadBits( p_ifo
, pi_buffer
, &p_current
,
352 parental
.p_parental_desc
[i
].ps_country_code
, 2 );
353 DumpBits( p_ifo
, pi_buffer
, &p_current
, 2 );
354 parental
.p_parental_desc
[i
].i_parental_mask_start_byte
=
355 ReadWord( p_ifo
, pi_buffer
, &p_current
);
356 DumpBits( p_ifo
, pi_buffer
, &p_current
, 2 );
359 parental
.p_parental_mask
= malloc( parental
.i_country_nb
*
360 sizeof(parental_mask_t
) );
361 if( parental
.p_parental_mask
== NULL
)
363 intf_ErrMsg( "ifo erro: out of memory in IfoInit" );
367 for( i
= 0 ; i
< parental
.i_country_nb
; i
++ )
369 p_current
= FillBuffer( p_ifo
, pi_buffer
, i_start
+
370 parental
.p_parental_desc
[i
].i_parental_mask_start_byte
);
371 for( j
= 0 ; j
< 8 ; j
++ )
373 parental
.p_parental_mask
[i
].ppi_mask
[j
] =
374 malloc( ( parental
.i_vts_nb
+ 1 ) *sizeof(u16
) );
375 if( parental
.p_parental_mask
[i
].ppi_mask
[j
] == NULL
)
377 intf_ErrMsg( "ifo error: out of memory in IfoInit" );
380 for( k
= 0 ; k
< parental
.i_vts_nb
+ 1 ; k
++ )
382 parental
.p_parental_mask
[i
].ppi_mask
[j
][k
] =
383 ReadWord( p_ifo
, pi_buffer
, &p_current
);
391 * information and attributes about for each vts.
393 #define vts_inf p_ifo->vmg.vts_inf
394 if( manager_inf
.i_vts_inf_start_sector
)
398 p_current
= FillBuffer( p_ifo
, pi_buffer
, p_ifo
->i_off
+
399 manager_inf
.i_vts_inf_start_sector
*DVD_LB_SIZE
);
400 i_start
= p_ifo
->i_pos
;
402 //fprintf( stderr, "VTS ATTR\n" );
404 vts_inf
.i_vts_nb
= ReadWord( p_ifo
, pi_buffer
, &p_current
);;
405 //fprintf( stderr, "VTS ATTR Nb: %d\n", vts_inf.i_vts_nb );
406 DumpBits( p_ifo
, pi_buffer
, &p_current
, 2 );
407 vts_inf
.i_end_byte
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
408 vts_inf
.pi_vts_attr_start_byte
=
409 malloc( vts_inf
.i_vts_nb
*sizeof(u32
) );
410 if( vts_inf
.pi_vts_attr_start_byte
== NULL
)
412 intf_ErrMsg( "ifo error: out of memory in IfoInit" );
416 for( i
= 0 ; i
< vts_inf
.i_vts_nb
; i
++ )
418 vts_inf
.pi_vts_attr_start_byte
[i
] = ReadDouble( p_ifo
, pi_buffer
, &p_current
);
421 vts_inf
.p_vts_attr
= malloc( vts_inf
.i_vts_nb
*sizeof(vts_attr_t
) );
422 if( vts_inf
.p_vts_attr
== NULL
)
424 intf_ErrMsg( "ifo erro: out of memory in IfoInit" );
428 for( i
= 0 ; i
< vts_inf
.i_vts_nb
; i
++ )
430 p_current
= FillBuffer( p_ifo
, pi_buffer
, i_start
+
431 vts_inf
.pi_vts_attr_start_byte
[i
] );
432 vts_inf
.p_vts_attr
[i
].i_end_byte
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
433 vts_inf
.p_vts_attr
[i
].i_cat_app_type
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
434 // GETS( &vts_inf.p_vts_attr[i].vts_menu_video_attr );
435 DumpBits( p_ifo
, pi_buffer
, &p_current
, 2 );
436 DumpBits( p_ifo
, pi_buffer
, &p_current
, 1 );
437 vts_inf
.p_vts_attr
[i
].i_vts_menu_audio_nb
= ReadByte( p_ifo
, pi_buffer
, &p_current
);
438 //fprintf( stderr, "m audio nb : %d\n", vts_inf.p_vts_attr[i].i_vts_menu_audio_nb );
439 for( j
= 0 ; j
< 8 ; j
++ )
441 i_temp
= ReadQuad( p_ifo
, pi_buffer
, &p_current
);;
443 DumpBits( p_ifo
, pi_buffer
, &p_current
, 17 );
444 vts_inf
.p_vts_attr
[i
].i_vts_menu_spu_nb
= ReadByte( p_ifo
, pi_buffer
, &p_current
);
445 //fprintf( stderr, "m subp nb : %d\n", vts_inf.p_vts_attr[i].i_vts_menu_spu_nb );
446 for( j
= 0 ; j
< 28 ; j
++ )
448 ReadBits( p_ifo
, pi_buffer
, &p_current
, (u8
*)(&i_temp
), 6 );
449 /* FIXME : Fix endianness issue here */
451 DumpBits( p_ifo
, pi_buffer
, &p_current
, 2 );
452 // GETS( &vts_inf.p_vts_attr[i].vtstt_video_vts_inf );
453 DumpBits( p_ifo
, pi_buffer
, &p_current
, 2 );
454 DumpBits( p_ifo
, pi_buffer
, &p_current
, 1 );
455 vts_inf
.p_vts_attr
[i
].i_vts_title_audio_nb
=
456 ReadDouble( p_ifo
, pi_buffer
, &p_current
);
457 //fprintf( stderr, "tt audio nb : %d\n", vts_inf.p_vts_attr[i].i_vts_title_audio_nb );
458 for( j
= 0 ; j
< 8 ; j
++ )
460 i_temp
= ReadQuad( p_ifo
, pi_buffer
, &p_current
);;
462 DumpBits( p_ifo
, pi_buffer
, &p_current
, 17 );
463 vts_inf
.p_vts_attr
[i
].i_vts_title_spu_nb
= ReadByte( p_ifo
, pi_buffer
, &p_current
);
464 //fprintf( stderr, "tt subp nb : %d\n", vts_inf.p_vts_attr[i].i_vts_title_spu_nb );
465 for( j
=0 ; j
<28/*vts_inf.p_vts_vts_inf[i].i_vtstt_subpic_nb*/ ; j
++ )
467 ReadBits( p_ifo
, pi_buffer
, &p_current
, (u8
*)(&i_temp
), 6 );
468 /* FIXME : Fix endianness issue here */
477 if( manager_inf
.i_cell_inf_start_sector
)
479 if( ReadCellInf( p_ifo
, &p_ifo
->vmg
.cell_inf
, p_ifo
->i_off
+
480 manager_inf
.i_cell_inf_start_sector
*DVD_LB_SIZE
) < 0 )
487 * global vob unit map.
489 if( manager_inf
.i_vobu_map_start_sector
)
491 if( ReadVobuMap( p_ifo
, &p_ifo
->vmg
.vobu_map
, p_ifo
->i_off
+
492 manager_inf
.i_vobu_map_start_sector
*DVD_LB_SIZE
) < 0 )
499 p_ifo
->vts
.b_initialized
= 0;
501 intf_WarnMsg( 2, "ifo info: vmg initialized" );
506 /*****************************************************************************
507 * IfoTitleSet: Parse vts*.ifo files to fill the Video Title Set structure.
508 *****************************************************************************/
509 int IfoTitleSet( ifo_t
* p_ifo
)
511 u8 pi_buffer
[DVD_LB_SIZE
];
519 if( p_ifo
->vts
.b_initialized
)
521 FreeTitleSet( &p_ifo
->vts
);
525 (off_t
)( p_ifo
->vmg
.title_inf
.p_attr
[p_ifo
->i_title
-1].i_start_sector
)
529 //fprintf(stderr, "offset: %lld\n" , i_off );
531 p_current
= FillBuffer( p_ifo
, pi_buffer
, i_off
);
532 //i_start = p_ifo->i_pos;
533 p_ifo
->vts
.i_pos
= p_ifo
->i_pos
;
535 #define manager_inf p_ifo->vts.manager_inf
537 * reads manager information
539 //fprintf( stderr, "VTSI\n" );
541 ReadBits( p_ifo
, pi_buffer
, &p_current
, manager_inf
.psz_id
, 12 );
542 manager_inf
.psz_id
[12] = '\0';
543 manager_inf
.i_end_sector
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
544 DumpBits( p_ifo
, pi_buffer
, &p_current
, 12 );
545 manager_inf
.i_inf_end_sector
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
546 DumpBits( p_ifo
, pi_buffer
, &p_current
, 1 );
547 manager_inf
.i_spec_ver
= ReadByte( p_ifo
, pi_buffer
, &p_current
);
548 manager_inf
.i_cat
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
549 DumpBits( p_ifo
, pi_buffer
, &p_current
, 90 );
550 manager_inf
.i_inf_end_byte
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
551 DumpBits( p_ifo
, pi_buffer
, &p_current
, 60 );
552 manager_inf
.i_menu_vob_start_sector
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
553 manager_inf
.i_title_vob_start_sector
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
554 manager_inf
.i_title_inf_start_sector
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
555 manager_inf
.i_title_unit_start_sector
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
556 manager_inf
.i_menu_unit_start_sector
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
557 manager_inf
.i_time_inf_start_sector
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
558 manager_inf
.i_menu_cell_inf_start_sector
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
559 manager_inf
.i_menu_vobu_map_start_sector
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
560 manager_inf
.i_cell_inf_start_sector
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
561 manager_inf
.i_vobu_map_start_sector
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
562 DumpBits( p_ifo
, pi_buffer
, &p_current
, 24 );
563 // GETS( &manager_inf.m_video_atrt );
564 DumpBits( p_ifo
, pi_buffer
, &p_current
, 2 );
565 DumpBits( p_ifo
, pi_buffer
, &p_current
, 1 );
566 manager_inf
.i_menu_audio_nb
= ReadByte( p_ifo
, pi_buffer
, &p_current
);
567 for( i
= 0 ; i
< 8 ; i
++ )
569 i_temp
= ReadQuad( p_ifo
, pi_buffer
, &p_current
);
571 DumpBits( p_ifo
, pi_buffer
, &p_current
, 17 );
572 manager_inf
.i_menu_spu_nb
= ReadByte( p_ifo
, pi_buffer
, &p_current
);
573 for( i
= 0 ; i
< 28 ; i
++ )
575 ReadBits( p_ifo
, pi_buffer
, &p_current
, (u8
*)(&i_temp
), 6 );
576 /* FIXME : take care of endianness */
578 DumpBits( p_ifo
, pi_buffer
, &p_current
, 2 );
580 i_short
= ReadWord( p_ifo
, pi_buffer
, &p_current
);
582 manager_inf
.video_attr
.i_mode
= i_short
& 0x1;
584 manager_inf
.video_attr
.i_letterboxed
= i_short
& 0x1;
586 manager_inf
.video_attr
.i_source_res
= i_short
& 0x3;
588 manager_inf
.video_attr
.i_line21_2
= i_short
& 0x1;
590 manager_inf
.video_attr
.i_line21_1
= i_short
& 0x1;
592 manager_inf
.video_attr
.i_perm_displ
= i_short
& 0x3;
594 manager_inf
.video_attr
.i_ratio
= i_short
& 0x3;
596 manager_inf
.video_attr
.i_system
= i_short
& 0x3;
598 manager_inf
.video_attr
.i_compression
= i_short
& 0x3;
600 DumpBits( p_ifo
, pi_buffer
, &p_current
, 1 );
601 manager_inf
.i_audio_nb
= ReadByte( p_ifo
, pi_buffer
, &p_current
);
602 //fprintf( stderr, "vtsi audio nb : %d\n", manager_inf.i_audio_nb );
603 for( i
= 0 ; i
< 8 ; i
++ )
605 i_temp
= ReadQuad( p_ifo
, pi_buffer
, &p_current
);
606 //fprintf( stderr, "Audio %d: %llx\n", i, i_temp );
608 manager_inf
.p_audio_attr
[i
].i_bar
= i_temp
& 0xff;
610 manager_inf
.p_audio_attr
[i
].i_caption
= i_temp
& 0xff;
612 manager_inf
.p_audio_attr
[i
].i_foo
= i_temp
& 0xff;
614 manager_inf
.p_audio_attr
[i
].i_lang_code
= i_temp
& 0xffff;
616 manager_inf
.p_audio_attr
[i
].i_num_channels
= i_temp
& 0x7;
618 manager_inf
.p_audio_attr
[i
].i_test
= i_temp
& 0x1;
620 manager_inf
.p_audio_attr
[i
].i_sample_freq
= i_temp
& 0x3;
622 manager_inf
.p_audio_attr
[i
].i_quantization
= i_temp
& 0x3;
624 manager_inf
.p_audio_attr
[i
].i_appl_mode
= i_temp
& 0x3;
626 manager_inf
.p_audio_attr
[i
].i_type
= i_temp
& 0x3;
628 manager_inf
.p_audio_attr
[i
].i_multichannel_extension
= i_temp
& 0x1;
630 manager_inf
.p_audio_attr
[i
].i_coding_mode
= i_temp
& 0x7;
632 DumpBits( p_ifo
, pi_buffer
, &p_current
, 17 );
633 manager_inf
.i_spu_nb
= ReadByte( p_ifo
, pi_buffer
, &p_current
);
634 //fprintf( stderr, "vtsi subpic nb : %d\n", manager_inf.i_spu_nb );
635 for( i
=0 ; i
<manager_inf
.i_spu_nb
; i
++ )
637 ReadBits( p_ifo
, pi_buffer
, &p_current
, (u8
*)(&i_temp
), 6 );
638 i_temp
= hton64( i_temp
) >> 16;
639 //fprintf( stderr, "Subpic %d: %llx\n", i, i_temp );
640 manager_inf
.p_spu_attr
[i
].i_caption
= i_temp
& 0xff;
642 manager_inf
.p_spu_attr
[i
].i_foo
= i_temp
& 0xff;
644 manager_inf
.p_spu_attr
[i
].i_lang_code
= i_temp
& 0xffff;
646 manager_inf
.p_spu_attr
[i
].i_prefix
= i_temp
& 0xffff;
650 * reads title information: set of pointers to title
652 #define title_inf p_ifo->vts.title_inf
653 if( manager_inf
.i_title_inf_start_sector
)
655 p_current
= FillBuffer( p_ifo
, pi_buffer
, p_ifo
->vts
.i_pos
+
656 manager_inf
.i_title_inf_start_sector
*DVD_LB_SIZE
);
658 i_start
= p_ifo
->i_pos
;
660 //fprintf( stderr, "VTS PTR\n" );
662 title_inf
.i_title_nb
= ReadWord( p_ifo
, pi_buffer
, &p_current
);
663 //fprintf( stderr, "VTS title_inf nb: %d\n", title_inf.i_title_nb );
664 DumpBits( p_ifo
, pi_buffer
, &p_current
, 2 );
665 title_inf
.i_end_byte
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
667 title_inf
.pi_start_byte
= malloc( title_inf
.i_title_nb
*sizeof(u32
) );
668 if( title_inf
.pi_start_byte
== NULL
)
670 intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" );
674 for( i
= 0 ; i
< title_inf
.i_title_nb
; i
++ )
676 title_inf
.pi_start_byte
[i
] = ReadDouble( p_ifo
, pi_buffer
, &p_current
);
680 title_inf
.p_title_start
= malloc( title_inf
.i_title_nb
681 *sizeof(title_start_t
) );
682 if( title_inf
.p_title_start
== NULL
)
684 intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" );
688 for( i
= 0 ; i
< title_inf
.i_title_nb
; i
++ )
690 p_current
= FillBuffer( p_ifo
, pi_buffer
, i_start
+
691 title_inf
.pi_start_byte
[i
] );
693 title_inf
.p_title_start
[i
].i_title_id
=
694 ReadWord( p_ifo
, pi_buffer
, &p_current
);
695 title_inf
.p_title_start
[i
].i_chapter
= ReadWord( p_ifo
, pi_buffer
, &p_current
);
696 //fprintf( stderr, "VTS %d title_inf Pgc: %d Prg: %d\n", i,title_inf.p_title_start[i].i_program_chain_num, title_inf.p_title_start[i].i_program_num );
702 * menu unit information
704 if( manager_inf
.i_menu_unit_start_sector
)
706 if( ReadTitleUnit( p_ifo
, &p_ifo
->vts
.menu_unit
, p_ifo
->vts
.i_pos
+
707 manager_inf
.i_menu_unit_start_sector
*DVD_LB_SIZE
) < 0 )
714 * title unit information
716 if( manager_inf
.i_title_unit_start_sector
)
718 if( ReadUnitInf( p_ifo
, &p_ifo
->vts
.title_unit
, p_ifo
->vts
.i_pos
+
719 manager_inf
.i_title_unit_start_sector
*DVD_LB_SIZE
) < 0 )
726 * time map inforamtion
728 #define time_inf p_ifo->vts.time_inf
729 if( manager_inf
.i_time_inf_start_sector
)
731 u8 pi_buffer
[DVD_LB_SIZE
];
733 p_current
= FillBuffer( p_ifo
, pi_buffer
, p_ifo
->vts
.i_pos
+
734 manager_inf
.i_time_inf_start_sector
*DVD_LB_SIZE
);
736 //fprintf( stderr, "TMAP\n" );
738 time_inf
.i_nb
= ReadWord( p_ifo
, pi_buffer
, &p_current
);;
739 DumpBits( p_ifo
, pi_buffer
, &p_current
, 2 );
740 time_inf
.i_end_byte
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
742 time_inf
.pi_start_byte
= malloc( time_inf
.i_nb
*sizeof(u32
) );
743 if( time_inf
.pi_start_byte
== NULL
)
745 intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" );
749 for( i
= 0 ; i
< time_inf
.i_nb
; i
++ )
751 time_inf
.pi_start_byte
[i
] = ReadDouble( p_ifo
, pi_buffer
, &p_current
);
754 time_inf
.p_time_map
= malloc( time_inf
.i_nb
*sizeof(time_map_t
) );
755 if( time_inf
.p_time_map
== NULL
)
757 intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" );
761 for( i
= 0 ; i
< time_inf
.i_nb
; i
++ )
763 time_inf
.p_time_map
[i
].i_time_unit
= ReadByte( p_ifo
, pi_buffer
, &p_current
);
764 DumpBits( p_ifo
, pi_buffer
, &p_current
, 1 );
765 time_inf
.p_time_map
[i
].i_entry_nb
= ReadWord( p_ifo
, pi_buffer
, &p_current
);
767 time_inf
.p_time_map
[i
].pi_sector
=
768 malloc( time_inf
.p_time_map
[i
].i_entry_nb
*sizeof(u32
) );
769 if( time_inf
.p_time_map
[i
].pi_sector
== NULL
)
771 intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" );
775 for( j
= 0 ; j
< time_inf
.p_time_map
[i
].i_entry_nb
; j
++ )
777 time_inf
.p_time_map
[i
].pi_sector
[j
] = ReadDouble( p_ifo
, pi_buffer
, &p_current
);
783 if( manager_inf
.i_menu_cell_inf_start_sector
)
785 if( ReadCellInf( p_ifo
, &p_ifo
->vts
.menu_cell_inf
, p_ifo
->vts
.i_pos
+
786 manager_inf
.i_menu_cell_inf_start_sector
*DVD_LB_SIZE
) < 0 )
792 if( manager_inf
.i_menu_vobu_map_start_sector
)
794 if( ReadVobuMap( p_ifo
, &p_ifo
->vts
.menu_vobu_map
, p_ifo
->vts
.i_pos
+
795 manager_inf
.i_menu_vobu_map_start_sector
*DVD_LB_SIZE
) < 0 )
801 if( manager_inf
.i_cell_inf_start_sector
)
803 if( ReadCellInf( p_ifo
, &p_ifo
->vts
.cell_inf
, p_ifo
->vts
.i_pos
+
804 manager_inf
.i_cell_inf_start_sector
*DVD_LB_SIZE
) )
810 if( manager_inf
.i_vobu_map_start_sector
)
812 if( ReadVobuMap( p_ifo
, &p_ifo
->vts
.vobu_map
, p_ifo
->vts
.i_pos
+
813 manager_inf
.i_vobu_map_start_sector
*DVD_LB_SIZE
) )
820 intf_WarnMsg( 2, "ifo info: vts %d initialized",
821 p_ifo
->vmg
.title_inf
.p_attr
[p_ifo
->i_title
-1].i_title_set_num
);
823 p_ifo
->vts
.b_initialized
= 1;
828 /*****************************************************************************
829 * FreeTitleSet : free all structures allocated by IfoTitleSet
830 *****************************************************************************/
831 static int FreeTitleSet( vts_t
* p_vts
)
835 if( p_vts
->manager_inf
.i_vobu_map_start_sector
)
837 FreeVobuMap( &p_vts
->vobu_map
);
840 if( p_vts
->manager_inf
.i_cell_inf_start_sector
)
842 FreeCellInf( &p_vts
->cell_inf
);
845 if( p_vts
->manager_inf
.i_menu_vobu_map_start_sector
)
847 FreeVobuMap( &p_vts
->menu_vobu_map
);
850 if( p_vts
->manager_inf
.i_menu_cell_inf_start_sector
)
852 FreeCellInf( &p_vts
->menu_cell_inf
);
855 if( p_vts
->manager_inf
.i_time_inf_start_sector
)
857 for( i
= 0 ; i
< p_vts
->time_inf
.i_nb
; i
++ )
859 free( p_vts
->time_inf
.p_time_map
[i
].pi_sector
);
862 free( p_vts
->time_inf
.p_time_map
);
863 free( p_vts
->time_inf
.pi_start_byte
);
866 if( p_vts
->manager_inf
.i_title_unit_start_sector
)
868 FreeUnitInf( &p_vts
->title_unit
);
871 if( p_vts
->manager_inf
.i_menu_unit_start_sector
)
873 FreeTitleUnit( &p_vts
->menu_unit
);
876 if( p_vts
->manager_inf
.i_title_inf_start_sector
)
878 free( p_vts
->title_inf
.pi_start_byte
);
879 free( p_vts
->title_inf
.p_title_start
);
882 p_vts
->b_initialized
= 0;
887 /*****************************************************************************
888 * IfoDestroy : Frees all the memory allocated to ifo structures
889 *****************************************************************************/
890 void IfoDestroy( ifo_t
* p_ifo
)
894 FreeTitleSet( &p_ifo
->vts
);
896 if( p_ifo
->vmg
.manager_inf
.i_vobu_map_start_sector
)
898 FreeVobuMap( &p_ifo
->vmg
.vobu_map
);
901 if( p_ifo
->vmg
.manager_inf
.i_cell_inf_start_sector
)
903 FreeCellInf( &p_ifo
->vmg
.cell_inf
);
906 if( p_ifo
->vmg
.manager_inf
.i_vts_inf_start_sector
)
908 free( p_ifo
->vmg
.vts_inf
.p_vts_attr
);
909 free( p_ifo
->vmg
.vts_inf
.pi_vts_attr_start_byte
);
912 /* free parental information structures */
913 if( p_ifo
->vmg
.manager_inf
.i_parental_inf_start_sector
)
915 for( i
= 0 ; i
< p_ifo
->vmg
.parental_inf
.i_country_nb
; i
++ )
917 for( j
= 0 ; j
< 8 ; j
++ )
919 free( p_ifo
->vmg
.parental_inf
.p_parental_mask
[i
].ppi_mask
[j
] );
923 free( p_ifo
->vmg
.parental_inf
.p_parental_mask
);
924 free( p_ifo
->vmg
.parental_inf
.p_parental_desc
);
927 if( p_ifo
->vmg
.manager_inf
.i_title_unit_start_sector
)
929 FreeTitleUnit( &p_ifo
->vmg
.title_unit
);
932 if( p_ifo
->vmg
.manager_inf
.i_title_inf_start_sector
)
934 free( p_ifo
->vmg
.title_inf
.p_attr
);
937 FreeTitle( &p_ifo
->vmg
.title
);
944 * Function common to Video Manager and Video Title set Processing
947 /*****************************************************************************
948 * ReadTitle : Fills the title structure.
949 *****************************************************************************
950 * Titles are logical stream units that correspond to a whole inside the dvd.
951 * Several title can point to the same part of the physical DVD, and give
952 * map to different anglesfor instance.
953 *****************************************************************************/
954 static int ReadTitle( ifo_t
* p_ifo
, title_t
* p_title
, off_t i_pos
)
956 u8 pi_buffer
[DVD_LB_SIZE
];
963 p_current
= FillBuffer( p_ifo
, pi_buffer
, i_pos
);
965 i_start
= p_ifo
->i_pos
;
967 //fprintf( stderr, "PGC @ %lld\n",p_ifo->i_pos );
969 DumpBits( p_ifo
, pi_buffer
, &p_current
, 2);
970 p_title
->i_chapter_nb
= ReadByte( p_ifo
, pi_buffer
, &p_current
);
971 p_title
->i_cell_nb
= ReadByte( p_ifo
, pi_buffer
, &p_current
);
972 //fprintf( stderr, "title: Prg: %d Cell: %d\n",p_title->i_chapter_nb,p_title->i_cell_nb );
973 p_title
->i_play_time
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
974 p_title
->i_prohibited_user_op
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
975 for( i
= 0 ; i
< 8 ; i
++ )
977 i_audio
= ReadWord( p_ifo
, pi_buffer
, &p_current
);
978 p_title
->pi_audio_status
[i
].i_foo
= i_audio
& 0xff;
980 p_title
->pi_audio_status
[i
].i_position
= i_audio
& 0x07;
982 p_title
->pi_audio_status
[i
].i_available
= i_audio
;
984 for( i
= 0 ; i
< 32 ; i
++ )
986 i_spu
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
987 p_title
->pi_spu_status
[i
].i_position_pan
= i_spu
& 0x1f;
989 p_title
->pi_spu_status
[i
].i_position_letter
= i_spu
& 0x1f;
991 p_title
->pi_spu_status
[i
].i_position_wide
= i_spu
& 0x1f;
993 p_title
->pi_spu_status
[i
].i_position_43
= i_spu
& 0x1f;
995 p_title
->pi_spu_status
[i
].i_available
= i_spu
;
997 p_title
->i_next_title_num
= ReadWord( p_ifo
, pi_buffer
, &p_current
);
998 p_title
->i_prev_title_num
= ReadWord( p_ifo
, pi_buffer
, &p_current
);
999 p_title
->i_go_up_title_num
= ReadWord( p_ifo
, pi_buffer
, &p_current
);
1000 //fprintf( stderr, "title: Prev: %d Next: %d Up: %d\n",pgc.i_prev_pgc_nb ,pgc.i_next_pgc_nb, pgc.i_goup_pgc_nb );
1001 p_title
->i_still_time
= ReadByte( p_ifo
, pi_buffer
, &p_current
);
1002 p_title
->i_play_mode
= ReadByte( p_ifo
, pi_buffer
, &p_current
);
1003 for( i
= 0 ; i
< 16 ; i
++ )
1005 p_title
->pi_yuv_color
[i
] = ReadDouble( p_ifo
, pi_buffer
, &p_current
);
1006 /* FIXME : We have to erase the extra bit */
1008 p_title
->i_command_start_byte
= ReadWord( p_ifo
, pi_buffer
, &p_current
);
1009 p_title
->i_chapter_map_start_byte
= ReadWord( p_ifo
, pi_buffer
, &p_current
);
1010 p_title
->i_cell_play_start_byte
= ReadWord( p_ifo
, pi_buffer
, &p_current
);
1011 p_title
->i_cell_pos_start_byte
= ReadWord( p_ifo
, pi_buffer
, &p_current
);
1013 /* parsing of command_t */
1014 if( p_title
->i_command_start_byte
)
1016 p_current
= FillBuffer( p_ifo
, pi_buffer
,
1017 i_start
+ p_title
->i_command_start_byte
);
1020 p_title
->command
.i_pre_command_nb
= ReadWord( p_ifo
, pi_buffer
, &p_current
);
1021 p_title
->command
.i_post_command_nb
= ReadWord( p_ifo
, pi_buffer
, &p_current
);
1022 p_title
->command
.i_cell_command_nb
= ReadWord( p_ifo
, pi_buffer
, &p_current
);
1023 DumpBits( p_ifo
, pi_buffer
, &p_current
, 2 );
1025 /* pre-title commands */
1026 if( p_title
->command
.i_pre_command_nb
)
1028 p_title
->command
.p_pre_command
=
1029 malloc( p_title
->command
.i_pre_command_nb
1030 *sizeof(command_desc_t
) );
1032 if( p_title
->command
.p_pre_command
== NULL
)
1034 intf_ErrMsg( "ifo error: out of memory in ReadTitle" );
1038 for( i
= 0 ; i
< p_title
->command
.i_pre_command_nb
; i
++ )
1040 p_title
->command
.p_pre_command
[i
] = ReadQuad( p_ifo
, pi_buffer
, &p_current
);
1045 p_title
->command
.p_pre_command
= NULL
;
1048 /* post-title commands */
1049 if( p_title
->command
.i_post_command_nb
)
1051 p_title
->command
.p_post_command
=
1052 malloc( p_title
->command
.i_post_command_nb
1053 *sizeof(command_desc_t
) );
1055 if( p_title
->command
.p_post_command
== NULL
)
1057 intf_ErrMsg( "ifo error: out of memory in ReadTitle" );
1061 for( i
=0 ; i
<p_title
->command
.i_post_command_nb
; i
++ )
1063 p_title
->command
.p_post_command
[i
] = ReadQuad( p_ifo
, pi_buffer
, &p_current
);
1068 p_title
->command
.p_post_command
= NULL
;
1072 if( p_title
->command
.i_cell_command_nb
)
1074 p_title
->command
.p_cell_command
=
1075 malloc( p_title
->command
.i_cell_command_nb
1076 *sizeof(command_desc_t
) );
1078 if( p_title
->command
.p_cell_command
== NULL
)
1080 intf_ErrMsg( "ifo error: out of memory in ReadTitle" );
1084 for( i
=0 ; i
<p_title
->command
.i_cell_command_nb
; i
++ )
1086 p_title
->command
.p_cell_command
[i
] = ReadQuad( p_ifo
, pi_buffer
, &p_current
);
1091 p_title
->command
.p_cell_command
= NULL
;
1095 /* parsing of chapter_map_t: it gives the entry cell for each chapter */
1096 if( p_title
->i_chapter_map_start_byte
)
1098 p_ifo
->i_pos
= lseek( p_ifo
->i_fd
,
1099 i_start
+ p_title
->i_chapter_map_start_byte
,
1102 p_title
->chapter_map
.pi_start_cell
=
1103 malloc( p_title
->i_chapter_nb
*sizeof(chapter_map_t
) );
1105 if( p_title
->chapter_map
.pi_start_cell
== NULL
)
1107 intf_ErrMsg( "ifo error: out of memory in Read Title" );
1111 ReadBits( p_ifo
, pi_buffer
, &p_current
, p_title
->chapter_map
.pi_start_cell
,
1112 p_title
->i_chapter_nb
);
1116 p_title
->chapter_map
.pi_start_cell
= NULL
;
1119 /* parsing of cell_play_t */
1120 if( p_title
->i_cell_play_start_byte
)
1122 p_current
= FillBuffer( p_ifo
, pi_buffer
,
1123 i_start
+ p_title
->i_cell_play_start_byte
);
1125 p_title
->p_cell_play
= malloc( p_title
->i_cell_nb
1126 *sizeof(cell_play_t
) );
1128 if( p_title
->p_cell_play
== NULL
)
1130 intf_ErrMsg( "ifo error: out of memory in ReadTitle" );
1134 for( i
= 0 ; i
< p_title
->i_cell_nb
; i
++ )
1136 p_title
->p_cell_play
[i
].i_category
= ReadWord( p_ifo
, pi_buffer
, &p_current
);
1137 p_title
->p_cell_play
[i
].i_still_time
= ReadByte( p_ifo
, pi_buffer
, &p_current
);
1138 p_title
->p_cell_play
[i
].i_command_nb
= ReadByte( p_ifo
, pi_buffer
, &p_current
);
1139 p_title
->p_cell_play
[i
].i_play_time
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
1140 p_title
->p_cell_play
[i
].i_start_sector
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
1141 p_title
->p_cell_play
[i
].i_first_ilvu_vobu_esector
=
1142 ReadDouble( p_ifo
, pi_buffer
, &p_current
);
1143 p_title
->p_cell_play
[i
].i_last_vobu_start_sector
=
1144 ReadDouble( p_ifo
, pi_buffer
, &p_current
);
1145 p_title
->p_cell_play
[i
].i_end_sector
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
1149 /* Parsing of cell_pos_t */
1150 if( p_title
->i_cell_pos_start_byte
)
1152 p_current
= FillBuffer( p_ifo
, pi_buffer
,
1153 i_start
+ p_title
->i_cell_pos_start_byte
);
1155 p_title
->p_cell_pos
= malloc( p_title
->i_cell_nb
1156 *sizeof(cell_pos_t
) );
1158 if( p_title
->p_cell_pos
== NULL
)
1160 intf_ErrMsg( "ifo error: out of memory" );
1164 for( i
= 0 ; i
< p_title
->i_cell_nb
; i
++ )
1166 p_title
->p_cell_pos
[i
].i_vob_id
= ReadWord( p_ifo
, pi_buffer
, &p_current
);
1167 DumpBits( p_ifo
, pi_buffer
, &p_current
, 1 );
1168 p_title
->p_cell_pos
[i
].i_cell_id
= ReadByte( p_ifo
, pi_buffer
, &p_current
);
1175 /*****************************************************************************
1176 * FreeTitle: frees alla structure allocated by a call to ReadTitle
1177 *****************************************************************************/
1178 static int FreeTitle( title_t
* p_title
)
1180 if( p_title
->i_command_start_byte
)
1182 if( p_title
->command
.i_pre_command_nb
)
1184 free( p_title
->command
.p_pre_command
);
1187 if( p_title
->command
.i_post_command_nb
)
1189 free( p_title
->command
.p_post_command
);
1192 if( p_title
->command
.i_cell_command_nb
)
1194 free( p_title
->command
.p_cell_command
);
1197 if( p_title
->i_chapter_map_start_byte
)
1199 free( p_title
->chapter_map
.pi_start_cell
);
1202 if( p_title
->i_cell_play_start_byte
)
1204 free( p_title
->p_cell_play
);
1207 if( p_title
->i_cell_pos_start_byte
)
1209 free( p_title
->p_cell_pos
);
1216 /*****************************************************************************
1217 * ReadUnitInf : Fills Menu Language Unit Table/ PGC Info Table
1218 *****************************************************************************/
1219 static int ReadUnitInf( ifo_t
* p_ifo
, unit_inf_t
* p_unit_inf
, off_t i_pos
)
1221 u8 pi_buffer
[DVD_LB_SIZE
];
1226 p_current
= FillBuffer( p_ifo
, pi_buffer
, i_pos
);
1228 i_start
= p_ifo
->i_pos
;
1229 //fprintf( stderr, "Unit\n" );
1231 p_unit_inf
->i_title_nb
= ReadWord( p_ifo
, pi_buffer
, &p_current
);
1232 //fprintf( stderr, "Unit nb: %d\n", p_unit_inf->i_title_nb );
1233 DumpBits( p_ifo
, pi_buffer
, &p_current
, 2 );
1234 p_unit_inf
->i_end_byte
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
1236 p_unit_inf
->p_title
=
1237 malloc( p_unit_inf
->i_title_nb
*sizeof(unit_title_t
) );
1238 if( p_unit_inf
->p_title
== NULL
)
1240 intf_ErrMsg( "ifo error: out of memory in ReadUnit" );
1244 for( i
= 0 ; i
< p_unit_inf
->i_title_nb
; i
++ )
1246 p_unit_inf
->p_title
[i
].i_category_mask
= ReadByte( p_ifo
, pi_buffer
, &p_current
);
1247 p_unit_inf
->p_title
[i
].i_category
= ReadByte( p_ifo
, pi_buffer
, &p_current
);
1248 //fprintf( stderr, "cat mask %d: %x cat %x\n", i, p_unit_inf->p_title[i].i_category_mask, p_unit_inf->p_title[i].i_category );
1249 p_unit_inf
->p_title
[i
].i_parental_mask
= ReadWord( p_ifo
, pi_buffer
, &p_current
);
1250 p_unit_inf
->p_title
[i
].i_title_start_byte
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
1253 for( i
= 0 ; i
< p_unit_inf
->i_title_nb
; i
++ )
1255 //fprintf( stderr, "Unit: PGC %d @ %lld\n", i, p_ifo->i_pos );
1256 ReadTitle( p_ifo
, &p_unit_inf
->p_title
[i
].title
, i_start
+
1257 p_unit_inf
->p_title
[i
].i_title_start_byte
);
1263 /*****************************************************************************
1264 * FreeUnitInf : frees a structure allocated by ReadUnit
1265 *****************************************************************************/
1266 static int FreeUnitInf( unit_inf_t
* p_unit_inf
)
1268 if( p_unit_inf
->p_title
!= NULL
)
1270 free( p_unit_inf
->p_title
);
1277 /*****************************************************************************
1278 * ReadTitleUnit: Fills the Title Unit structure.
1279 *****************************************************************************/
1280 static int ReadTitleUnit( ifo_t
* p_ifo
, title_unit_t
* p_title_unit
,
1283 u8 pi_buffer
[DVD_LB_SIZE
];
1288 p_current
= FillBuffer( p_ifo
, pi_buffer
, i_pos
);
1289 i_start
= p_ifo
->i_pos
;
1290 //fprintf( stderr, "Unit Table\n" );
1292 p_title_unit
->i_unit_nb
= ReadWord( p_ifo
, pi_buffer
, &p_current
);
1293 DumpBits( p_ifo
, pi_buffer
, &p_current
, 2 );
1294 p_title_unit
->i_end_byte
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
1296 //fprintf(stderr, "Unit: nb %d end %d\n", p_title_unit->i_unit_nb, p_title_unit->i_end_byte );
1298 p_title_unit
->p_unit
= malloc( p_title_unit
->i_unit_nb
*sizeof(unit_t
) );
1299 if( p_title_unit
->p_unit
== NULL
)
1301 intf_ErrMsg( "ifo error: out of memory in ReadTitleUnit" );
1305 for( i
= 0 ; i
< p_title_unit
->i_unit_nb
; i
++ )
1307 //ReadBits( p_ifo, pi_buffer, &p_current, p_title_unit->p_unit[i].ps_lang_code, 2 );
1308 p_title_unit
->p_unit
[i
].i_lang_code
= ReadWord( p_ifo
, pi_buffer
, &p_current
);
1309 //fprintf( stderr, "lang %d %x\n", i,p_title_unit->p_unit[i].i_lang_code );
1310 DumpBits( p_ifo
, pi_buffer
, &p_current
, 1 );
1311 p_title_unit
->p_unit
[i
].i_existence_mask
= ReadByte( p_ifo
, pi_buffer
, &p_current
);
1312 p_title_unit
->p_unit
[i
].i_unit_inf_start_byte
=
1313 ReadDouble( p_ifo
, pi_buffer
, &p_current
);
1316 p_title_unit
->p_unit_inf
=
1317 malloc( p_title_unit
->i_unit_nb
*sizeof(unit_inf_t
) );
1318 if( p_title_unit
->p_unit_inf
== NULL
)
1320 intf_ErrMsg( "ifo error: out of memory in ReadTitleUnit" );
1324 for( i
= 0 ; i
< p_title_unit
->i_unit_nb
; i
++ )
1326 ReadUnitInf( p_ifo
, &p_title_unit
->p_unit_inf
[i
], i_start
+
1327 p_title_unit
->p_unit
[i
].i_unit_inf_start_byte
);
1333 /*****************************************************************************
1334 * FreeTitleUnit: frees a structure allocateed by ReadTitleUnit
1335 *****************************************************************************/
1336 static int FreeTitleUnit( title_unit_t
* p_title_unit
)
1340 if( p_title_unit
->p_unit_inf
!= NULL
)
1342 for( i
= 0 ; i
< p_title_unit
->i_unit_nb
; i
++ )
1344 FreeUnitInf( &p_title_unit
->p_unit_inf
[i
] );
1347 free( p_title_unit
->p_unit_inf
);
1353 /*****************************************************************************
1354 * ReadCellInf : Fills the Cell Information structure.
1355 *****************************************************************************/
1356 static int ReadCellInf( ifo_t
* p_ifo
, cell_inf_t
* p_cell_inf
, off_t i_pos
)
1358 u8 pi_buffer
[DVD_LB_SIZE
];
1363 p_current
= FillBuffer( p_ifo
, pi_buffer
, i_pos
);
1364 i_start
= p_ifo
->i_pos
;
1365 //fprintf( stderr, "CELL ADD\n" );
1367 p_cell_inf
->i_vob_nb
= ReadWord( p_ifo
, pi_buffer
, &p_current
);
1368 DumpBits( p_ifo
, pi_buffer
, &p_current
, 2 );
1369 p_cell_inf
->i_end_byte
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
1371 p_cell_inf
->i_cell_nb
= (p_cell_inf
->i_end_byte
/* - 7*/) / sizeof(cell_map_t
);
1373 //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 );
1375 p_cell_inf
->p_cell_map
=
1376 malloc( p_cell_inf
->i_cell_nb
*sizeof(cell_map_t
) );
1377 if( p_cell_inf
->p_cell_map
== NULL
)
1379 intf_ErrMsg( "ifo error: out of memory in ReadCellInf" );
1383 for( i
= 0 ; i
< p_cell_inf
->i_cell_nb
; i
++ )
1385 p_cell_inf
->p_cell_map
[i
].i_vob_id
= ReadWord( p_ifo
, pi_buffer
, &p_current
);
1386 p_cell_inf
->p_cell_map
[i
].i_cell_id
= ReadByte( p_ifo
, pi_buffer
, &p_current
);
1387 DumpBits( p_ifo
, pi_buffer
, &p_current
, 1 );
1388 p_cell_inf
->p_cell_map
[i
].i_start_sector
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
1389 // fprintf(stderr, "sector[%d] %d (%lld)\n", i,ntohl(*(u32*)(p_current)), p_ifo->i_pos);
1390 p_cell_inf
->p_cell_map
[i
].i_end_sector
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
1396 /*****************************************************************************
1397 * FreeCellInf : frees structures allocated by ReadCellInf
1398 *****************************************************************************/
1399 static int FreeCellInf( cell_inf_t
* p_cell_inf
)
1401 free( p_cell_inf
->p_cell_map
);
1406 /*****************************************************************************
1407 * ReadVobuMap : Fills the VOBU Map structure.
1408 *****************************************************************************/
1409 static int ReadVobuMap( ifo_t
* p_ifo
, vobu_map_t
* p_vobu_map
, off_t i_pos
)
1411 u8 pi_buffer
[DVD_LB_SIZE
];
1416 p_current
= FillBuffer( p_ifo
, pi_buffer
, i_pos
);
1417 i_start
= p_ifo
->i_pos
;
1418 //fprintf( stderr, "VOBU ADMAP\n" );
1420 p_vobu_map
->i_end_byte
= ReadDouble( p_ifo
, pi_buffer
, &p_current
);
1421 i_max
= ( i_start
+ p_vobu_map
->i_end_byte
+ 1 - p_ifo
->i_pos
)
1424 p_vobu_map
->pi_vobu_start_sector
= malloc( i_max
*sizeof(u32
) );
1425 if( p_vobu_map
->pi_vobu_start_sector
== NULL
)
1427 intf_ErrMsg( "ifo error: out of memory in ReadVobuMap" );
1431 for( i
= 0 ; i
< i_max
; i
++ )
1433 p_vobu_map
->pi_vobu_start_sector
[i
] = ReadDouble( p_ifo
, pi_buffer
, &p_current
);
1439 /*****************************************************************************
1440 * FreeVobuMap: frees structures allocated by ReadVobuMap
1441 *****************************************************************************/
1442 static int FreeVobuMap( vobu_map_t
* p_vobu_map
)
1444 free( p_vobu_map
->pi_vobu_start_sector
);
1450 * IFO virtual machine : a set of commands that give the
1451 * interactive behaviour of the dvd
1455 #define OP_VAL_16(i) (ntoh16( com.data.pi_16[i]))
1456 #define OP_VAL_8(i) ((com.data.pi_8[i]))
1458 static char ifo_reg
[][80]=
1460 "Menu_Language_Code",
1462 "SubPicture_Stream_#",
1468 "Highlighted_Button_#",
1471 "Karaoke_audio_mixing_mode",
1472 "Parental_mgmt_country_code",
1476 "Audio_language_code_setting",
1477 "Audio_language_extension_code",
1478 "SPU_language_code_setting",
1479 "SPU_language_extension_code",
1480 "?Player_Regional_Code",
1486 static char * IfoMath( char val
)
1488 static char math_op
[][10] =
1508 return (char *) math_op
[val
& 0x0f];
1512 char ifo_cmp
[][10] =
1524 char ifo_parental
[][10] =
1536 char ifo_menu_id
[][80] =
1548 char * IfoMenuName( char index
)
1550 return ifo_menu_id
[index
&0x07];
1553 static void IfoRegister( u16 i_data
, u8 i_direct
)
1557 if( 0/*isalpha( i_data >> 8 & 0xff )*/ )
1559 printf("'%c%c'", i_data
>>8&0xff, i_data
&0xff);
1563 printf("0x%02x", i_data
);
1578 printf("s[%s]", ifo_reg
[i_data
]);
1591 printf("r[0x%02x]", i_data
);
1597 static void IfoAdvanced( u8
*pi_code
)
1599 u8 i_cmd
= pi_code
[0];
1605 printf( " Highlight button %d; ", pi_code
[1]>>2 );
1610 printf( " Illegal " );
1615 printf( "ReSuME %d", pi_code
[7] );
1617 else if( ( i_cmd
& 0x06) == 0x02 )
1619 printf ("Link to %s cell ", ( i_cmd
& 0x01 ) ? "prev" : "next");
1623 printf( "advanced (0x%02x) ", i_cmd
);
1628 static void IfoJmp( ifo_command_t com
)
1633 switch( com
.i_sub_cmd
)
1639 printf( "VTS 0x%02x", OP_VAL_8(3) );
1642 printf( "This VTS Title 0x%02x", OP_VAL_8(3) );
1645 printf( "This VTS Title 0x%02x Part 0x%04x",
1647 OP_VAL_8(0)<<8|OP_VAL_8(1));
1651 printf ("in SystemSpace ");
1652 switch (OP_VAL_8(3)>>4) {
1654 printf ("to play first PGC");
1657 printf ("to menu \"%s\"", decode_menuname (OP_VAL_8(3)));
1661 printf ("to VTS 0x%02x and TTN 0x%02x", OP_VAL_8(1), OP_VAL_8(2));
1664 printf ("to VMGM PGC number 0x%02x", OP_VAL_8(0)<<8 | OP_VAL_8(1));
1667 printf ("vts 0x%02x lu 0x%02x menu \"%s\"", OP_VAL_8(2), OP_VAL_8(1), decode_menuname (OP_VAL_8(3)));
1670 switch( OP_VAL_8(3)>>6 )
1673 printf( "to play first PGC" );
1676 printf( "to VMG title menu (?)" );
1679 printf( "vts 0x%02x lu 0x%02x menu \"%s\"",
1682 IfoMenuName( OP_VAL_8(3)&0xF ) );
1685 printf( "vmg pgc 0x%04x (?)", ( OP_VAL_8(0)<<8) | OP_VAL_8(1) );
1692 switch(OP_VAL_8(3)>>4) {
1694 printf ("system first pgc");
1697 printf ("system title menu");
1700 printf ("system menu \"%s\"", decode_menuname (OP_VAL_8(3)));
1703 printf ("system vmg pgc %02x ????", OP_VAL_8(0)<<8|OP_VAL_8(1));
1706 printf ("system lu 0x%02x menu \"%s\"", OP_VAL_8(2), decode_menuname (OP_VAL_8(3)));
1709 printf ("system vmg pgc 0x%02x", OP_VAL_8(0)<<8|OP_VAL_8(1));
1713 // OP_VAL_8(2) is number of cell
1714 // it is processed BEFORE switch
1715 // under some conditions, it is ignored
1716 // I don't understand exactly what it means
1717 printf( " ( spec cell 0x%02X ) ", OP_VAL_8(2) );
1719 switch( OP_VAL_8(3)>>6 )
1722 printf( "to FP PGC" );
1725 printf( "to VMG root menu (?)" );
1728 printf( "to VTS menu \"%s\" (?)",
1729 IfoMenuName(OP_VAL_8(3)&0xF) );
1732 printf( "vmg pgc 0x%02x (?)", (OP_VAL_8(0)<<8)|OP_VAL_8(1) );
1740 static void IfoLnk( ifo_command_t com
)
1742 u16 i_button
=OP_VAL_8(4)>>2;
1746 switch( com
.i_sub_cmd
)
1749 IfoAdvanced( &OP_VAL_8(4) );
1753 printf( "PGC 0x%02x", OP_VAL_16(2) );
1757 printf( "PTT 0x%02x", OP_VAL_16(2) );
1761 printf( "Program 0x%02x this PGC", OP_VAL_8(5) );
1765 printf( "Cell 0x%02x this PGC", OP_VAL_8(5) );
1773 printf( ", Highlight 0x%02x", OP_VAL_8(4)>>2 );
1778 void IfoSetSystem( ifo_command_t com
)
1785 for( i
=1; i
<=3; i
++ )
1787 if( OP_VAL_8(i
)&0x80 )
1791 printf ("s[%s] = 0x%02x;", ifo_reg
[i
], OP_VAL_8(i
)&0xf);
1795 printf ("s[%s] = r[0x%02x];", ifo_reg
[i
], OP_VAL_8(i
)&0xf);
1801 if(OP_VAL_8(1]&0x80)
1802 printf ("s[%s] = 0x%02x;", reg_name
[1], OP_VAL_8(1]&0xf);
1803 if(OP_VAL_8(2)&0x80)
1804 //DENT: lwhat about 0x7f here ???
1805 printf ("s[%s] = 0x%02x;", reg_name
[2], OP_VAL_8(2)&0x7f);
1806 if(OP_VAL_8(3)&0x80)
1807 printf ("s[%s] = 0x%02x;", reg_name
[3], OP_VAL_8(3)&0xf);
1809 if(OP_VAL_8(1)&0x80)
1810 printf ("s[%s] = r[0x%02x];", reg_name
[1], OP_VAL_8(1)&0xf);
1811 if(OP_VAL_8(2)&0x80)
1812 printf ("s[%s] = r[0x%02x];", reg_name
[2], OP_VAL_8(2)&0xf);
1813 if(OP_VAL_8(3)&0x80)
1814 printf ("s[%s] = r[0x%02x];", reg_name
[3], OP_VAL_8(3)&0xf);
1822 printf( "s[%s] = 0x%02x", ifo_reg
[9], OP_VAL_16(0) );
1826 printf( "s[%s] = r[0x%02x]", ifo_reg
[9], OP_VAL_8(1)&0x0f );
1829 printf( "s[%s] = (s[%s]&0x7FFF)|0x%02x",
1830 ifo_reg
[10], ifo_reg
[10], OP_VAL_16(1)&0x8000);
1835 printf( "r[0x%02x] = 0x%02x", OP_VAL_8(3)&0x0f, OP_VAL_16(0) );
1839 printf ("r[r[0x%02x]] = r[0x%02x]",
1840 OP_VAL_8(3)&0x0f, OP_VAL_8(1)&0x0f);
1844 //actually only bits 00011100 00011100 are set
1847 printf ("s[%s] = 0x%02x", ifo_reg
[11], OP_VAL_16(1));
1851 printf ("s[%s] = r[0x%02x]", ifo_reg
[11], OP_VAL_8(3)&0x0f );
1856 //s[%s]=(r[%s]&0x3FF) | (0x%02x << 0xA);
1857 //but it is way too ugly
1860 printf( "s[%s] = 0x%02x", ifo_reg
[8], OP_VAL_8(2)>>2 );
1864 printf( "s[%s] = r[0x%02x]", ifo_reg
[8], OP_VAL_8(3)&0x0f );
1872 static void IfoSet( ifo_command_t com
)
1874 IfoRegister( OP_VAL_16(0), 0 );
1875 printf( " %s ", IfoMath( com
.i_cmd
) );
1876 IfoRegister( OP_VAL_16(1), com
.i_direct
);
1879 /*****************************************************************************
1880 * CommandRead : translates the command strings in ifo into command
1882 *****************************************************************************/
1883 void CommandRead( ifo_command_t com
)
1885 u8
* pi_code
= (u8
*)(&com
);
1887 switch( com
.i_type
)
1900 printf ("if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
1901 ifo_cmp
[com
.i_cmp
]);
1902 IfoRegister (OP_VAL_16(1), com
.i_dir_cmp
);
1907 switch( com
.i_sub_cmd
)
1910 printf( "goto Line 0x%02x", OP_VAL_16(2) );
1914 printf( "stop VM" );
1918 printf( "Set Parental Level To %s and goto Line 0x%02x",
1919 ifo_parental
[OP_VAL_8(4)&0x7],
1924 printf( "Illegal" );
1943 printf( "if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f,
1944 ifo_cmp
[com
.i_cmp
] );
1945 IfoRegister( OP_VAL_8(5), 0 );
1956 printf( "if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
1957 ifo_cmp
[com
.i_cmp
] );
1958 IfoRegister( OP_VAL_16(1), com
.i_dir_cmp
);
1972 IfoSetSystem( com
);
1974 else if( com
.i_cmp
&& !com
.i_sub_cmd
)
1976 printf ("if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f, ifo_cmp
[com
.i_cmp
]);
1977 IfoRegister( OP_VAL_8(5), 0 );
1979 IfoSetSystem( com
);
1981 else if( !com
.i_cmp
&& com
.i_sub_cmd
)
1984 IfoSetSystem( com
);
2000 else if( com
.i_cmp
&& !com
.i_sub_cmd
)
2002 printf ("if (r[0x%02x] %s ", OP_VAL_8(0)&0x0f, ifo_cmp
[com
.i_cmp
]);
2003 IfoRegister( OP_VAL_16(2), com
.i_dir_cmp
);
2007 else if( !com
.i_cmp
&& com
.i_sub_cmd
)
2021 * math command on r[opcode[1]] and
2022 * direct?be2me_16(OP_VAL_8(0)):reg[OP_VAL_8(1)] is executed
2023 * ( unless command is swap; then r[opcode[1]] and r[OP_VAL_8(1)]
2025 * boolean operation cmp on r[opcode[1]] and
2026 * dir_cmp?be2me_16(OP_VAL_8(1)[1]):reg[OP_VAL_8(3)] is executed
2027 * on true result, buttons(c[6], c[7]) is called
2028 * problem is 'what is buttons()'
2031 printf( "r[0x%X] ", pi_code
[1] );
2032 printf( " %s ", IfoMath( com
.i_cmd
) );
2033 if( com
.i_cmd
== 2 )
2035 printf( "r[0x%X] ", OP_VAL_8(1) );
2039 IfoRegister( OP_VAL_16(0), com
.i_direct
);
2043 printf( "if ( r[%d] %s ", pi_code
[1], ifo_cmp
[com
.i_cmp
] );
2044 IfoRegister( OP_VAL_8(1), com
.i_dir_cmp
);
2045 printf( " ) then {" );
2046 IfoAdvanced( &OP_VAL_8(4) );
2051 * opposite to case 4: boolean, math and buttons.
2057 if( !com
.i_direct
&& com
.i_dir_cmp
)
2059 printf( "0x%X", OP_VAL_16(1) );
2063 IfoRegister( OP_VAL_8(3), 0 );
2064 if( OP_VAL_8(3)&0x80 )
2066 printf( "s[%s]", ifo_reg
[OP_VAL_8(3)&0x1F] );
2070 printf( "r[0x%X]", OP_VAL_8(3)&0x1F);
2071 // 0x1F is either not a mistake,
2072 // or Microsoft programmer's mistake!!!
2076 printf( " %s r[0x%X] ", ifo_cmp
[com
.i_cmp
],
2077 com
.i_direct
? OP_VAL_8(2) : OP_VAL_8(1) );
2078 printf( " ) then {" );
2079 printf( "r[0x%X] ", pi_code
[1] & 0xF );
2080 printf( " %s ", IfoMath( com
.i_cmd
) );
2082 if( com
.i_cmd
== 0x02 ) // swap
2084 printf("r[0x%X] ", OP_VAL_8(0)&0x1F);
2090 printf( "0x%X", OP_VAL_16(0) );
2094 if( OP_VAL_8(0) & 0x80 )
2096 printf("s[%s]", ifo_reg
[OP_VAL_8(0) & 0x1F] );
2100 printf("r[0x%X]", OP_VAL_8(0) & 0x1F );
2106 IfoAdvanced( &OP_VAL_8(4) );
2112 printf( "Unknown Command\n" );
2119 /*****************************************************************************
2120 * CommandPrint : print in clear text (I hope so !) what a command does
2121 *****************************************************************************/
2122 void CommandPrint( ifo_t ifo
)