1 /*****************************************************************************
2 * dvd_ifo.c: Functions for ifo parsing
3 *****************************************************************************
4 * Copyright (C) 1999-2001 VideoLAN
5 * $Id: dvd_ifo.c,v 1.10 2001/02/19 03:12:26 stef 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 *****************************************************************************/
42 #include "input_dvd.h"
44 void CommandRead( ifo_command_t );
50 /*****************************************************************************
51 * IfoInit : Creates an ifo structure and prepares for parsing directly
53 *****************************************************************************/
54 ifo_t IfoInit( int i_fd )
59 /* If we are here the dvd device has already been opened */
62 i_lba = UDFFindFile( i_fd, "/VIDEO_TS/VIDEO_TS.IFO");
64 ifo.i_off = (off_t)(i_lba) * DVD_LB_SIZE;
65 ifo.i_pos = lseek( ifo.i_fd, ifo.i_off, SEEK_SET );
70 /*****************************************************************************
71 * IfoEnd : Frees all the memory allocated to ifo structures
72 *****************************************************************************/
73 void IfoEnd( ifo_t* p_ifo )
77 /* Free structures from video title sets */
78 for( j=0 ; j<p_ifo->vmg.mat.i_tts_nb ; j++ )
80 free( p_ifo->p_vts[j].vobu_admap.pi_vobu_ssector );
81 free( p_ifo->p_vts[j].c_adt.p_cell_inf );
82 free( p_ifo->p_vts[j].m_vobu_admap.pi_vobu_ssector );
83 free( p_ifo->p_vts[j].m_c_adt.p_cell_inf );
84 for( i=0 ; i<p_ifo->p_vts[j].tmap_ti.i_nb ; i++ )
86 free( p_ifo->p_vts[j].tmap_ti.p_tmap[i].pi_sector );
88 free( p_ifo->p_vts[j].tmap_ti.pi_sbyte );
89 free( p_ifo->p_vts[j].tmap_ti.p_tmap );
90 free( p_ifo->p_vts[j].pgci_ti.p_srp );
91 for( i=0 ; i<p_ifo->p_vts[j].pgci_ut.i_lu_nb ; i++ )
93 free( p_ifo->p_vts[j].pgci_ut.p_pgci_inf[i].p_srp );
95 free( p_ifo->p_vts[j].pgci_ut.p_pgci_inf );
96 free( p_ifo->p_vts[j].pgci_ut.p_lu );
101 /* Free structures from video manager */
102 free( p_ifo->vmg.vobu_admap.pi_vobu_ssector );
103 free( p_ifo->vmg.c_adt.p_cell_inf );
104 for( i=0 ; i<p_ifo->vmg.pgci_ut.i_lu_nb ; i++ )
106 free( p_ifo->vmg.pgci_ut.p_pgci_inf[i].p_srp );
108 free( p_ifo->vmg.pgci_ut.p_pgci_inf );
109 free( p_ifo->vmg.pgci_ut.p_lu );
110 for( i=1 ; i<=8 ; i++ )
112 free( p_ifo->vmg.ptl_mait.p_ptl_mask->ppi_ptl_mask[i] );
114 free( p_ifo->vmg.ptl_mait.p_ptl_desc );
115 free( p_ifo->vmg.ptl_mait.p_ptl_mask );
116 free( p_ifo->vmg.vts_atrt.pi_vts_atrt_sbyte );
117 free( p_ifo->vmg.vts_atrt.p_vts_atrt );
118 free( p_ifo->vmg.pgc.p_cell_pos_inf );
119 free( p_ifo->vmg.pgc.p_cell_play_inf );
120 free( p_ifo->vmg.pgc.prg_map.pi_entry_cell );
121 free( p_ifo->vmg.pgc.com_tab.p_cell_com );
122 free( p_ifo->vmg.pgc.com_tab.p_post_com );
123 free( p_ifo->vmg.pgc.com_tab.p_pre_com );
129 * Macros to process ifo files
132 #define GET( p_field , i_len ) \
134 read( p_ifo->i_fd , (p_field) , (i_len) ); \
135 /*fprintf(stderr, "Pos : %lld Val : %llx\n", \
136 (long long)(p_ifo->i_pos - i_start), \
137 (long long)*(p_field) ); */ \
138 p_ifo->i_pos += i_len; \
141 #define GETC( p_field ) \
143 read( p_ifo->i_fd , (p_field) , 1 ); \
144 /*fprintf(stderr, "Pos : %lld Value : %d\n", \
145 (long long)(p_ifo->i_pos - i_start), \
150 #define GETS( p_field ) \
152 read( p_ifo->i_fd , (p_field) , 2 ); \
153 *(p_field) = ntohs( *(p_field) ); \
154 /*fprintf(stderr, "Pos : %lld Value : %d\n", \
155 (long long)(p_ifo->i_pos - i_start), \
160 #define GETL( p_field ) \
162 read( p_ifo->i_fd , (p_field) , 4 ); \
163 *(p_field) = ntohl( *(p_field) ); \
164 /*fprintf(stderr, "Pos : %lld Value : %d\n", \
165 (long long)(p_ifo->i_pos - i_start), \
170 #define GETLL( p_field ) \
172 read( p_ifo->i_fd , (p_field) , 8 ); \
173 *(p_field) = ntoh64( *(p_field) ); \
174 /*fprintf(stderr, "Pos : %lld Value : %lld\n", \
175 (long long)(p_ifo->i_pos - i_start), \
180 #define FLUSH( i_len ) \
182 /*fprintf(stderr, "Pos : %lld\n", (long long)(p_ifo->i_pos - i_start));*/ \
183 p_ifo->i_pos = lseek( p_ifo->i_fd , \
184 p_ifo->i_pos + (i_len), SEEK_SET ); \
188 * Function common to Video Manager and Video Title set Processing
191 /*****************************************************************************
192 * ReadPGC : Fills the Program Chain structure.
193 *****************************************************************************/
194 #define GETCOMMAND( p_com ) \
196 read( p_ifo->i_fd , (p_com) , 8 ); \
197 /*fprintf(stderr, "Pos : %lld Type : %d direct : %d cmd : %d dircmp : %d cmp : %d subcmd : %d v0 : %d v2 : %d v4 : %d\n", \
198 (long long)(p_ifo->i_pos - i_start), \
199 (int)((p_com)->i_type), \
200 (int)((p_com)->i_direct), \
201 (int)((p_com)->i_cmd), \
202 (int)((p_com)->i_dir_cmp), \
203 (int)((p_com)->i_cmp), \
204 (int)((p_com)->i_sub_cmd), \
205 (int)((p_com)->data.pi_16[0]), \
206 (int)((p_com)->data.pi_16[1]), \
207 (int)((p_com)->data.pi_16[2]));*/ \
208 /* CommandRead( *(p_com) );*/ \
212 static pgc_t ReadPGC( ifo_t* p_ifo )
216 off_t i_start = p_ifo->i_pos;
218 //fprintf( stderr, "PGC\n" );
221 GETC( &pgc.i_prg_nb );
222 GETC( &pgc.i_cell_nb );
223 GETL( &pgc.i_play_time );
224 GETL( &pgc.i_prohibited_user_op );
225 for( i=0 ; i<8 ; i++ )
227 GETS( &pgc.pi_audio_status[i] );
229 for( i=0 ; i<32 ; i++ )
231 GETL( &pgc.pi_subpic_status[i] );
233 GETS( &pgc.i_next_pgc_nb );
234 GETS( &pgc.i_prev_pgc_nb );
235 GETS( &pgc.i_goup_pgc_nb );
236 GETC( &pgc.i_still_time );
237 GETC( &pgc.i_play_mode );
238 for( i=0 ; i<16 ; i++ )
240 GETL( &pgc.pi_yuv_color[i] );
241 /* FIXME : We have to erase the extra bit */
243 GETS( &pgc.i_com_tab_sbyte );
244 GETS( &pgc.i_prg_map_sbyte );
245 GETS( &pgc.i_cell_play_inf_sbyte );
246 GETS( &pgc.i_cell_pos_inf_sbyte );
248 /* Parsing of pgc_com_tab_t */
249 if( pgc.i_com_tab_sbyte )
251 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
252 + pgc.i_com_tab_sbyte, SEEK_SET );
253 GETS( &pgc.com_tab.i_pre_com_nb );
254 GETS( &pgc.com_tab.i_post_com_nb );
255 GETS( &pgc.com_tab.i_cell_com_nb );
257 if( pgc.com_tab.i_pre_com_nb )
259 pgc.com_tab.p_pre_com =
260 malloc(pgc.com_tab.i_pre_com_nb *sizeof(ifo_command_t));
261 if( pgc.com_tab.p_pre_com == NULL )
263 intf_ErrMsg( "Out of memory" );
267 for( i=0 ; i<pgc.com_tab.i_pre_com_nb ; i++ )
269 GETCOMMAND( &pgc.com_tab.p_pre_com[i] );
272 if( pgc.com_tab.i_post_com_nb )
274 pgc.com_tab.p_post_com =
275 malloc(pgc.com_tab.i_post_com_nb *sizeof(ifo_command_t));
276 if( pgc.com_tab.p_post_com == NULL )
278 intf_ErrMsg( "Out of memory" );
282 for( i=0 ; i<pgc.com_tab.i_post_com_nb ; i++ )
284 GETCOMMAND( &pgc.com_tab.p_post_com[i] );
287 if( pgc.com_tab.i_cell_com_nb )
289 pgc.com_tab.p_cell_com =
290 malloc(pgc.com_tab.i_cell_com_nb *sizeof(ifo_command_t));
291 if( pgc.com_tab.p_cell_com == NULL )
293 intf_ErrMsg( "Out of memory" );
297 for( i=0 ; i<pgc.com_tab.i_cell_com_nb ; i++ )
299 GETCOMMAND( &pgc.com_tab.p_cell_com[i] );
303 /* Parsing of pgc_prg_map_t */
304 if( pgc.i_prg_map_sbyte )
306 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
307 + pgc.i_prg_map_sbyte, SEEK_SET );
308 pgc.prg_map.pi_entry_cell = malloc( pgc.i_prg_nb *sizeof(u8) );
309 if( pgc.prg_map.pi_entry_cell == NULL )
311 intf_ErrMsg( "Out of memory" );
315 GET( pgc.prg_map.pi_entry_cell, pgc.i_prg_nb );
316 /* FIXME : check endianness here */
318 /* Parsing of cell_play_inf_t */
319 if( pgc.i_cell_play_inf_sbyte )
321 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
322 + pgc.i_cell_play_inf_sbyte, SEEK_SET );
323 pgc.p_cell_play_inf = malloc( pgc.i_cell_nb *sizeof(cell_play_inf_t) );
324 if( pgc.p_cell_play_inf == NULL )
326 intf_ErrMsg( "Out of memory" );
330 for( i=0 ; i<pgc.i_cell_nb ; i++ )
332 GETS( &pgc.p_cell_play_inf[i].i_cat );
333 GETC( &pgc.p_cell_play_inf[i].i_still_time );
334 GETC( &pgc.p_cell_play_inf[i].i_com_nb );
335 GETL( &pgc.p_cell_play_inf[i].i_play_time );
336 GETL( &pgc.p_cell_play_inf[i].i_entry_sector );
337 GETL( &pgc.p_cell_play_inf[i].i_first_ilvu_vobu_esector );
338 GETL( &pgc.p_cell_play_inf[i].i_lvobu_ssector );
339 GETL( &pgc.p_cell_play_inf[i].i_lsector );
342 /* Parsing of cell_pos_inf_map */
343 if( pgc.i_cell_pos_inf_sbyte )
345 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
346 + pgc.i_cell_pos_inf_sbyte, SEEK_SET );
347 pgc.p_cell_pos_inf = malloc( pgc.i_cell_nb *sizeof(cell_pos_inf_t) );
348 if( pgc.p_cell_pos_inf == NULL )
350 intf_ErrMsg( "Out of memory" );
354 for( i=0 ; i<pgc.i_cell_nb ; i++ )
356 GETS( &pgc.p_cell_pos_inf[i].i_vob_id );
358 GETC( &pgc.p_cell_pos_inf[i].i_cell_id );
365 /*****************************************************************************
366 * ReadUnit : Fills Menu Language Unit Table/ PGC Info Table
367 *****************************************************************************/
368 static pgci_inf_t ReadUnit( ifo_t* p_ifo )
372 off_t i_start = p_ifo->i_pos;
374 //fprintf( stderr, "Unit\n" );
376 GETS( &inf.i_srp_nb );
378 GETL( &inf.i_lu_ebyte );
379 inf.p_srp = malloc( inf.i_srp_nb *sizeof(pgci_srp_t) );
380 if( inf.p_srp == NULL )
382 intf_ErrMsg( "Out of memory" );
386 for( i=0 ; i<inf.i_srp_nb ; i++ )
388 GETC( &inf.p_srp[i].i_pgc_cat_mask );
389 GETC( &inf.p_srp[i].i_pgc_cat );
390 GETS( &inf.p_srp[i].i_par_mask );
391 GETL( &inf.p_srp[i].i_pgci_sbyte );
393 for( i=0 ; i<inf.i_srp_nb ; i++ )
395 p_ifo->i_pos = lseek( p_ifo->i_fd,
396 i_start + inf.p_srp[i].i_pgci_sbyte,
398 inf.p_srp[i].pgc = ReadPGC( p_ifo );
404 /*****************************************************************************
405 * ReadUnitTable : Fills the PGCI Unit structure.
406 *****************************************************************************/
407 static pgci_ut_t ReadUnitTable( ifo_t* p_ifo )
411 off_t i_start = p_ifo->i_pos;
413 //fprintf( stderr, "Unit Table\n" );
415 GETS( &pgci.i_lu_nb );
417 GETL( &pgci.i_ebyte );
418 pgci.p_lu = malloc( pgci.i_lu_nb *sizeof(pgci_lu_t) );
419 if( pgci.p_lu == NULL )
421 intf_ErrMsg( "Out of memory" );
425 for( i=0 ; i<pgci.i_lu_nb ; i++ )
427 GET( pgci.p_lu[i].ps_lang_code, 2 );
429 GETC( &pgci.p_lu[i].i_existence_mask );
430 GETL( &pgci.p_lu[i].i_lu_sbyte );
432 pgci.p_pgci_inf = malloc( pgci.i_lu_nb *sizeof(pgci_inf_t) );
433 if( pgci.p_pgci_inf == NULL )
435 intf_ErrMsg( "Out of memory" );
439 for( i=0 ; i<pgci.i_lu_nb ; i++ )
441 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start +
442 pgci.p_lu[i].i_lu_sbyte,
444 pgci.p_pgci_inf[i] = ReadUnit( p_ifo );
450 /*****************************************************************************
451 * ReadCellInf : Fills the Cell Information structure.
452 *****************************************************************************/
453 static c_adt_t ReadCellInf( ifo_t* p_ifo )
456 off_t i_start = p_ifo->i_pos;
459 //fprintf( stderr, "CELL ADD\n" );
461 GETS( &c_adt.i_vob_nb );
463 GETL( &c_adt.i_ebyte );
465 ( i_start + c_adt.i_ebyte + 1 - p_ifo->i_pos ) / sizeof(cell_inf_t);
466 c_adt.p_cell_inf = malloc( c_adt.i_cell_nb *sizeof(cell_inf_t) );
467 if( c_adt.p_cell_inf == NULL )
469 intf_ErrMsg( "Out of memory" );
473 for( i = 0 ; i < c_adt.i_cell_nb ; i++ )
475 GETS( &c_adt.p_cell_inf[i].i_vob_id );
476 GETC( &c_adt.p_cell_inf[i].i_cell_id );
478 GETL( &c_adt.p_cell_inf[i].i_ssector );
479 GETL( &c_adt.p_cell_inf[i].i_esector );
485 /*****************************************************************************
486 * ReadMap : Fills the VOBU Map structure.
487 *****************************************************************************/
488 static vobu_admap_t ReadMap( ifo_t* p_ifo )
492 off_t i_start = p_ifo->i_pos;
494 //fprintf( stderr, "VOBU ADMAP\n" );
496 GETL( &map.i_ebyte );
497 i_max = ( i_start + map.i_ebyte + 1 - p_ifo->i_pos ) / sizeof(u32);
498 map.pi_vobu_ssector = malloc( i_max *sizeof(u32) );
499 for( i=0 ; i<i_max ; i++ )
501 GETL( &map.pi_vobu_ssector[i] );
508 * Video Manager Information Processing.
509 * This is what is contained in video_ts.ifo.
512 /*****************************************************************************
513 * ReadVMGInfMat : Fills the Management Information structure.
514 *****************************************************************************/
515 static vmgi_mat_t ReadVMGInfMat( ifo_t* p_ifo )
519 // off_t i_start = p_ifo->i_pos;
521 //fprintf( stderr, "VMGI\n" );
523 GET( mat.psz_id , 12 );
524 mat.psz_id[12] = '\0';
525 GETL( &mat.i_lsector );
527 GETL( &mat.i_i_lsector );
529 GETC( &mat.i_spec_ver );
531 GETS( &mat.i_vol_nb );
533 GETC( &mat.i_disc_side );
535 GETS( &mat.i_tts_nb );
536 GET( mat.ps_provider_id, 32 );
537 GETLL( &mat.i_pos_code );
539 GETL( &mat.i_i_mat_ebyte );
540 GETL( &mat.i_fp_pgc_sbyte );
542 GETL( &mat.i_vobs_ssector );
543 GETL( &mat.i_ptt_srpt_ssector );
544 GETL( &mat.i_pgci_ut_ssector );
545 GETL( &mat.i_ptl_mait_ssector );
546 GETL( &mat.i_vts_atrt_ssector );
547 GETL( &mat.i_txtdt_mg_ssector );
548 GETL( &mat.i_c_adt_ssector );
549 GETL( &mat.i_vobu_admap_ssector );
551 GETS( &mat.i_video_atrt );
553 GETC( &mat.i_audio_nb );
554 //fprintf( stderr, "vmgi audio nb : %d\n", mat.i_audio_nb );
555 for( i=0 ; i < 8 ; i++ )
557 GETLL( &mat.pi_audio_atrt[i] );
560 GETC( &mat.i_subpic_nb );
561 //fprintf( stderr, "vmgi subpic nb : %d\n", mat.i_subpic_nb );
562 for( i=0 ; i < mat.i_subpic_nb ; i++ )
564 GET( &mat.pi_subpic_atrt[i], 6 );
565 /* FIXME : take care of endianness */
571 /*****************************************************************************
572 * ReadVMGTitlePointer : Fills the Part Of Title Search Pointer structure.
573 *****************************************************************************/
574 static vmg_ptt_srpt_t ReadVMGTitlePointer( ifo_t* p_ifo )
578 // off_t i_start = p_ifo->i_pos;
580 //fprintf( stderr, "PTR\n" );
582 GETS( &ptr.i_ttu_nb );
584 GETL( &ptr.i_ebyte );
586 ptr.p_tts = malloc( ptr.i_ttu_nb *sizeof(tts_t) );
587 if( ptr.p_tts == NULL )
589 intf_ErrMsg( "Out of memory" );
593 for( i=0 ; i<ptr.i_ttu_nb ; i++ )
595 GETC( &ptr.p_tts[i].i_play_type );
596 GETC( &ptr.p_tts[i].i_angle_nb );
597 GETS( &ptr.p_tts[i].i_ptt_nb );
598 GETS( &ptr.p_tts[i].i_parental_id );
599 GETC( &ptr.p_tts[i].i_tts_nb );
600 GETC( &ptr.p_tts[i].i_vts_ttn );
601 GETL( &ptr.p_tts[i].i_ssector );
602 //fprintf( stderr, "PTR: %d %d %d\n",ptr.p_tts[i].i_tts_nb,ptr.p_tts[i].i_vts_ttn, ptr.p_tts[i].i_ssector );
608 /*****************************************************************************
609 * ReadParentalInf : Fills the Parental Management structure.
610 *****************************************************************************/
611 static vmg_ptl_mait_t ReadParentalInf( ifo_t* p_ifo )
615 off_t i_start = p_ifo->i_pos;
617 //fprintf( stderr, "PTL\n" );
619 GETS( &par.i_country_nb );
620 GETS( &par.i_vts_nb );
621 GETL( &par.i_ebyte );
622 par.p_ptl_desc = malloc( par.i_country_nb *sizeof(vmg_ptl_mai_desc_t) );
623 if( par.p_ptl_desc == NULL )
625 intf_ErrMsg( "Out of memory" );
629 for( i=0 ; i<par.i_country_nb ; i++ )
631 GET( par.p_ptl_desc[i].ps_country_code, 2 );
633 GETS( &par.p_ptl_desc[i].i_ptl_mai_sbyte );
636 par.p_ptl_mask = malloc( par.i_country_nb *sizeof(vmg_ptl_mask_t) );
637 if( par.p_ptl_mask == NULL )
639 intf_ErrMsg( "Out of memory" );
643 for( i=0 ; i<par.i_country_nb ; i++ )
645 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start +
646 par.p_ptl_desc[i].i_ptl_mai_sbyte, SEEK_SET );
647 for( j=1 ; j<=8 ; j++ )
649 par.p_ptl_mask[i].ppi_ptl_mask[j] =
650 malloc( par.i_vts_nb *sizeof(u16) );
651 if( par.p_ptl_mask[i].ppi_ptl_mask[j] == NULL )
653 intf_ErrMsg( "Out of memory" );
657 for( k=0 ; k<par.i_vts_nb ; k++ )
659 GETS( &par.p_ptl_mask[i].ppi_ptl_mask[j][k] );
667 /*****************************************************************************
668 * ReadVTSAttr : Fills the structure about VTS attributes.
669 *****************************************************************************/
670 static vmg_vts_atrt_t ReadVTSAttr( ifo_t* p_ifo )
674 off_t i_start = p_ifo->i_pos;
676 //fprintf( stderr, "VTS ATTR\n" );
678 GETS( &atrt.i_vts_nb );
680 GETL( &atrt.i_ebyte );
681 atrt.pi_vts_atrt_sbyte = malloc( atrt.i_vts_nb *sizeof(u32) );
682 if( atrt.pi_vts_atrt_sbyte == NULL )
684 intf_ErrMsg( "Out of memory" );
688 for( i=0 ; i<atrt.i_vts_nb ; i++ )
690 GETL( &atrt.pi_vts_atrt_sbyte[i] );
692 atrt.p_vts_atrt = malloc( atrt.i_vts_nb *sizeof(vts_atrt_t) );
693 if( atrt.p_vts_atrt == NULL )
695 intf_ErrMsg( "Out of memory" );
699 for( i=0 ; i<atrt.i_vts_nb ; i++ )
701 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start +
702 atrt.pi_vts_atrt_sbyte[i],
704 GETL( &atrt.p_vts_atrt[i].i_ebyte );
705 GETL( &atrt.p_vts_atrt[i].i_cat_app_type );
706 GETS( &atrt.p_vts_atrt[i].i_vtsm_video_atrt );
708 GETC( &atrt.p_vts_atrt[i].i_vtsm_audio_nb );
709 //fprintf( stderr, "m audio nb : %d\n", atrt.p_vts_atrt[i].i_vtsm_audio_nb );
710 for( j=0 ; j<8 ; j++ )
712 GETLL( &atrt.p_vts_atrt[i].pi_vtsm_audio_atrt[j] );
715 GETC( &atrt.p_vts_atrt[i].i_vtsm_subpic_nb );
716 //fprintf( stderr, "m subp nb : %d\n", atrt.p_vts_atrt[i].i_vtsm_subpic_nb );
717 for( j=0 ; j<28 ; j++ )
719 GET( &atrt.p_vts_atrt[i].pi_vtsm_subpic_atrt[j], 6 );
720 /* FIXME : Fix endianness issue here */
723 GETS( &atrt.p_vts_atrt[i].i_vtstt_video_atrt );
725 GETL( &atrt.p_vts_atrt[i].i_vtstt_audio_nb );
726 //fprintf( stderr, "tt audio nb : %d\n", atrt.p_vts_atrt[i].i_vtstt_audio_nb );
727 for( j=0 ; j<8 ; j++ )
729 GETLL( &atrt.p_vts_atrt[i].pi_vtstt_audio_atrt[j] );
732 GETC( &atrt.p_vts_atrt[i].i_vtstt_subpic_nb );
733 //fprintf( stderr, "tt subp nb : %d\n", atrt.p_vts_atrt[i].i_vtstt_subpic_nb );
734 for( j=0 ; j<28/*atrt.p_vts_atrt[i].i_vtstt_subpic_nb*/ ; j++ )
736 GET( &atrt.p_vts_atrt[i].pi_vtstt_subpic_atrt[j], 6 );
737 /* FIXME : Fix endianness issue here */
744 /*****************************************************************************
745 * ReadVMG : Parse video_ts.ifo file to fill the Video Manager structure.
746 *****************************************************************************/
747 static vmg_t ReadVMG( ifo_t* p_ifo )
751 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off, SEEK_SET);
752 vmg.mat = ReadVMGInfMat( p_ifo );
753 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
754 vmg.mat.i_fp_pgc_sbyte, SEEK_SET );
755 vmg.pgc = ReadPGC( p_ifo );
756 if( vmg.mat.i_ptt_srpt_ssector )
758 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
759 vmg.mat.i_ptt_srpt_ssector *DVD_LB_SIZE,
761 vmg.ptt_srpt = ReadVMGTitlePointer( p_ifo );
763 if( vmg.mat.i_pgci_ut_ssector )
765 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
766 vmg.mat.i_pgci_ut_ssector *DVD_LB_SIZE,
768 vmg.pgci_ut = ReadUnitTable( p_ifo );
770 if( vmg.mat.i_ptl_mait_ssector )
772 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
773 vmg.mat.i_ptl_mait_ssector *DVD_LB_SIZE,
775 vmg.ptl_mait = ReadParentalInf( p_ifo );
777 if( vmg.mat.i_vts_atrt_ssector )
779 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
780 vmg.mat.i_vts_atrt_ssector *DVD_LB_SIZE,
782 vmg.vts_atrt = ReadVTSAttr( p_ifo );
784 if( vmg.mat.i_c_adt_ssector )
786 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
787 vmg.mat.i_c_adt_ssector *DVD_LB_SIZE,
789 vmg.c_adt = ReadCellInf( p_ifo );
791 if( vmg.mat.i_vobu_admap_ssector )
793 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
794 vmg.mat.i_vobu_admap_ssector *DVD_LB_SIZE,
796 vmg.vobu_admap = ReadMap( p_ifo );
802 * Video Title Set Information Processing.
803 * This is what is contained in vts_*.ifo.
806 /*****************************************************************************
807 * ReadVTSInfMat : Fills the Title Set Information structure.
808 *****************************************************************************/
809 static vtsi_mat_t ReadVTSInfMat( ifo_t* p_ifo )
813 // off_t i_start = p_ifo->i_pos;
815 //fprintf( stderr, "VTSI\n" );
817 GET( mat.psz_id , 12 );
818 mat.psz_id[12] = '\0';
819 GETL( &mat.i_lsector );
821 GETL( &mat.i_i_lsector );
823 GETC( &mat.i_spec_ver );
826 GETL( &mat.i_mat_ebyte );
828 GETL( &mat.i_m_vobs_ssector );
829 GETL( &mat.i_tt_vobs_ssector );
830 GETL( &mat.i_ptt_srpt_ssector );
831 GETL( &mat.i_pgcit_ssector );
832 GETL( &mat.i_m_pgci_ut_ssector );
833 GETL( &mat.i_tmap_ti_ssector );
834 GETL( &mat.i_m_c_adt_ssector );
835 GETL( &mat.i_m_vobu_admap_ssector );
836 GETL( &mat.i_c_adt_ssector );
837 GETL( &mat.i_vobu_admap_ssector );
839 GETS( &mat.i_m_video_atrt );
841 GETC( &mat.i_m_audio_nb );
842 for( i=0 ; i<8 ; i++ )
844 GETLL( &mat.pi_m_audio_atrt[i] );
847 GETC( &mat.i_m_subpic_nb );
848 for( i=0 ; i<28 ; i++ )
850 GET( &mat.pi_m_subpic_atrt[i], 6 );
851 /* FIXME : take care of endianness */
854 GETS( &mat.i_video_atrt );
856 GETC( &mat.i_audio_nb );
857 //fprintf( stderr, "vtsi audio nb : %d\n", mat.i_audio_nb );
858 for( i=0 ; i<8 ; i++ )
860 GETLL( &mat.pi_audio_atrt[i] );
863 GETC( &mat.i_subpic_nb );
864 //fprintf( stderr, "vtsi subpic nb : %d\n", mat.i_subpic_nb );
865 for( i=0 ; i<mat.i_subpic_nb ; i++ )
867 GET( &mat.pi_subpic_atrt[i], 6 );
868 /* FIXME : take care of endianness */
874 /*****************************************************************************
875 * ReadVTSTitlePointer : Fills the Part Of Title Search Pointer structure.
876 *****************************************************************************/
877 static vts_ptt_srpt_t ReadVTSTitlePointer( ifo_t* p_ifo )
881 off_t i_start = p_ifo->i_pos;
883 //fprintf( stderr, "PTR\n" );
885 GETS( &ptr.i_ttu_nb );
887 GETL( &ptr.i_ebyte );
888 ptr.pi_ttu_sbyte = malloc( ptr.i_ttu_nb *sizeof(u32) );
889 if( ptr.pi_ttu_sbyte == NULL )
891 intf_ErrMsg( "Out of memory" );
895 for( i=0 ; i<ptr.i_ttu_nb ; i++ )
897 GETL( &ptr.pi_ttu_sbyte[i] );
900 ptr.p_ttu = malloc( ptr.i_ttu_nb *sizeof(ttu_t) );
901 if( ptr.p_ttu == NULL )
903 intf_ErrMsg( "Out of memory" );
907 for( i=0 ; i<ptr.i_ttu_nb ; i++ )
909 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start +
910 ptr.pi_ttu_sbyte[i], SEEK_SET );
911 GETS( &ptr.p_ttu[i].i_pgc_nb );
912 GETS( &ptr.p_ttu[i].i_prg_nb );
918 /*****************************************************************************
919 * ReadVTSTimeMap : Fills the time map table
920 *****************************************************************************/
921 static vts_tmap_ti_t ReadVTSTimeMap( ifo_t* p_ifo )
925 // off_t i_start = p_ifo->i_pos;
927 //fprintf( stderr, "TMAP\n" );
931 GETL( &tmap.i_ebyte );
932 tmap.pi_sbyte = malloc( tmap.i_nb *sizeof(u32) );
933 if( tmap.pi_sbyte == NULL )
935 intf_ErrMsg( "Out of memory" );
939 for( i=0 ; i<tmap.i_nb ; i++ )
941 GETL( &tmap.pi_sbyte[i] );
943 tmap.p_tmap = malloc( tmap.i_nb *sizeof(tmap_t) );
944 if( tmap.p_tmap == NULL )
946 intf_ErrMsg( "Out of memory" );
950 for( i=0 ; i<tmap.i_nb ; i++ )
952 GETC( &tmap.p_tmap[i].i_time_unit );
954 GETS( &tmap.p_tmap[i].i_entry_nb );
955 tmap.p_tmap[i].pi_sector =
956 malloc( tmap.p_tmap[i].i_entry_nb *sizeof(u32) );
957 if( tmap.p_tmap[i].pi_sector == NULL )
959 intf_ErrMsg( "Out of memory" );
963 for( j=0 ; j<tmap.p_tmap[i].i_entry_nb ; j++ )
965 GETL( &tmap.p_tmap[i].pi_sector[j] );
973 /*****************************************************************************
974 * ReadVTS : Parse vts*.ifo files to fill the Video Title Set structure.
975 *****************************************************************************/
976 static vts_t ReadVTS( ifo_t* p_ifo )
980 vts.i_pos = p_ifo->i_pos;
982 vts.mat = ReadVTSInfMat( p_ifo );
983 if( vts.mat.i_ptt_srpt_ssector )
985 p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
986 vts.mat.i_ptt_srpt_ssector *DVD_LB_SIZE,
988 vts.ptt_srpt = ReadVTSTitlePointer( p_ifo );
990 if( vts.mat.i_m_pgci_ut_ssector )
992 p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
993 vts.mat.i_m_pgci_ut_ssector *DVD_LB_SIZE,
995 vts.pgci_ut = ReadUnitTable( p_ifo );
997 if( vts.mat.i_pgcit_ssector )
999 p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
1000 vts.mat.i_pgcit_ssector *DVD_LB_SIZE,
1002 vts.pgci_ti = ReadUnit( p_ifo );
1004 if( vts.mat.i_tmap_ti_ssector )
1006 p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
1007 vts.mat.i_tmap_ti_ssector *DVD_LB_SIZE,
1009 vts.tmap_ti = ReadVTSTimeMap( p_ifo );
1011 if( vts.mat.i_m_c_adt_ssector )
1013 p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
1014 vts.mat.i_m_c_adt_ssector *DVD_LB_SIZE,
1016 vts.m_c_adt = ReadCellInf( p_ifo );
1018 if( vts.mat.i_m_vobu_admap_ssector )
1020 p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
1021 vts.mat.i_m_vobu_admap_ssector *DVD_LB_SIZE,
1023 vts.m_vobu_admap = ReadMap( p_ifo );
1025 if( vts.mat.i_c_adt_ssector )
1027 p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
1028 vts.mat.i_c_adt_ssector *DVD_LB_SIZE,
1030 vts.c_adt = ReadCellInf( p_ifo );
1032 if( vts.mat.i_vobu_admap_ssector )
1034 p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
1035 vts.mat.i_vobu_admap_ssector *DVD_LB_SIZE,
1037 vts.vobu_admap = ReadMap( p_ifo );
1044 * DVD Information Management
1047 /*****************************************************************************
1048 * IfoRead : Function that fills structure and calls specified functions
1050 *****************************************************************************/
1051 void IfoRead( ifo_t* p_ifo )
1056 /* Video Manager Initialization */
1057 intf_WarnMsg( 2, "ifo: initializing VMG" );
1058 p_ifo->vmg = ReadVMG( p_ifo );
1060 /* Video Title Sets initialization */
1061 p_ifo->p_vts = malloc( p_ifo->vmg.mat.i_tts_nb *sizeof(vts_t) );
1062 if( p_ifo->p_vts == NULL )
1064 intf_ErrMsg( "Out of memory" );
1069 for( i=0 ; i<p_ifo->vmg.mat.i_tts_nb ; i++ )
1072 intf_WarnMsg( 2, "ifo: initializing VTS %d", i+1 );
1074 i_off = (off_t)( p_ifo->vmg.ptt_srpt.p_tts[i].i_ssector ) *DVD_LB_SIZE
1077 p_ifo->i_pos = lseek( p_ifo->i_fd, i_off, SEEK_SET );
1079 /* FIXME : I really don't know why udf find file
1080 * does not give the exact beginning of file */
1082 p_ifo->p_vts[i] = ReadVTS( p_ifo );
1090 * IFO virtual machine : a set of commands that give the
1091 * interactive behaviour of the dvd
1095 #define OP_VAL_16(i) (ntoh16( com.data.pi_16[i]))
1096 #define OP_VAL_8(i) ((com.data.pi_8[i]))
1098 static char ifo_reg[][80]=
1100 "Menu_Language_Code",
1102 "SubPicture_Stream_#",
1108 "Highlighted_Button_#",
1111 "Karaoke_audio_mixing_mode",
1112 "Parental_mgmt_country_code",
1116 "Audio_language_code_setting",
1117 "Audio_language_extension_code",
1118 "SPU_language_code_setting",
1119 "SPU_language_extension_code",
1120 "?Player_Regional_Code",
1126 static char * IfoMath( char val )
1128 static char math_op[][10] =
1148 return (char *) math_op[val & 0x0f];
1152 char ifo_cmp[][10] =
1164 char ifo_parental[][10] =
1176 char ifo_menu_id[][80] =
1188 char * IfoMenuName( char index )
1190 return ifo_menu_id[index&0x07];
1193 static void IfoRegister( u16 i_data, u8 i_direct)
1197 if( 0/*isalpha( i_data >> 8 & 0xff )*/ )
1199 printf("'%c%c'", i_data>>8&0xff, i_data&0xff);
1203 printf("0x%02x", i_data);
1218 printf("s[%s]", ifo_reg[i_data]);
1231 printf("r[0x%02x]", i_data);
1237 static void IfoAdvanced( u8 *pi_code )
1239 u8 i_cmd = pi_code[0];
1245 printf( " Highlight button %d; ", pi_code[1]>>2 );
1250 printf( " Illegal " );
1255 printf( "ReSuME %d", pi_code[7] );
1257 else if( ( i_cmd & 0x06) == 0x02 )
1259 printf ("Link to %s cell ", ( i_cmd & 0x01 ) ? "prev" : "next");
1263 printf( "advanced (0x%02x) ", i_cmd );
1268 static void IfoJmp( ifo_command_t com )
1273 switch( com.i_sub_cmd )
1279 printf( "VTS 0x%02x", OP_VAL_8(3) );
1282 printf( "This VTS Title 0x%02x", OP_VAL_8(3) );
1285 printf( "This VTS Title 0x%02x Part 0x%04x",
1287 OP_VAL_8(0)<<8|OP_VAL_8(1));
1291 printf ("in SystemSpace ");
1292 switch (OP_VAL_8(3)>>4) {
1294 printf ("to play first PGC");
1297 printf ("to menu \"%s\"", decode_menuname (OP_VAL_8(3)));
1301 printf ("to VTS 0x%02x and TTN 0x%02x", OP_VAL_8(1), OP_VAL_8(2));
1304 printf ("to VMGM PGC number 0x%02x", OP_VAL_8(0)<<8 | OP_VAL_8(1));
1307 printf ("vts 0x%02x lu 0x%02x menu \"%s\"", OP_VAL_8(2), OP_VAL_8(1), decode_menuname (OP_VAL_8(3)));
1310 switch( OP_VAL_8(3)>>6 )
1313 printf( "to play first PGC" );
1316 printf( "to VMG title menu (?)" );
1319 printf( "vts 0x%02x lu 0x%02x menu \"%s\"",
1322 IfoMenuName( OP_VAL_8(3)&0xF ) );
1325 printf( "vmg pgc 0x%04x (?)", ( OP_VAL_8(0)<<8) | OP_VAL_8(1) );
1332 switch(OP_VAL_8(3)>>4) {
1334 printf ("system first pgc");
1337 printf ("system title menu");
1340 printf ("system menu \"%s\"", decode_menuname (OP_VAL_8(3)));
1343 printf ("system vmg pgc %02x ????", OP_VAL_8(0)<<8|OP_VAL_8(1));
1346 printf ("system lu 0x%02x menu \"%s\"", OP_VAL_8(2), decode_menuname (OP_VAL_8(3)));
1349 printf ("system vmg pgc 0x%02x", OP_VAL_8(0)<<8|OP_VAL_8(1));
1353 // OP_VAL_8(2) is number of cell
1354 // it is processed BEFORE switch
1355 // under some conditions, it is ignored
1356 // I don't understand exactly what it means
1357 printf( " ( spec cell 0x%02X ) ", OP_VAL_8(2) );
1359 switch( OP_VAL_8(3)>>6 )
1362 printf( "to FP PGC" );
1365 printf( "to VMG root menu (?)" );
1368 printf( "to VTS menu \"%s\" (?)",
1369 IfoMenuName(OP_VAL_8(3)&0xF) );
1372 printf( "vmg pgc 0x%02x (?)", (OP_VAL_8(0)<<8)|OP_VAL_8(1) );
1380 static void IfoLnk( ifo_command_t com )
1382 u16 i_button=OP_VAL_8(4)>>2;
1386 switch( com.i_sub_cmd )
1389 IfoAdvanced( &OP_VAL_8(4) );
1393 printf( "PGC 0x%02x", OP_VAL_16(2) );
1397 printf( "PTT 0x%02x", OP_VAL_16(2) );
1401 printf( "Program 0x%02x this PGC", OP_VAL_8(5) );
1405 printf( "Cell 0x%02x this PGC", OP_VAL_8(5) );
1413 printf( ", Highlight 0x%02x", OP_VAL_8(4)>>2 );
1418 void IfoSetSystem( ifo_command_t com )
1425 for( i=1; i<=3; i++ )
1427 if( OP_VAL_8(i)&0x80 )
1431 printf ("s[%s] = 0x%02x;", ifo_reg[i], OP_VAL_8(i)&0xf);
1435 printf ("s[%s] = r[0x%02x];", ifo_reg[i], OP_VAL_8(i)&0xf);
1441 if(OP_VAL_8(1]&0x80)
1442 printf ("s[%s] = 0x%02x;", reg_name[1], OP_VAL_8(1]&0xf);
1443 if(OP_VAL_8(2)&0x80)
1444 //DENT: lwhat about 0x7f here ???
1445 printf ("s[%s] = 0x%02x;", reg_name[2], OP_VAL_8(2)&0x7f);
1446 if(OP_VAL_8(3)&0x80)
1447 printf ("s[%s] = 0x%02x;", reg_name[3], OP_VAL_8(3)&0xf);
1449 if(OP_VAL_8(1)&0x80)
1450 printf ("s[%s] = r[0x%02x];", reg_name[1], OP_VAL_8(1)&0xf);
1451 if(OP_VAL_8(2)&0x80)
1452 printf ("s[%s] = r[0x%02x];", reg_name[2], OP_VAL_8(2)&0xf);
1453 if(OP_VAL_8(3)&0x80)
1454 printf ("s[%s] = r[0x%02x];", reg_name[3], OP_VAL_8(3)&0xf);
1462 printf( "s[%s] = 0x%02x", ifo_reg[9], OP_VAL_16(0) );
1466 printf( "s[%s] = r[0x%02x]", ifo_reg[9], OP_VAL_8(1)&0x0f );
1469 printf( "s[%s] = (s[%s]&0x7FFF)|0x%02x",
1470 ifo_reg[10], ifo_reg[10], OP_VAL_16(1)&0x8000);
1475 printf( "r[0x%02x] = 0x%02x", OP_VAL_8(3)&0x0f, OP_VAL_16(0) );
1479 printf ("r[r[0x%02x]] = r[0x%02x]",
1480 OP_VAL_8(3)&0x0f, OP_VAL_8(1)&0x0f);
1484 //actually only bits 00011100 00011100 are set
1487 printf ("s[%s] = 0x%02x", ifo_reg[11], OP_VAL_16(1));
1491 printf ("s[%s] = r[0x%02x]", ifo_reg[11], OP_VAL_8(3)&0x0f );
1496 //s[%s]=(r[%s]&0x3FF) | (0x%02x << 0xA);
1497 //but it is way too ugly
1500 printf( "s[%s] = 0x%02x", ifo_reg[8], OP_VAL_8(2)>>2 );
1504 printf( "s[%s] = r[0x%02x]", ifo_reg[8], OP_VAL_8(3)&0x0f );
1512 static void IfoSet( ifo_command_t com )
1514 IfoRegister( OP_VAL_16(0), 0 );
1515 printf( " %s ", IfoMath( com.i_cmd ) );
1516 IfoRegister( OP_VAL_16(1), com.i_direct );
1519 /*****************************************************************************
1520 * CommandRead : translates the command strings in ifo into command
1522 *****************************************************************************/
1523 void CommandRead( ifo_command_t com )
1525 u8* pi_code = (u8*)(&com);
1527 switch( com.i_type )
1540 printf ("if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
1541 ifo_cmp[com.i_cmp]);
1542 IfoRegister (OP_VAL_16(1), com.i_dir_cmp);
1547 switch( com.i_sub_cmd )
1550 printf( "goto Line 0x%02x", OP_VAL_16(2) );
1554 printf( "stop VM" );
1558 printf( "Set Parental Level To %s and goto Line 0x%02x",
1559 ifo_parental[OP_VAL_8(4)&0x7],
1564 printf( "Illegal" );
1583 printf( "if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f,
1584 ifo_cmp[com.i_cmp] );
1585 IfoRegister( OP_VAL_8(5), 0 );
1596 printf( "if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
1597 ifo_cmp[com.i_cmp] );
1598 IfoRegister( OP_VAL_16(1), com.i_dir_cmp );
1612 IfoSetSystem( com );
1614 else if( com.i_cmp && !com.i_sub_cmd )
1616 printf ("if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f, ifo_cmp[com.i_cmp]);
1617 IfoRegister( OP_VAL_8(5), 0 );
1619 IfoSetSystem( com );
1621 else if( !com.i_cmp && com.i_sub_cmd )
1624 IfoSetSystem( com );
1640 else if( com.i_cmp && !com.i_sub_cmd )
1642 printf ("if (r[0x%02x] %s ", OP_VAL_8(0)&0x0f, ifo_cmp[com.i_cmp]);
1643 IfoRegister( OP_VAL_16(2), com.i_dir_cmp );
1647 else if( !com.i_cmp && com.i_sub_cmd )
1661 * math command on r[opcode[1]] and
1662 * direct?be2me_16(OP_VAL_8(0)):reg[OP_VAL_8(1)] is executed
1663 * ( unless command is swap; then r[opcode[1]] and r[OP_VAL_8(1)]
1665 * boolean operation cmp on r[opcode[1]] and
1666 * dir_cmp?be2me_16(OP_VAL_8(1)[1]):reg[OP_VAL_8(3)] is executed
1667 * on true result, buttons(c[6], c[7]) is called
1668 * problem is 'what is buttons()'
1671 printf( "r[0x%X] ", pi_code[1] );
1672 printf( " %s ", IfoMath( com.i_cmd ) );
1673 if( com.i_cmd == 2 )
1675 printf( "r[0x%X] ", OP_VAL_8(1) );
1679 IfoRegister( OP_VAL_16(0), com.i_direct );
1683 printf( "if ( r[%d] %s ", pi_code[1], ifo_cmp[com.i_cmp] );
1684 IfoRegister( OP_VAL_8(1), com.i_dir_cmp );
1685 printf( " ) then {" );
1686 IfoAdvanced( &OP_VAL_8(4) );
1691 * opposite to case 4: boolean, math and buttons.
1697 if( !com.i_direct && com.i_dir_cmp )
1699 printf( "0x%X", OP_VAL_16(1) );
1703 IfoRegister( OP_VAL_8(3), 0 );
1704 if( OP_VAL_8(3)&0x80 )
1706 printf( "s[%s]", ifo_reg[OP_VAL_8(3)&0x1F] );
1710 printf( "r[0x%X]", OP_VAL_8(3)&0x1F);
1711 // 0x1F is either not a mistake,
1712 // or Microsoft programmer's mistake!!!
1716 printf( " %s r[0x%X] ", ifo_cmp[com.i_cmp],
1717 com.i_direct ? OP_VAL_8(2) : OP_VAL_8(1) );
1718 printf( " ) then {" );
1719 printf( "r[0x%X] ", pi_code[1] & 0xF );
1720 printf( " %s ", IfoMath( com.i_cmd ) );
1722 if( com.i_cmd == 0x02 ) // swap
1724 printf("r[0x%X] ", OP_VAL_8(0)&0x1F);
1730 printf( "0x%X", OP_VAL_16(0) );
1734 if( OP_VAL_8(0) & 0x80 )
1736 printf("s[%s]", ifo_reg[OP_VAL_8(0) & 0x1F] );
1740 printf("r[0x%X]", OP_VAL_8(0) & 0x1F );
1746 IfoAdvanced( &OP_VAL_8(4) );
1752 printf( "Unknown Command\n" );
1759 /*****************************************************************************
1760 * CommandPrint : print in clear text (I hope so !) what a command does
1761 *****************************************************************************/
1762 void CommandPrint( ifo_t ifo )