1 /*****************************************************************************
2 * dvd_ifo.c: Functions for ifo parsing
3 *****************************************************************************
4 * Copyright (C) 1999-2001 VideoLAN
5 * $Id: dvd_ifo.c,v 1.12 2001/02/20 02:56:50 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"
47 static vmg_t ReadVMG ( ifo_t* );
48 void CommandRead( ifo_command_t );
54 /*****************************************************************************
55 * IfoInit : Creates an ifo structure and prepares for parsing directly
57 *****************************************************************************/
58 ifo_t IfoInit( int i_fd )
63 /* If we are here the dvd device has already been opened */
66 i_lba = UDFFindFile( i_fd, "/VIDEO_TS/VIDEO_TS.IFO");
68 ifo.i_off = (off_t)(i_lba) * DVD_LB_SIZE;
69 ifo.i_pos = lseek( ifo.i_fd, ifo.i_off, SEEK_SET );
71 /* Video Manager Initialization */
72 intf_WarnMsg( 2, "ifo: initializing VMG" );
73 ifo.vmg = ReadVMG( &ifo );
78 /*****************************************************************************
79 * IfoEnd : Frees all the memory allocated to ifo structures
80 *****************************************************************************/
81 void IfoEnd( ifo_t* p_ifo )
86 /* Free structures from video title sets */
87 for( j=0 ; j<p_ifo->vmg.mat.i_tts_nb ; j++ )
89 free( p_ifo->p_vts[j].vobu_admap.pi_vobu_ssector );
90 free( p_ifo->p_vts[j].c_adt.p_cell_inf );
91 free( p_ifo->p_vts[j].m_vobu_admap.pi_vobu_ssector );
92 free( p_ifo->p_vts[j].m_c_adt.p_cell_inf );
93 for( i=0 ; i<p_ifo->p_vts[j].tmap_ti.i_nb ; i++ )
95 free( p_ifo->p_vts[j].tmap_ti.p_tmap[i].pi_sector );
97 free( p_ifo->p_vts[j].tmap_ti.pi_sbyte );
98 free( p_ifo->p_vts[j].tmap_ti.p_tmap );
99 free( p_ifo->p_vts[j].pgci_ti.p_srp );
100 for( i=0 ; i<p_ifo->p_vts[j].pgci_ut.i_lu_nb ; i++ )
102 free( p_ifo->p_vts[j].pgci_ut.p_pgci_inf[i].p_srp );
104 free( p_ifo->p_vts[j].pgci_ut.p_pgci_inf );
105 free( p_ifo->p_vts[j].pgci_ut.p_lu );
108 free( p_ifo->p_vts );
110 /* Free structures from video manager */
111 free( p_ifo->vmg.vobu_admap.pi_vobu_ssector );
112 free( p_ifo->vmg.c_adt.p_cell_inf );
113 for( i=0 ; i<p_ifo->vmg.pgci_ut.i_lu_nb ; i++ )
115 free( p_ifo->vmg.pgci_ut.p_pgci_inf[i].p_srp );
117 free( p_ifo->vmg.pgci_ut.p_pgci_inf );
118 free( p_ifo->vmg.pgci_ut.p_lu );
119 for( i=1 ; i<=8 ; i++ )
121 free( p_ifo->vmg.ptl_mait.p_ptl_mask->ppi_ptl_mask[i] );
123 free( p_ifo->vmg.ptl_mait.p_ptl_desc );
124 free( p_ifo->vmg.ptl_mait.p_ptl_mask );
125 free( p_ifo->vmg.vts_atrt.pi_vts_atrt_sbyte );
126 free( p_ifo->vmg.vts_atrt.p_vts_atrt );
127 free( p_ifo->vmg.pgc.p_cell_pos_inf );
128 free( p_ifo->vmg.pgc.p_cell_play_inf );
129 free( p_ifo->vmg.pgc.prg_map.pi_entry_cell );
130 free( p_ifo->vmg.pgc.com_tab.p_cell_com );
131 free( p_ifo->vmg.pgc.com_tab.p_post_com );
132 free( p_ifo->vmg.pgc.com_tab.p_pre_com );
138 * Macros to process ifo files
141 #define GET( p_field , i_len ) \
143 read( p_ifo->i_fd , (p_field) , (i_len) ); \
144 /*fprintf(stderr, "Pos : %lld Val : %llx\n", \
145 (long long)(p_ifo->i_pos - i_start), \
146 (long long)*(p_field) ); */ \
147 p_ifo->i_pos += i_len; \
150 #define GETC( p_field ) \
152 read( p_ifo->i_fd , (p_field) , 1 ); \
153 /*fprintf(stderr, "Pos : %lld Value : %d\n", \
154 (long long)(p_ifo->i_pos - i_start), \
159 #define GETS( p_field ) \
161 read( p_ifo->i_fd , (p_field) , 2 ); \
162 *(p_field) = ntohs( *(p_field) ); \
163 /*fprintf(stderr, "Pos : %lld Value : %d\n", \
164 (long long)(p_ifo->i_pos - i_start), \
169 #define GETL( p_field ) \
171 read( p_ifo->i_fd , (p_field) , 4 ); \
172 *(p_field) = ntohl( *(p_field) ); \
173 /*fprintf(stderr, "Pos : %lld Value : %d\n", \
174 (long long)(p_ifo->i_pos - i_start), \
179 #define GETLL( p_field ) \
181 read( p_ifo->i_fd , (p_field) , 8 ); \
182 *(p_field) = ntoh64( *(p_field) ); \
183 /*fprintf(stderr, "Pos : %lld Value : %lld\n", \
184 (long long)(p_ifo->i_pos - i_start), \
189 #define FLUSH( i_len ) \
191 /*fprintf(stderr, "Pos : %lld\n", (long long)(p_ifo->i_pos - i_start));*/ \
192 p_ifo->i_pos = lseek( p_ifo->i_fd , \
193 p_ifo->i_pos + (i_len), SEEK_SET ); \
197 * Function common to Video Manager and Video Title set Processing
200 /*****************************************************************************
201 * ReadPGC : Fills the Program Chain structure.
202 *****************************************************************************/
203 #define GETCOMMAND( p_com ) \
205 read( p_ifo->i_fd , (p_com) , 8 ); \
206 /*fprintf(stderr, "Pos : %lld Type : %d direct : %d cmd : %d dircmp : %d cmp : %d subcmd : %d v0 : %d v2 : %d v4 : %d\n", \
207 (long long)(p_ifo->i_pos - i_start), \
208 (int)((p_com)->i_type), \
209 (int)((p_com)->i_direct), \
210 (int)((p_com)->i_cmd), \
211 (int)((p_com)->i_dir_cmp), \
212 (int)((p_com)->i_cmp), \
213 (int)((p_com)->i_sub_cmd), \
214 (int)((p_com)->data.pi_16[0]), \
215 (int)((p_com)->data.pi_16[1]), \
216 (int)((p_com)->data.pi_16[2]));*/ \
217 /* CommandRead( *(p_com) );*/ \
221 static pgc_t ReadPGC( ifo_t* p_ifo )
225 off_t i_start = p_ifo->i_pos;
227 //fprintf( stderr, "PGC\n" );
230 GETC( &pgc.i_prg_nb );
231 GETC( &pgc.i_cell_nb );
232 //fprintf( stderr, "PGC: Prg: %d Cell: %d\n", pgc.i_prg_nb, pgc.i_cell_nb );
233 GETL( &pgc.i_play_time );
234 GETL( &pgc.i_prohibited_user_op );
235 for( i=0 ; i<8 ; i++ )
237 GETS( &pgc.pi_audio_status[i] );
239 for( i=0 ; i<32 ; i++ )
241 GETL( &pgc.pi_subpic_status[i] );
243 GETS( &pgc.i_next_pgc_nb );
244 GETS( &pgc.i_prev_pgc_nb );
245 GETS( &pgc.i_goup_pgc_nb );
246 //fprintf( stderr, "PGC: Prev: %d Next: %d Up: %d\n",pgc.i_prev_pgc_nb ,pgc.i_next_pgc_nb, pgc.i_goup_pgc_nb );
247 GETC( &pgc.i_still_time );
248 GETC( &pgc.i_play_mode );
249 for( i=0 ; i<16 ; i++ )
251 GETL( &pgc.pi_yuv_color[i] );
252 /* FIXME : We have to erase the extra bit */
254 GETS( &pgc.i_com_tab_sbyte );
255 GETS( &pgc.i_prg_map_sbyte );
256 GETS( &pgc.i_cell_play_inf_sbyte );
257 GETS( &pgc.i_cell_pos_inf_sbyte );
259 /* Parsing of pgc_com_tab_t */
260 if( pgc.i_com_tab_sbyte )
262 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
263 + pgc.i_com_tab_sbyte, SEEK_SET );
264 GETS( &pgc.com_tab.i_pre_com_nb );
265 GETS( &pgc.com_tab.i_post_com_nb );
266 GETS( &pgc.com_tab.i_cell_com_nb );
268 if( pgc.com_tab.i_pre_com_nb )
270 pgc.com_tab.p_pre_com =
271 malloc(pgc.com_tab.i_pre_com_nb *sizeof(ifo_command_t));
272 if( pgc.com_tab.p_pre_com == NULL )
274 intf_ErrMsg( "Out of memory" );
278 for( i=0 ; i<pgc.com_tab.i_pre_com_nb ; i++ )
280 GETCOMMAND( &pgc.com_tab.p_pre_com[i] );
283 if( pgc.com_tab.i_post_com_nb )
285 pgc.com_tab.p_post_com =
286 malloc(pgc.com_tab.i_post_com_nb *sizeof(ifo_command_t));
287 if( pgc.com_tab.p_post_com == NULL )
289 intf_ErrMsg( "Out of memory" );
293 for( i=0 ; i<pgc.com_tab.i_post_com_nb ; i++ )
295 GETCOMMAND( &pgc.com_tab.p_post_com[i] );
298 if( pgc.com_tab.i_cell_com_nb )
300 pgc.com_tab.p_cell_com =
301 malloc(pgc.com_tab.i_cell_com_nb *sizeof(ifo_command_t));
302 if( pgc.com_tab.p_cell_com == NULL )
304 intf_ErrMsg( "Out of memory" );
308 for( i=0 ; i<pgc.com_tab.i_cell_com_nb ; i++ )
310 GETCOMMAND( &pgc.com_tab.p_cell_com[i] );
314 /* Parsing of pgc_prg_map_t */
315 if( pgc.i_prg_map_sbyte )
317 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
318 + pgc.i_prg_map_sbyte, SEEK_SET );
319 pgc.prg_map.pi_entry_cell = malloc( pgc.i_prg_nb *sizeof(u8) );
320 if( pgc.prg_map.pi_entry_cell == NULL )
322 intf_ErrMsg( "Out of memory" );
326 GET( pgc.prg_map.pi_entry_cell, pgc.i_prg_nb );
327 /* FIXME : check endianness here */
329 /* Parsing of cell_play_inf_t */
330 if( pgc.i_cell_play_inf_sbyte )
332 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
333 + pgc.i_cell_play_inf_sbyte, SEEK_SET );
334 pgc.p_cell_play_inf = malloc( pgc.i_cell_nb *sizeof(cell_play_inf_t) );
335 if( pgc.p_cell_play_inf == NULL )
337 intf_ErrMsg( "Out of memory" );
341 for( i=0 ; i<pgc.i_cell_nb ; i++ )
343 GETS( &pgc.p_cell_play_inf[i].i_cat );
344 GETC( &pgc.p_cell_play_inf[i].i_still_time );
345 GETC( &pgc.p_cell_play_inf[i].i_com_nb );
346 GETL( &pgc.p_cell_play_inf[i].i_play_time );
347 GETL( &pgc.p_cell_play_inf[i].i_entry_sector );
348 GETL( &pgc.p_cell_play_inf[i].i_first_ilvu_vobu_esector );
349 GETL( &pgc.p_cell_play_inf[i].i_lvobu_ssector );
350 GETL( &pgc.p_cell_play_inf[i].i_lsector );
353 /* Parsing of cell_pos_inf_map */
354 if( pgc.i_cell_pos_inf_sbyte )
356 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
357 + pgc.i_cell_pos_inf_sbyte, SEEK_SET );
358 pgc.p_cell_pos_inf = malloc( pgc.i_cell_nb *sizeof(cell_pos_inf_t) );
359 if( pgc.p_cell_pos_inf == NULL )
361 intf_ErrMsg( "Out of memory" );
365 for( i=0 ; i<pgc.i_cell_nb ; i++ )
367 GETS( &pgc.p_cell_pos_inf[i].i_vob_id );
369 GETC( &pgc.p_cell_pos_inf[i].i_cell_id );
376 /*****************************************************************************
377 * ReadUnit : Fills Menu Language Unit Table/ PGC Info Table
378 *****************************************************************************/
379 static pgci_inf_t ReadUnit( ifo_t* p_ifo )
383 off_t i_start = p_ifo->i_pos;
385 //fprintf( stderr, "Unit\n" );
387 GETS( &inf.i_srp_nb );
389 GETL( &inf.i_lu_ebyte );
390 inf.p_srp = malloc( inf.i_srp_nb *sizeof(pgci_srp_t) );
391 if( inf.p_srp == NULL )
393 intf_ErrMsg( "Out of memory" );
397 for( i=0 ; i<inf.i_srp_nb ; i++ )
399 GETC( &inf.p_srp[i].i_pgc_cat_mask );
400 GETC( &inf.p_srp[i].i_pgc_cat );
401 GETS( &inf.p_srp[i].i_par_mask );
402 GETL( &inf.p_srp[i].i_pgci_sbyte );
404 for( i=0 ; i<inf.i_srp_nb ; i++ )
406 p_ifo->i_pos = lseek( p_ifo->i_fd,
407 i_start + inf.p_srp[i].i_pgci_sbyte,
409 //fprintf( stderr, "Unit: PGC %d\n", i );
410 inf.p_srp[i].pgc = ReadPGC( p_ifo );
416 /*****************************************************************************
417 * ReadUnitTable : Fills the PGCI Unit structure.
418 *****************************************************************************/
419 static pgci_ut_t ReadUnitTable( ifo_t* p_ifo )
423 off_t i_start = p_ifo->i_pos;
425 //fprintf( stderr, "Unit Table\n" );
427 GETS( &pgci.i_lu_nb );
429 GETL( &pgci.i_ebyte );
430 pgci.p_lu = malloc( pgci.i_lu_nb *sizeof(pgci_lu_t) );
431 if( pgci.p_lu == NULL )
433 intf_ErrMsg( "Out of memory" );
437 for( i=0 ; i<pgci.i_lu_nb ; i++ )
439 GET( pgci.p_lu[i].ps_lang_code, 2 );
441 GETC( &pgci.p_lu[i].i_existence_mask );
442 GETL( &pgci.p_lu[i].i_lu_sbyte );
444 pgci.p_pgci_inf = malloc( pgci.i_lu_nb *sizeof(pgci_inf_t) );
445 if( pgci.p_pgci_inf == NULL )
447 intf_ErrMsg( "Out of memory" );
451 for( i=0 ; i<pgci.i_lu_nb ; i++ )
453 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start +
454 pgci.p_lu[i].i_lu_sbyte,
456 pgci.p_pgci_inf[i] = ReadUnit( p_ifo );
462 /*****************************************************************************
463 * ReadCellInf : Fills the Cell Information structure.
464 *****************************************************************************/
465 static c_adt_t ReadCellInf( ifo_t* p_ifo )
468 off_t i_start = p_ifo->i_pos;
471 //fprintf( stderr, "CELL ADD\n" );
473 GETS( &c_adt.i_vob_nb );
475 GETL( &c_adt.i_ebyte );
477 ( i_start + c_adt.i_ebyte + 1 - p_ifo->i_pos ) / sizeof(cell_inf_t);
478 c_adt.p_cell_inf = malloc( c_adt.i_cell_nb *sizeof(cell_inf_t) );
479 if( c_adt.p_cell_inf == NULL )
481 intf_ErrMsg( "Out of memory" );
485 for( i = 0 ; i < c_adt.i_cell_nb ; i++ )
487 GETS( &c_adt.p_cell_inf[i].i_vob_id );
488 GETC( &c_adt.p_cell_inf[i].i_cell_id );
490 GETL( &c_adt.p_cell_inf[i].i_ssector );
491 GETL( &c_adt.p_cell_inf[i].i_esector );
497 /*****************************************************************************
498 * ReadMap : Fills the VOBU Map structure.
499 *****************************************************************************/
500 static vobu_admap_t ReadMap( ifo_t* p_ifo )
504 off_t i_start = p_ifo->i_pos;
506 //fprintf( stderr, "VOBU ADMAP\n" );
508 GETL( &map.i_ebyte );
509 i_max = ( i_start + map.i_ebyte + 1 - p_ifo->i_pos ) / sizeof(u32);
510 map.pi_vobu_ssector = malloc( i_max *sizeof(u32) );
511 for( i=0 ; i<i_max ; i++ )
513 GETL( &map.pi_vobu_ssector[i] );
520 * Video Manager Information Processing.
521 * This is what is contained in video_ts.ifo.
524 /*****************************************************************************
525 * ReadVMGInfMat : Fills the Management Information structure.
526 *****************************************************************************/
527 static vmgi_mat_t ReadVMGInfMat( ifo_t* p_ifo )
531 // off_t i_start = p_ifo->i_pos;
533 //fprintf( stderr, "VMGI\n" );
535 GET( mat.psz_id , 12 );
536 mat.psz_id[12] = '\0';
537 GETL( &mat.i_lsector );
539 GETL( &mat.i_i_lsector );
541 GETC( &mat.i_spec_ver );
543 GETS( &mat.i_vol_nb );
545 GETC( &mat.i_disc_side );
547 GETS( &mat.i_tts_nb );
548 GET( mat.ps_provider_id, 32 );
549 GETLL( &mat.i_pos_code );
551 GETL( &mat.i_i_mat_ebyte );
552 GETL( &mat.i_fp_pgc_sbyte );
554 GETL( &mat.i_vobs_ssector );
555 GETL( &mat.i_ptt_srpt_ssector );
556 GETL( &mat.i_pgci_ut_ssector );
557 GETL( &mat.i_ptl_mait_ssector );
558 GETL( &mat.i_vts_atrt_ssector );
559 GETL( &mat.i_txtdt_mg_ssector );
560 GETL( &mat.i_c_adt_ssector );
561 GETL( &mat.i_vobu_admap_ssector );
563 GETS( &mat.i_video_atrt );
565 GETC( &mat.i_audio_nb );
566 //fprintf( stderr, "vmgi audio nb : %d\n", mat.i_audio_nb );
567 for( i=0 ; i < 8 ; i++ )
569 GETLL( &mat.pi_audio_atrt[i] );
572 GETC( &mat.i_subpic_nb );
573 //fprintf( stderr, "vmgi subpic nb : %d\n", mat.i_subpic_nb );
574 for( i=0 ; i < mat.i_subpic_nb ; i++ )
576 GET( &mat.pi_subpic_atrt[i], 6 );
577 /* FIXME : take care of endianness */
583 /*****************************************************************************
584 * ReadVMGTitlePointer : Fills the Part Of Title Search Pointer structure.
585 *****************************************************************************/
586 static vmg_ptt_srpt_t ReadVMGTitlePointer( ifo_t* p_ifo )
590 // off_t i_start = p_ifo->i_pos;
592 //fprintf( stderr, "PTR\n" );
594 GETS( &ptr.i_ttu_nb );
595 //fprintf( stderr, "PTR: TTU nb %d\n", ptr.i_ttu_nb );
597 GETL( &ptr.i_ebyte );
599 ptr.p_tts = malloc( ptr.i_ttu_nb *sizeof(tts_t) );
600 if( ptr.p_tts == NULL )
602 intf_ErrMsg( "Out of memory" );
606 for( i=0 ; i<ptr.i_ttu_nb ; i++ )
608 GETC( &ptr.p_tts[i].i_play_type );
609 GETC( &ptr.p_tts[i].i_angle_nb );
610 GETS( &ptr.p_tts[i].i_ptt_nb );
611 GETS( &ptr.p_tts[i].i_parental_id );
612 GETC( &ptr.p_tts[i].i_tts_nb );
613 GETC( &ptr.p_tts[i].i_vts_ttn );
614 GETL( &ptr.p_tts[i].i_ssector );
615 //fprintf( stderr, "PTR: %d %d %d\n", ptr.p_tts[i].i_ptt_nb, ptr.p_tts[i].i_tts_nb,ptr.p_tts[i].i_vts_ttn );
621 /*****************************************************************************
622 * ReadParentalInf : Fills the Parental Management structure.
623 *****************************************************************************/
624 static vmg_ptl_mait_t ReadParentalInf( ifo_t* p_ifo )
628 off_t i_start = p_ifo->i_pos;
630 //fprintf( stderr, "PTL\n" );
632 GETS( &par.i_country_nb );
633 GETS( &par.i_vts_nb );
634 GETL( &par.i_ebyte );
635 par.p_ptl_desc = malloc( par.i_country_nb *sizeof(vmg_ptl_mai_desc_t) );
636 if( par.p_ptl_desc == NULL )
638 intf_ErrMsg( "Out of memory" );
642 for( i=0 ; i<par.i_country_nb ; i++ )
644 GET( par.p_ptl_desc[i].ps_country_code, 2 );
646 GETS( &par.p_ptl_desc[i].i_ptl_mai_sbyte );
649 par.p_ptl_mask = malloc( par.i_country_nb *sizeof(vmg_ptl_mask_t) );
650 if( par.p_ptl_mask == NULL )
652 intf_ErrMsg( "Out of memory" );
656 for( i=0 ; i<par.i_country_nb ; i++ )
658 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start +
659 par.p_ptl_desc[i].i_ptl_mai_sbyte, SEEK_SET );
660 for( j=1 ; j<=8 ; j++ )
662 par.p_ptl_mask[i].ppi_ptl_mask[j] =
663 malloc( par.i_vts_nb *sizeof(u16) );
664 if( par.p_ptl_mask[i].ppi_ptl_mask[j] == NULL )
666 intf_ErrMsg( "Out of memory" );
670 for( k=0 ; k<par.i_vts_nb ; k++ )
672 GETS( &par.p_ptl_mask[i].ppi_ptl_mask[j][k] );
680 /*****************************************************************************
681 * ReadVTSAttr : Fills the structure about VTS attributes.
682 *****************************************************************************/
683 static vmg_vts_atrt_t ReadVTSAttr( ifo_t* p_ifo )
687 off_t i_start = p_ifo->i_pos;
689 //fprintf( stderr, "VTS ATTR\n" );
691 GETS( &atrt.i_vts_nb );
692 //fprintf( stderr, "VTS ATTR Nb: %d\n", atrt.i_vts_nb );
694 GETL( &atrt.i_ebyte );
695 atrt.pi_vts_atrt_sbyte = malloc( atrt.i_vts_nb *sizeof(u32) );
696 if( atrt.pi_vts_atrt_sbyte == NULL )
698 intf_ErrMsg( "Out of memory" );
702 for( i=0 ; i<atrt.i_vts_nb ; i++ )
704 GETL( &atrt.pi_vts_atrt_sbyte[i] );
706 atrt.p_vts_atrt = malloc( atrt.i_vts_nb *sizeof(vts_atrt_t) );
707 if( atrt.p_vts_atrt == NULL )
709 intf_ErrMsg( "Out of memory" );
713 for( i=0 ; i<atrt.i_vts_nb ; i++ )
715 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start +
716 atrt.pi_vts_atrt_sbyte[i],
718 GETL( &atrt.p_vts_atrt[i].i_ebyte );
719 GETL( &atrt.p_vts_atrt[i].i_cat_app_type );
720 GETS( &atrt.p_vts_atrt[i].i_vtsm_video_atrt );
722 GETC( &atrt.p_vts_atrt[i].i_vtsm_audio_nb );
723 //fprintf( stderr, "m audio nb : %d\n", atrt.p_vts_atrt[i].i_vtsm_audio_nb );
724 for( j=0 ; j<8 ; j++ )
726 GETLL( &atrt.p_vts_atrt[i].pi_vtsm_audio_atrt[j] );
729 GETC( &atrt.p_vts_atrt[i].i_vtsm_subpic_nb );
730 //fprintf( stderr, "m subp nb : %d\n", atrt.p_vts_atrt[i].i_vtsm_subpic_nb );
731 for( j=0 ; j<28 ; j++ )
733 GET( &atrt.p_vts_atrt[i].pi_vtsm_subpic_atrt[j], 6 );
734 /* FIXME : Fix endianness issue here */
737 GETS( &atrt.p_vts_atrt[i].i_vtstt_video_atrt );
739 GETL( &atrt.p_vts_atrt[i].i_vtstt_audio_nb );
740 //fprintf( stderr, "tt audio nb : %d\n", atrt.p_vts_atrt[i].i_vtstt_audio_nb );
741 for( j=0 ; j<8 ; j++ )
743 GETLL( &atrt.p_vts_atrt[i].pi_vtstt_audio_atrt[j] );
746 GETC( &atrt.p_vts_atrt[i].i_vtstt_subpic_nb );
747 //fprintf( stderr, "tt subp nb : %d\n", atrt.p_vts_atrt[i].i_vtstt_subpic_nb );
748 for( j=0 ; j<28/*atrt.p_vts_atrt[i].i_vtstt_subpic_nb*/ ; j++ )
750 GET( &atrt.p_vts_atrt[i].pi_vtstt_subpic_atrt[j], 6 );
751 /* FIXME : Fix endianness issue here */
758 /*****************************************************************************
759 * ReadVMG : Parse video_ts.ifo file to fill the Video Manager structure.
760 *****************************************************************************/
761 static vmg_t ReadVMG( ifo_t* p_ifo )
765 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off, SEEK_SET);
766 vmg.mat = ReadVMGInfMat( p_ifo );
767 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
768 vmg.mat.i_fp_pgc_sbyte, SEEK_SET );
769 vmg.pgc = ReadPGC( p_ifo );
770 if( vmg.mat.i_ptt_srpt_ssector )
772 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
773 vmg.mat.i_ptt_srpt_ssector *DVD_LB_SIZE,
775 vmg.ptt_srpt = ReadVMGTitlePointer( p_ifo );
777 if( vmg.mat.i_pgci_ut_ssector )
779 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
780 vmg.mat.i_pgci_ut_ssector *DVD_LB_SIZE,
782 vmg.pgci_ut = ReadUnitTable( p_ifo );
784 if( vmg.mat.i_ptl_mait_ssector )
786 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
787 vmg.mat.i_ptl_mait_ssector *DVD_LB_SIZE,
789 vmg.ptl_mait = ReadParentalInf( p_ifo );
791 if( vmg.mat.i_vts_atrt_ssector )
793 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
794 vmg.mat.i_vts_atrt_ssector *DVD_LB_SIZE,
796 vmg.vts_atrt = ReadVTSAttr( p_ifo );
798 if( vmg.mat.i_c_adt_ssector )
800 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
801 vmg.mat.i_c_adt_ssector *DVD_LB_SIZE,
803 vmg.c_adt = ReadCellInf( p_ifo );
805 if( vmg.mat.i_vobu_admap_ssector )
807 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
808 vmg.mat.i_vobu_admap_ssector *DVD_LB_SIZE,
810 vmg.vobu_admap = ReadMap( p_ifo );
816 * Video Title Set Information Processing.
817 * This is what is contained in vts_*.ifo.
820 /*****************************************************************************
821 * ReadVTSInfMat : Fills the Title Set Information structure.
822 *****************************************************************************/
823 static vtsi_mat_t ReadVTSInfMat( ifo_t* p_ifo )
827 // off_t i_start = p_ifo->i_pos;
829 //fprintf( stderr, "VTSI\n" );
831 GET( mat.psz_id , 12 );
832 mat.psz_id[12] = '\0';
833 GETL( &mat.i_lsector );
835 GETL( &mat.i_i_lsector );
837 GETC( &mat.i_spec_ver );
840 GETL( &mat.i_mat_ebyte );
842 GETL( &mat.i_m_vobs_ssector );
843 GETL( &mat.i_tt_vobs_ssector );
844 GETL( &mat.i_ptt_srpt_ssector );
845 GETL( &mat.i_pgcit_ssector );
846 GETL( &mat.i_m_pgci_ut_ssector );
847 GETL( &mat.i_tmap_ti_ssector );
848 GETL( &mat.i_m_c_adt_ssector );
849 GETL( &mat.i_m_vobu_admap_ssector );
850 GETL( &mat.i_c_adt_ssector );
851 GETL( &mat.i_vobu_admap_ssector );
853 GETS( &mat.i_m_video_atrt );
855 GETC( &mat.i_m_audio_nb );
856 for( i=0 ; i<8 ; i++ )
858 GETLL( &mat.pi_m_audio_atrt[i] );
861 GETC( &mat.i_m_subpic_nb );
862 for( i=0 ; i<28 ; i++ )
864 GET( &mat.pi_m_subpic_atrt[i], 6 );
865 /* FIXME : take care of endianness */
868 GETS( &mat.i_video_atrt );
870 GETC( &mat.i_audio_nb );
871 //fprintf( stderr, "vtsi audio nb : %d\n", mat.i_audio_nb );
872 for( i=0 ; i<8 ; i++ )
874 GETLL( &mat.pi_audio_atrt[i] );
877 GETC( &mat.i_subpic_nb );
878 //fprintf( stderr, "vtsi subpic nb : %d\n", mat.i_subpic_nb );
879 for( i=0 ; i<mat.i_subpic_nb ; i++ )
881 GET( &mat.pi_subpic_atrt[i], 6 );
882 /* FIXME : take care of endianness */
888 /*****************************************************************************
889 * ReadVTSTitlePointer : Fills the Part Of Title Search Pointer structure.
890 *****************************************************************************/
891 static vts_ptt_srpt_t ReadVTSTitlePointer( ifo_t* p_ifo )
895 off_t i_start = p_ifo->i_pos;
897 //fprintf( stderr, "VTS PTR\n" );
899 GETS( &ptr.i_ttu_nb );
900 //fprintf( stderr, "VTS PTR nb: %d\n", ptr.i_ttu_nb );
902 GETL( &ptr.i_ebyte );
903 ptr.pi_ttu_sbyte = malloc( ptr.i_ttu_nb *sizeof(u32) );
904 if( ptr.pi_ttu_sbyte == NULL )
906 intf_ErrMsg( "Out of memory" );
910 for( i=0 ; i<ptr.i_ttu_nb ; i++ )
912 GETL( &ptr.pi_ttu_sbyte[i] );
915 ptr.p_ttu = malloc( ptr.i_ttu_nb *sizeof(ttu_t) );
916 if( ptr.p_ttu == NULL )
918 intf_ErrMsg( "Out of memory" );
922 for( i=0 ; i<ptr.i_ttu_nb ; i++ )
924 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start +
925 ptr.pi_ttu_sbyte[i], SEEK_SET );
926 GETS( &ptr.p_ttu[i].i_pgc_nb );
927 GETS( &ptr.p_ttu[i].i_prg_nb );
928 //fprintf( stderr, "VTS %d PTR Pgc: %d Prg: %d\n", i,ptr.p_ttu[i].i_pgc_nb, ptr.p_ttu[i].i_prg_nb );
934 /*****************************************************************************
935 * ReadVTSTimeMap : Fills the time map table
936 *****************************************************************************/
937 static vts_tmap_ti_t ReadVTSTimeMap( ifo_t* p_ifo )
941 // off_t i_start = p_ifo->i_pos;
943 //fprintf( stderr, "TMAP\n" );
947 GETL( &tmap.i_ebyte );
948 tmap.pi_sbyte = malloc( tmap.i_nb *sizeof(u32) );
949 if( tmap.pi_sbyte == NULL )
951 intf_ErrMsg( "Out of memory" );
955 for( i=0 ; i<tmap.i_nb ; i++ )
957 GETL( &tmap.pi_sbyte[i] );
959 tmap.p_tmap = malloc( tmap.i_nb *sizeof(tmap_t) );
960 if( tmap.p_tmap == NULL )
962 intf_ErrMsg( "Out of memory" );
966 for( i=0 ; i<tmap.i_nb ; i++ )
968 GETC( &tmap.p_tmap[i].i_time_unit );
970 GETS( &tmap.p_tmap[i].i_entry_nb );
971 tmap.p_tmap[i].pi_sector =
972 malloc( tmap.p_tmap[i].i_entry_nb *sizeof(u32) );
973 if( tmap.p_tmap[i].pi_sector == NULL )
975 intf_ErrMsg( "Out of memory" );
979 for( j=0 ; j<tmap.p_tmap[i].i_entry_nb ; j++ )
981 GETL( &tmap.p_tmap[i].pi_sector[j] );
989 /*****************************************************************************
990 * IfoReadVTS : Parse vts*.ifo files to fill the Video Title Set structure.
991 *****************************************************************************/
992 int IfoReadVTS( ifo_t* p_ifo )
998 intf_WarnMsg( 2, "ifo: initializing VTS %d", p_ifo->i_title );
1000 i_title = p_ifo->i_title;
1001 i_off = (off_t)( p_ifo->vmg.ptt_srpt.p_tts[i_title].i_ssector ) *DVD_LB_SIZE
1004 p_ifo->i_pos = lseek( p_ifo->i_fd, i_off, SEEK_SET );
1006 vts.i_pos = p_ifo->i_pos;
1008 vts.mat = ReadVTSInfMat( p_ifo );
1009 if( vts.mat.i_ptt_srpt_ssector )
1011 p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
1012 vts.mat.i_ptt_srpt_ssector *DVD_LB_SIZE,
1014 vts.ptt_srpt = ReadVTSTitlePointer( p_ifo );
1016 if( vts.mat.i_m_pgci_ut_ssector )
1018 p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
1019 vts.mat.i_m_pgci_ut_ssector *DVD_LB_SIZE,
1021 vts.pgci_ut = ReadUnitTable( p_ifo );
1023 if( vts.mat.i_pgcit_ssector )
1025 p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
1026 vts.mat.i_pgcit_ssector *DVD_LB_SIZE,
1028 vts.pgci_ti = ReadUnit( p_ifo );
1030 if( vts.mat.i_tmap_ti_ssector )
1032 p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
1033 vts.mat.i_tmap_ti_ssector *DVD_LB_SIZE,
1035 vts.tmap_ti = ReadVTSTimeMap( p_ifo );
1037 if( vts.mat.i_m_c_adt_ssector )
1039 p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
1040 vts.mat.i_m_c_adt_ssector *DVD_LB_SIZE,
1042 vts.m_c_adt = ReadCellInf( p_ifo );
1044 if( vts.mat.i_m_vobu_admap_ssector )
1046 p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
1047 vts.mat.i_m_vobu_admap_ssector *DVD_LB_SIZE,
1049 vts.m_vobu_admap = ReadMap( p_ifo );
1051 if( vts.mat.i_c_adt_ssector )
1053 p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
1054 vts.mat.i_c_adt_ssector *DVD_LB_SIZE,
1056 vts.c_adt = ReadCellInf( p_ifo );
1058 if( vts.mat.i_vobu_admap_ssector )
1060 p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
1061 vts.mat.i_vobu_admap_ssector *DVD_LB_SIZE,
1063 vts.vobu_admap = ReadMap( p_ifo );
1072 * DVD Information Management
1075 /*****************************************************************************
1076 * IfoRead : Function that fills structure and calls specified functions
1078 *****************************************************************************/
1079 void IfoRead( ifo_t* p_ifo )
1084 /* Video Title Sets initialization */
1085 p_ifo->p_vts = malloc( p_ifo->vmg.mat.i_tts_nb *sizeof(vts_t) );
1086 if( p_ifo->p_vts == NULL )
1088 intf_ErrMsg( "Out of memory" );
1093 for( i=0 ; i<p_ifo->vmg.mat.i_tts_nb ; i++ )
1096 intf_WarnMsg( 2, "ifo: initializing VTS %d", i+1 );
1098 i_off = (off_t)( p_ifo->vmg.ptt_srpt.p_tts[i].i_ssector ) *DVD_LB_SIZE
1101 p_ifo->i_pos = lseek( p_ifo->i_fd, i_off, SEEK_SET );
1103 /* FIXME : I really don't know why udf find file
1104 * does not give the exact beginning of file */
1106 p_ifo->p_vts[i] = ReadVTS( p_ifo );
1114 * IFO virtual machine : a set of commands that give the
1115 * interactive behaviour of the dvd
1119 #define OP_VAL_16(i) (ntoh16( com.data.pi_16[i]))
1120 #define OP_VAL_8(i) ((com.data.pi_8[i]))
1122 static char ifo_reg[][80]=
1124 "Menu_Language_Code",
1126 "SubPicture_Stream_#",
1132 "Highlighted_Button_#",
1135 "Karaoke_audio_mixing_mode",
1136 "Parental_mgmt_country_code",
1140 "Audio_language_code_setting",
1141 "Audio_language_extension_code",
1142 "SPU_language_code_setting",
1143 "SPU_language_extension_code",
1144 "?Player_Regional_Code",
1150 static char * IfoMath( char val )
1152 static char math_op[][10] =
1172 return (char *) math_op[val & 0x0f];
1176 char ifo_cmp[][10] =
1188 char ifo_parental[][10] =
1200 char ifo_menu_id[][80] =
1212 char * IfoMenuName( char index )
1214 return ifo_menu_id[index&0x07];
1217 static void IfoRegister( u16 i_data, u8 i_direct)
1221 if( 0/*isalpha( i_data >> 8 & 0xff )*/ )
1223 printf("'%c%c'", i_data>>8&0xff, i_data&0xff);
1227 printf("0x%02x", i_data);
1242 printf("s[%s]", ifo_reg[i_data]);
1255 printf("r[0x%02x]", i_data);
1261 static void IfoAdvanced( u8 *pi_code )
1263 u8 i_cmd = pi_code[0];
1269 printf( " Highlight button %d; ", pi_code[1]>>2 );
1274 printf( " Illegal " );
1279 printf( "ReSuME %d", pi_code[7] );
1281 else if( ( i_cmd & 0x06) == 0x02 )
1283 printf ("Link to %s cell ", ( i_cmd & 0x01 ) ? "prev" : "next");
1287 printf( "advanced (0x%02x) ", i_cmd );
1292 static void IfoJmp( ifo_command_t com )
1297 switch( com.i_sub_cmd )
1303 printf( "VTS 0x%02x", OP_VAL_8(3) );
1306 printf( "This VTS Title 0x%02x", OP_VAL_8(3) );
1309 printf( "This VTS Title 0x%02x Part 0x%04x",
1311 OP_VAL_8(0)<<8|OP_VAL_8(1));
1315 printf ("in SystemSpace ");
1316 switch (OP_VAL_8(3)>>4) {
1318 printf ("to play first PGC");
1321 printf ("to menu \"%s\"", decode_menuname (OP_VAL_8(3)));
1325 printf ("to VTS 0x%02x and TTN 0x%02x", OP_VAL_8(1), OP_VAL_8(2));
1328 printf ("to VMGM PGC number 0x%02x", OP_VAL_8(0)<<8 | OP_VAL_8(1));
1331 printf ("vts 0x%02x lu 0x%02x menu \"%s\"", OP_VAL_8(2), OP_VAL_8(1), decode_menuname (OP_VAL_8(3)));
1334 switch( OP_VAL_8(3)>>6 )
1337 printf( "to play first PGC" );
1340 printf( "to VMG title menu (?)" );
1343 printf( "vts 0x%02x lu 0x%02x menu \"%s\"",
1346 IfoMenuName( OP_VAL_8(3)&0xF ) );
1349 printf( "vmg pgc 0x%04x (?)", ( OP_VAL_8(0)<<8) | OP_VAL_8(1) );
1356 switch(OP_VAL_8(3)>>4) {
1358 printf ("system first pgc");
1361 printf ("system title menu");
1364 printf ("system menu \"%s\"", decode_menuname (OP_VAL_8(3)));
1367 printf ("system vmg pgc %02x ????", OP_VAL_8(0)<<8|OP_VAL_8(1));
1370 printf ("system lu 0x%02x menu \"%s\"", OP_VAL_8(2), decode_menuname (OP_VAL_8(3)));
1373 printf ("system vmg pgc 0x%02x", OP_VAL_8(0)<<8|OP_VAL_8(1));
1377 // OP_VAL_8(2) is number of cell
1378 // it is processed BEFORE switch
1379 // under some conditions, it is ignored
1380 // I don't understand exactly what it means
1381 printf( " ( spec cell 0x%02X ) ", OP_VAL_8(2) );
1383 switch( OP_VAL_8(3)>>6 )
1386 printf( "to FP PGC" );
1389 printf( "to VMG root menu (?)" );
1392 printf( "to VTS menu \"%s\" (?)",
1393 IfoMenuName(OP_VAL_8(3)&0xF) );
1396 printf( "vmg pgc 0x%02x (?)", (OP_VAL_8(0)<<8)|OP_VAL_8(1) );
1404 static void IfoLnk( ifo_command_t com )
1406 u16 i_button=OP_VAL_8(4)>>2;
1410 switch( com.i_sub_cmd )
1413 IfoAdvanced( &OP_VAL_8(4) );
1417 printf( "PGC 0x%02x", OP_VAL_16(2) );
1421 printf( "PTT 0x%02x", OP_VAL_16(2) );
1425 printf( "Program 0x%02x this PGC", OP_VAL_8(5) );
1429 printf( "Cell 0x%02x this PGC", OP_VAL_8(5) );
1437 printf( ", Highlight 0x%02x", OP_VAL_8(4)>>2 );
1442 void IfoSetSystem( ifo_command_t com )
1449 for( i=1; i<=3; i++ )
1451 if( OP_VAL_8(i)&0x80 )
1455 printf ("s[%s] = 0x%02x;", ifo_reg[i], OP_VAL_8(i)&0xf);
1459 printf ("s[%s] = r[0x%02x];", ifo_reg[i], OP_VAL_8(i)&0xf);
1465 if(OP_VAL_8(1]&0x80)
1466 printf ("s[%s] = 0x%02x;", reg_name[1], OP_VAL_8(1]&0xf);
1467 if(OP_VAL_8(2)&0x80)
1468 //DENT: lwhat about 0x7f here ???
1469 printf ("s[%s] = 0x%02x;", reg_name[2], OP_VAL_8(2)&0x7f);
1470 if(OP_VAL_8(3)&0x80)
1471 printf ("s[%s] = 0x%02x;", reg_name[3], OP_VAL_8(3)&0xf);
1473 if(OP_VAL_8(1)&0x80)
1474 printf ("s[%s] = r[0x%02x];", reg_name[1], OP_VAL_8(1)&0xf);
1475 if(OP_VAL_8(2)&0x80)
1476 printf ("s[%s] = r[0x%02x];", reg_name[2], OP_VAL_8(2)&0xf);
1477 if(OP_VAL_8(3)&0x80)
1478 printf ("s[%s] = r[0x%02x];", reg_name[3], OP_VAL_8(3)&0xf);
1486 printf( "s[%s] = 0x%02x", ifo_reg[9], OP_VAL_16(0) );
1490 printf( "s[%s] = r[0x%02x]", ifo_reg[9], OP_VAL_8(1)&0x0f );
1493 printf( "s[%s] = (s[%s]&0x7FFF)|0x%02x",
1494 ifo_reg[10], ifo_reg[10], OP_VAL_16(1)&0x8000);
1499 printf( "r[0x%02x] = 0x%02x", OP_VAL_8(3)&0x0f, OP_VAL_16(0) );
1503 printf ("r[r[0x%02x]] = r[0x%02x]",
1504 OP_VAL_8(3)&0x0f, OP_VAL_8(1)&0x0f);
1508 //actually only bits 00011100 00011100 are set
1511 printf ("s[%s] = 0x%02x", ifo_reg[11], OP_VAL_16(1));
1515 printf ("s[%s] = r[0x%02x]", ifo_reg[11], OP_VAL_8(3)&0x0f );
1520 //s[%s]=(r[%s]&0x3FF) | (0x%02x << 0xA);
1521 //but it is way too ugly
1524 printf( "s[%s] = 0x%02x", ifo_reg[8], OP_VAL_8(2)>>2 );
1528 printf( "s[%s] = r[0x%02x]", ifo_reg[8], OP_VAL_8(3)&0x0f );
1536 static void IfoSet( ifo_command_t com )
1538 IfoRegister( OP_VAL_16(0), 0 );
1539 printf( " %s ", IfoMath( com.i_cmd ) );
1540 IfoRegister( OP_VAL_16(1), com.i_direct );
1543 /*****************************************************************************
1544 * CommandRead : translates the command strings in ifo into command
1546 *****************************************************************************/
1547 void CommandRead( ifo_command_t com )
1549 u8* pi_code = (u8*)(&com);
1551 switch( com.i_type )
1564 printf ("if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
1565 ifo_cmp[com.i_cmp]);
1566 IfoRegister (OP_VAL_16(1), com.i_dir_cmp);
1571 switch( com.i_sub_cmd )
1574 printf( "goto Line 0x%02x", OP_VAL_16(2) );
1578 printf( "stop VM" );
1582 printf( "Set Parental Level To %s and goto Line 0x%02x",
1583 ifo_parental[OP_VAL_8(4)&0x7],
1588 printf( "Illegal" );
1607 printf( "if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f,
1608 ifo_cmp[com.i_cmp] );
1609 IfoRegister( OP_VAL_8(5), 0 );
1620 printf( "if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
1621 ifo_cmp[com.i_cmp] );
1622 IfoRegister( OP_VAL_16(1), com.i_dir_cmp );
1636 IfoSetSystem( com );
1638 else if( com.i_cmp && !com.i_sub_cmd )
1640 printf ("if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f, ifo_cmp[com.i_cmp]);
1641 IfoRegister( OP_VAL_8(5), 0 );
1643 IfoSetSystem( com );
1645 else if( !com.i_cmp && com.i_sub_cmd )
1648 IfoSetSystem( com );
1664 else if( com.i_cmp && !com.i_sub_cmd )
1666 printf ("if (r[0x%02x] %s ", OP_VAL_8(0)&0x0f, ifo_cmp[com.i_cmp]);
1667 IfoRegister( OP_VAL_16(2), com.i_dir_cmp );
1671 else if( !com.i_cmp && com.i_sub_cmd )
1685 * math command on r[opcode[1]] and
1686 * direct?be2me_16(OP_VAL_8(0)):reg[OP_VAL_8(1)] is executed
1687 * ( unless command is swap; then r[opcode[1]] and r[OP_VAL_8(1)]
1689 * boolean operation cmp on r[opcode[1]] and
1690 * dir_cmp?be2me_16(OP_VAL_8(1)[1]):reg[OP_VAL_8(3)] is executed
1691 * on true result, buttons(c[6], c[7]) is called
1692 * problem is 'what is buttons()'
1695 printf( "r[0x%X] ", pi_code[1] );
1696 printf( " %s ", IfoMath( com.i_cmd ) );
1697 if( com.i_cmd == 2 )
1699 printf( "r[0x%X] ", OP_VAL_8(1) );
1703 IfoRegister( OP_VAL_16(0), com.i_direct );
1707 printf( "if ( r[%d] %s ", pi_code[1], ifo_cmp[com.i_cmp] );
1708 IfoRegister( OP_VAL_8(1), com.i_dir_cmp );
1709 printf( " ) then {" );
1710 IfoAdvanced( &OP_VAL_8(4) );
1715 * opposite to case 4: boolean, math and buttons.
1721 if( !com.i_direct && com.i_dir_cmp )
1723 printf( "0x%X", OP_VAL_16(1) );
1727 IfoRegister( OP_VAL_8(3), 0 );
1728 if( OP_VAL_8(3)&0x80 )
1730 printf( "s[%s]", ifo_reg[OP_VAL_8(3)&0x1F] );
1734 printf( "r[0x%X]", OP_VAL_8(3)&0x1F);
1735 // 0x1F is either not a mistake,
1736 // or Microsoft programmer's mistake!!!
1740 printf( " %s r[0x%X] ", ifo_cmp[com.i_cmp],
1741 com.i_direct ? OP_VAL_8(2) : OP_VAL_8(1) );
1742 printf( " ) then {" );
1743 printf( "r[0x%X] ", pi_code[1] & 0xF );
1744 printf( " %s ", IfoMath( com.i_cmd ) );
1746 if( com.i_cmd == 0x02 ) // swap
1748 printf("r[0x%X] ", OP_VAL_8(0)&0x1F);
1754 printf( "0x%X", OP_VAL_16(0) );
1758 if( OP_VAL_8(0) & 0x80 )
1760 printf("s[%s]", ifo_reg[OP_VAL_8(0) & 0x1F] );
1764 printf("r[0x%X]", OP_VAL_8(0) & 0x1F );
1770 IfoAdvanced( &OP_VAL_8(4) );
1776 printf( "Unknown Command\n" );
1783 /*****************************************************************************
1784 * CommandPrint : print in clear text (I hope so !) what a command does
1785 *****************************************************************************/
1786 void CommandPrint( ifo_t ifo )