1 /*****************************************************************************
2 * dvd_ifo.c: Functions for ifo parsing
3 *****************************************************************************
4 * Copyright (C) 1999-2001 VideoLAN
5 * $Id: dvd_ifo.c,v 1.15 2001/03/06 10:21:59 massiot 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 *****************************************************************************/
47 #include "input_dvd.h"
52 static vmg_t ReadVMG ( ifo_t* );
53 void CommandRead( ifo_command_t );
59 /*****************************************************************************
60 * IfoInit : Creates an ifo structure and prepares for parsing directly
62 *****************************************************************************/
63 ifo_t IfoInit( int i_fd )
68 /* If we are here the dvd device has already been opened */
71 i_lba = UDFFindFile( i_fd, "/VIDEO_TS/VIDEO_TS.IFO");
73 ifo.i_off = (off_t)(i_lba) * DVD_LB_SIZE;
74 ifo.i_pos = lseek( ifo.i_fd, ifo.i_off, SEEK_SET );
76 /* Video Manager Initialization */
77 intf_WarnMsg( 2, "ifo: initializing VMG" );
78 ifo.vmg = ReadVMG( &ifo );
83 /*****************************************************************************
84 * IfoEnd : Frees all the memory allocated to ifo structures
85 *****************************************************************************/
86 void IfoEnd( ifo_t* p_ifo )
91 /* Free structures from video title sets */
92 for( j=0 ; j<p_ifo->vmg.mat.i_tts_nb ; j++ )
94 free( p_ifo->p_vts[j].vobu_admap.pi_vobu_ssector );
95 free( p_ifo->p_vts[j].c_adt.p_cell_inf );
96 free( p_ifo->p_vts[j].m_vobu_admap.pi_vobu_ssector );
97 free( p_ifo->p_vts[j].m_c_adt.p_cell_inf );
98 for( i=0 ; i<p_ifo->p_vts[j].tmap_ti.i_nb ; i++ )
100 free( p_ifo->p_vts[j].tmap_ti.p_tmap[i].pi_sector );
102 free( p_ifo->p_vts[j].tmap_ti.pi_sbyte );
103 free( p_ifo->p_vts[j].tmap_ti.p_tmap );
104 free( p_ifo->p_vts[j].pgci_ti.p_srp );
105 for( i=0 ; i<p_ifo->p_vts[j].pgci_ut.i_lu_nb ; i++ )
107 free( p_ifo->p_vts[j].pgci_ut.p_pgci_inf[i].p_srp );
109 free( p_ifo->p_vts[j].pgci_ut.p_pgci_inf );
110 free( p_ifo->p_vts[j].pgci_ut.p_lu );
113 free( p_ifo->p_vts );
115 /* Free structures from video manager */
116 free( p_ifo->vmg.vobu_admap.pi_vobu_ssector );
117 free( p_ifo->vmg.c_adt.p_cell_inf );
118 for( i=0 ; i<p_ifo->vmg.pgci_ut.i_lu_nb ; i++ )
120 free( p_ifo->vmg.pgci_ut.p_pgci_inf[i].p_srp );
122 free( p_ifo->vmg.pgci_ut.p_pgci_inf );
123 free( p_ifo->vmg.pgci_ut.p_lu );
124 for( i=1 ; i<=8 ; i++ )
126 free( p_ifo->vmg.ptl_mait.p_ptl_mask->ppi_ptl_mask[i] );
128 free( p_ifo->vmg.ptl_mait.p_ptl_desc );
129 free( p_ifo->vmg.ptl_mait.p_ptl_mask );
130 free( p_ifo->vmg.vts_atrt.pi_vts_atrt_sbyte );
131 free( p_ifo->vmg.vts_atrt.p_vts_atrt );
132 free( p_ifo->vmg.pgc.p_cell_pos_inf );
133 free( p_ifo->vmg.pgc.p_cell_play_inf );
134 free( p_ifo->vmg.pgc.prg_map.pi_entry_cell );
135 free( p_ifo->vmg.pgc.com_tab.p_cell_com );
136 free( p_ifo->vmg.pgc.com_tab.p_post_com );
137 free( p_ifo->vmg.pgc.com_tab.p_pre_com );
143 * Macros to process ifo files
146 #define GET( p_field , i_len ) \
148 read( p_ifo->i_fd , (p_field) , (i_len) ); \
149 /*fprintf(stderr, "Pos : %lld Val : %llx\n", \
150 (long long)(p_ifo->i_pos - i_start), \
151 (long long)*(p_field) ); */ \
152 p_ifo->i_pos += i_len; \
155 #define GETC( p_field ) \
157 read( p_ifo->i_fd , (p_field) , 1 ); \
158 /*fprintf(stderr, "Pos : %lld Value : %d\n", \
159 (long long)(p_ifo->i_pos - i_start), \
164 #define GETS( p_field ) \
166 read( p_ifo->i_fd , (p_field) , 2 ); \
167 *(p_field) = ntohs( *(p_field) ); \
168 /*fprintf(stderr, "Pos : %lld Value : %d\n", \
169 (long long)(p_ifo->i_pos - i_start), \
174 #define GETL( p_field ) \
176 read( p_ifo->i_fd , (p_field) , 4 ); \
177 *(p_field) = ntohl( *(p_field) ); \
178 /*fprintf(stderr, "Pos : %lld Value : %d\n", \
179 (long long)(p_ifo->i_pos - i_start), \
184 #define GETLL( p_field ) \
186 read( p_ifo->i_fd , (p_field) , 8 ); \
187 *(p_field) = ntoh64( *(p_field) ); \
188 /*fprintf(stderr, "Pos : %lld Value : %lld\n", \
189 (long long)(p_ifo->i_pos - i_start), \
194 #define FLUSH( i_len ) \
196 /*fprintf(stderr, "Pos : %lld\n", (long long)(p_ifo->i_pos - i_start));*/ \
197 p_ifo->i_pos = lseek( p_ifo->i_fd , \
198 p_ifo->i_pos + (i_len), SEEK_SET ); \
202 * Function common to Video Manager and Video Title set Processing
205 /*****************************************************************************
206 * ReadPGC : Fills the Program Chain structure.
207 *****************************************************************************/
208 #define GETCOMMAND( p_com ) \
210 read( p_ifo->i_fd , (p_com) , 8 ); \
211 /*fprintf(stderr, "Pos : %lld Type : %d direct : %d cmd : %d dircmp : %d cmp : %d subcmd : %d v0 : %d v2 : %d v4 : %d\n", \
212 (long long)(p_ifo->i_pos - i_start), \
213 (int)((p_com)->i_type), \
214 (int)((p_com)->i_direct), \
215 (int)((p_com)->i_cmd), \
216 (int)((p_com)->i_dir_cmp), \
217 (int)((p_com)->i_cmp), \
218 (int)((p_com)->i_sub_cmd), \
219 (int)((p_com)->data.pi_16[0]), \
220 (int)((p_com)->data.pi_16[1]), \
221 (int)((p_com)->data.pi_16[2]));*/ \
222 /* CommandRead( *(p_com) );*/ \
226 static pgc_t ReadPGC( ifo_t* p_ifo )
230 off_t i_start = p_ifo->i_pos;
232 //fprintf( stderr, "PGC\n" );
235 GETC( &pgc.i_prg_nb );
236 GETC( &pgc.i_cell_nb );
237 //fprintf( stderr, "PGC: Prg: %d Cell: %d\n", pgc.i_prg_nb, pgc.i_cell_nb );
238 GETL( &pgc.i_play_time );
239 GETL( &pgc.i_prohibited_user_op );
240 for( i=0 ; i<8 ; i++ )
242 GETS( &pgc.pi_audio_status[i] );
244 for( i=0 ; i<32 ; i++ )
246 GETL( &pgc.pi_subpic_status[i] );
248 GETS( &pgc.i_next_pgc_nb );
249 GETS( &pgc.i_prev_pgc_nb );
250 GETS( &pgc.i_goup_pgc_nb );
251 //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 );
252 GETC( &pgc.i_still_time );
253 GETC( &pgc.i_play_mode );
254 for( i=0 ; i<16 ; i++ )
256 GETL( &pgc.pi_yuv_color[i] );
257 /* FIXME : We have to erase the extra bit */
259 GETS( &pgc.i_com_tab_sbyte );
260 GETS( &pgc.i_prg_map_sbyte );
261 GETS( &pgc.i_cell_play_inf_sbyte );
262 GETS( &pgc.i_cell_pos_inf_sbyte );
264 /* Parsing of pgc_com_tab_t */
265 if( pgc.i_com_tab_sbyte )
267 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
268 + pgc.i_com_tab_sbyte, SEEK_SET );
269 GETS( &pgc.com_tab.i_pre_com_nb );
270 GETS( &pgc.com_tab.i_post_com_nb );
271 GETS( &pgc.com_tab.i_cell_com_nb );
273 if( pgc.com_tab.i_pre_com_nb )
275 pgc.com_tab.p_pre_com =
276 malloc(pgc.com_tab.i_pre_com_nb *sizeof(ifo_command_t));
277 if( pgc.com_tab.p_pre_com == NULL )
279 intf_ErrMsg( "Out of memory" );
283 for( i=0 ; i<pgc.com_tab.i_pre_com_nb ; i++ )
285 GETCOMMAND( &pgc.com_tab.p_pre_com[i] );
288 if( pgc.com_tab.i_post_com_nb )
290 pgc.com_tab.p_post_com =
291 malloc(pgc.com_tab.i_post_com_nb *sizeof(ifo_command_t));
292 if( pgc.com_tab.p_post_com == NULL )
294 intf_ErrMsg( "Out of memory" );
298 for( i=0 ; i<pgc.com_tab.i_post_com_nb ; i++ )
300 GETCOMMAND( &pgc.com_tab.p_post_com[i] );
303 if( pgc.com_tab.i_cell_com_nb )
305 pgc.com_tab.p_cell_com =
306 malloc(pgc.com_tab.i_cell_com_nb *sizeof(ifo_command_t));
307 if( pgc.com_tab.p_cell_com == NULL )
309 intf_ErrMsg( "Out of memory" );
313 for( i=0 ; i<pgc.com_tab.i_cell_com_nb ; i++ )
315 GETCOMMAND( &pgc.com_tab.p_cell_com[i] );
319 /* Parsing of pgc_prg_map_t */
320 if( pgc.i_prg_map_sbyte )
322 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
323 + pgc.i_prg_map_sbyte, SEEK_SET );
324 pgc.prg_map.pi_entry_cell = malloc( pgc.i_prg_nb *sizeof(u8) );
325 if( pgc.prg_map.pi_entry_cell == NULL )
327 intf_ErrMsg( "Out of memory" );
331 GET( pgc.prg_map.pi_entry_cell, pgc.i_prg_nb );
332 /* FIXME : check endianness here */
334 /* Parsing of cell_play_inf_t */
335 if( pgc.i_cell_play_inf_sbyte )
337 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
338 + pgc.i_cell_play_inf_sbyte, SEEK_SET );
339 pgc.p_cell_play_inf = malloc( pgc.i_cell_nb *sizeof(cell_play_inf_t) );
340 if( pgc.p_cell_play_inf == NULL )
342 intf_ErrMsg( "Out of memory" );
346 for( i=0 ; i<pgc.i_cell_nb ; i++ )
348 GETS( &pgc.p_cell_play_inf[i].i_cat );
349 GETC( &pgc.p_cell_play_inf[i].i_still_time );
350 GETC( &pgc.p_cell_play_inf[i].i_com_nb );
351 GETL( &pgc.p_cell_play_inf[i].i_play_time );
352 GETL( &pgc.p_cell_play_inf[i].i_entry_sector );
353 GETL( &pgc.p_cell_play_inf[i].i_first_ilvu_vobu_esector );
354 GETL( &pgc.p_cell_play_inf[i].i_lvobu_ssector );
355 GETL( &pgc.p_cell_play_inf[i].i_lsector );
358 /* Parsing of cell_pos_inf_map */
359 if( pgc.i_cell_pos_inf_sbyte )
361 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
362 + pgc.i_cell_pos_inf_sbyte, SEEK_SET );
363 pgc.p_cell_pos_inf = malloc( pgc.i_cell_nb *sizeof(cell_pos_inf_t) );
364 if( pgc.p_cell_pos_inf == NULL )
366 intf_ErrMsg( "Out of memory" );
370 for( i=0 ; i<pgc.i_cell_nb ; i++ )
372 GETS( &pgc.p_cell_pos_inf[i].i_vob_id );
374 GETC( &pgc.p_cell_pos_inf[i].i_cell_id );
381 /*****************************************************************************
382 * ReadUnit : Fills Menu Language Unit Table/ PGC Info Table
383 *****************************************************************************/
384 static pgci_inf_t ReadUnit( ifo_t* p_ifo )
388 off_t i_start = p_ifo->i_pos;
390 //fprintf( stderr, "Unit\n" );
392 GETS( &inf.i_srp_nb );
394 GETL( &inf.i_lu_ebyte );
395 inf.p_srp = malloc( inf.i_srp_nb *sizeof(pgci_srp_t) );
396 if( inf.p_srp == NULL )
398 intf_ErrMsg( "Out of memory" );
402 for( i=0 ; i<inf.i_srp_nb ; i++ )
404 GETC( &inf.p_srp[i].i_pgc_cat_mask );
405 GETC( &inf.p_srp[i].i_pgc_cat );
406 GETS( &inf.p_srp[i].i_par_mask );
407 GETL( &inf.p_srp[i].i_pgci_sbyte );
409 for( i=0 ; i<inf.i_srp_nb ; i++ )
411 p_ifo->i_pos = lseek( p_ifo->i_fd,
412 i_start + inf.p_srp[i].i_pgci_sbyte,
414 //fprintf( stderr, "Unit: PGC %d\n", i );
415 inf.p_srp[i].pgc = ReadPGC( p_ifo );
421 /*****************************************************************************
422 * ReadUnitTable : Fills the PGCI Unit structure.
423 *****************************************************************************/
424 static pgci_ut_t ReadUnitTable( ifo_t* p_ifo )
428 off_t i_start = p_ifo->i_pos;
430 //fprintf( stderr, "Unit Table\n" );
432 GETS( &pgci.i_lu_nb );
434 GETL( &pgci.i_ebyte );
435 pgci.p_lu = malloc( pgci.i_lu_nb *sizeof(pgci_lu_t) );
436 if( pgci.p_lu == NULL )
438 intf_ErrMsg( "Out of memory" );
442 for( i=0 ; i<pgci.i_lu_nb ; i++ )
444 GET( pgci.p_lu[i].ps_lang_code, 2 );
446 GETC( &pgci.p_lu[i].i_existence_mask );
447 GETL( &pgci.p_lu[i].i_lu_sbyte );
449 pgci.p_pgci_inf = malloc( pgci.i_lu_nb *sizeof(pgci_inf_t) );
450 if( pgci.p_pgci_inf == NULL )
452 intf_ErrMsg( "Out of memory" );
456 for( i=0 ; i<pgci.i_lu_nb ; i++ )
458 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start +
459 pgci.p_lu[i].i_lu_sbyte,
461 pgci.p_pgci_inf[i] = ReadUnit( p_ifo );
467 /*****************************************************************************
468 * ReadCellInf : Fills the Cell Information structure.
469 *****************************************************************************/
470 static c_adt_t ReadCellInf( ifo_t* p_ifo )
473 off_t i_start = p_ifo->i_pos;
476 //fprintf( stderr, "CELL ADD\n" );
478 GETS( &c_adt.i_vob_nb );
480 GETL( &c_adt.i_ebyte );
482 ( i_start + c_adt.i_ebyte + 1 - p_ifo->i_pos ) / sizeof(cell_inf_t);
483 c_adt.p_cell_inf = malloc( c_adt.i_cell_nb *sizeof(cell_inf_t) );
484 if( c_adt.p_cell_inf == NULL )
486 intf_ErrMsg( "Out of memory" );
490 for( i = 0 ; i < c_adt.i_cell_nb ; i++ )
492 GETS( &c_adt.p_cell_inf[i].i_vob_id );
493 GETC( &c_adt.p_cell_inf[i].i_cell_id );
495 GETL( &c_adt.p_cell_inf[i].i_ssector );
496 GETL( &c_adt.p_cell_inf[i].i_esector );
502 /*****************************************************************************
503 * ReadMap : Fills the VOBU Map structure.
504 *****************************************************************************/
505 static vobu_admap_t ReadMap( ifo_t* p_ifo )
509 off_t i_start = p_ifo->i_pos;
511 //fprintf( stderr, "VOBU ADMAP\n" );
513 GETL( &map.i_ebyte );
514 i_max = ( i_start + map.i_ebyte + 1 - p_ifo->i_pos ) / sizeof(u32);
515 map.pi_vobu_ssector = malloc( i_max *sizeof(u32) );
516 for( i=0 ; i<i_max ; i++ )
518 GETL( &map.pi_vobu_ssector[i] );
525 * Video Manager Information Processing.
526 * This is what is contained in video_ts.ifo.
529 /*****************************************************************************
530 * ReadVMGInfMat : Fills the Management Information structure.
531 *****************************************************************************/
532 static vmgi_mat_t ReadVMGInfMat( ifo_t* p_ifo )
537 // off_t i_start = p_ifo->i_pos;
539 //fprintf( stderr, "VMGI\n" );
541 GET( mat.psz_id , 12 );
542 mat.psz_id[12] = '\0';
543 GETL( &mat.i_lsector );
545 GETL( &mat.i_i_lsector );
547 GETC( &mat.i_spec_ver );
549 GETS( &mat.i_vol_nb );
551 GETC( &mat.i_disc_side );
553 GETS( &mat.i_tts_nb );
554 GET( mat.ps_provider_id, 32 );
555 GETLL( &mat.i_pos_code );
557 GETL( &mat.i_i_mat_ebyte );
558 GETL( &mat.i_fp_pgc_sbyte );
560 GETL( &mat.i_vobs_ssector );
561 GETL( &mat.i_ptt_srpt_ssector );
562 GETL( &mat.i_pgci_ut_ssector );
563 GETL( &mat.i_ptl_mait_ssector );
564 GETL( &mat.i_vts_atrt_ssector );
565 GETL( &mat.i_txtdt_mg_ssector );
566 GETL( &mat.i_c_adt_ssector );
567 GETL( &mat.i_vobu_admap_ssector );
569 // GETS( &mat.video_atrt );
572 GETC( &mat.i_audio_nb );
573 //fprintf( stderr, "vmgi audio nb : %d\n", mat.i_audio_nb );
574 for( i=0 ; i < 8 ; i++ )
579 GETC( &mat.i_subpic_nb );
580 //fprintf( stderr, "vmgi subpic nb : %d\n", mat.i_subpic_nb );
581 for( i=0 ; i < mat.i_subpic_nb ; i++ )
584 /* FIXME : take care of endianness */
590 /*****************************************************************************
591 * ReadVMGTitlePointer : Fills the Part Of Title Search Pointer structure.
592 *****************************************************************************/
593 static vmg_ptt_srpt_t ReadVMGTitlePointer( ifo_t* p_ifo )
597 // off_t i_start = p_ifo->i_pos;
599 //fprintf( stderr, "PTR\n" );
601 GETS( &ptr.i_ttu_nb );
602 //fprintf( stderr, "PTR: TTU nb %d\n", ptr.i_ttu_nb );
604 GETL( &ptr.i_ebyte );
606 ptr.p_tts = malloc( ptr.i_ttu_nb *sizeof(tts_t) );
607 if( ptr.p_tts == NULL )
609 intf_ErrMsg( "Out of memory" );
613 for( i=0 ; i<ptr.i_ttu_nb ; i++ )
615 GETC( &ptr.p_tts[i].i_play_type );
616 GETC( &ptr.p_tts[i].i_angle_nb );
617 GETS( &ptr.p_tts[i].i_ptt_nb );
618 GETS( &ptr.p_tts[i].i_parental_id );
619 GETC( &ptr.p_tts[i].i_tts_nb );
620 GETC( &ptr.p_tts[i].i_vts_ttn );
621 GETL( &ptr.p_tts[i].i_ssector );
622 //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 );
628 /*****************************************************************************
629 * ReadParentalInf : Fills the Parental Management structure.
630 *****************************************************************************/
631 static vmg_ptl_mait_t ReadParentalInf( ifo_t* p_ifo )
635 off_t i_start = p_ifo->i_pos;
637 //fprintf( stderr, "PTL\n" );
639 GETS( &par.i_country_nb );
640 GETS( &par.i_vts_nb );
641 GETL( &par.i_ebyte );
642 par.p_ptl_desc = malloc( par.i_country_nb *sizeof(vmg_ptl_mai_desc_t) );
643 if( par.p_ptl_desc == NULL )
645 intf_ErrMsg( "Out of memory" );
649 for( i=0 ; i<par.i_country_nb ; i++ )
651 GET( par.p_ptl_desc[i].ps_country_code, 2 );
653 GETS( &par.p_ptl_desc[i].i_ptl_mai_sbyte );
656 par.p_ptl_mask = malloc( par.i_country_nb *sizeof(vmg_ptl_mask_t) );
657 if( par.p_ptl_mask == NULL )
659 intf_ErrMsg( "Out of memory" );
663 for( i=0 ; i<par.i_country_nb ; i++ )
665 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start +
666 par.p_ptl_desc[i].i_ptl_mai_sbyte, SEEK_SET );
667 for( j=1 ; j<=8 ; j++ )
669 par.p_ptl_mask[i].ppi_ptl_mask[j] =
670 malloc( par.i_vts_nb *sizeof(u16) );
671 if( par.p_ptl_mask[i].ppi_ptl_mask[j] == NULL )
673 intf_ErrMsg( "Out of memory" );
677 for( k=0 ; k<par.i_vts_nb ; k++ )
679 GETS( &par.p_ptl_mask[i].ppi_ptl_mask[j][k] );
687 /*****************************************************************************
688 * ReadVTSAttr : Fills the structure about VTS attributes.
689 *****************************************************************************/
690 static vmg_vts_atrt_t ReadVTSAttr( ifo_t* p_ifo )
695 off_t i_start = p_ifo->i_pos;
697 //fprintf( stderr, "VTS ATTR\n" );
699 GETS( &atrt.i_vts_nb );
700 //fprintf( stderr, "VTS ATTR Nb: %d\n", atrt.i_vts_nb );
702 GETL( &atrt.i_ebyte );
703 atrt.pi_vts_atrt_sbyte = malloc( atrt.i_vts_nb *sizeof(u32) );
704 if( atrt.pi_vts_atrt_sbyte == NULL )
706 intf_ErrMsg( "Out of memory" );
710 for( i=0 ; i<atrt.i_vts_nb ; i++ )
712 GETL( &atrt.pi_vts_atrt_sbyte[i] );
714 atrt.p_vts_atrt = malloc( atrt.i_vts_nb *sizeof(vts_atrt_t) );
715 if( atrt.p_vts_atrt == NULL )
717 intf_ErrMsg( "Out of memory" );
721 for( i=0 ; i<atrt.i_vts_nb ; i++ )
723 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start +
724 atrt.pi_vts_atrt_sbyte[i],
726 GETL( &atrt.p_vts_atrt[i].i_ebyte );
727 GETL( &atrt.p_vts_atrt[i].i_cat_app_type );
728 // GETS( &atrt.p_vts_atrt[i].vtsm_video_atrt );
731 GETC( &atrt.p_vts_atrt[i].i_vtsm_audio_nb );
732 //fprintf( stderr, "m audio nb : %d\n", atrt.p_vts_atrt[i].i_vtsm_audio_nb );
733 for( j=0 ; j<8 ; j++ )
738 GETC( &atrt.p_vts_atrt[i].i_vtsm_subpic_nb );
739 //fprintf( stderr, "m subp nb : %d\n", atrt.p_vts_atrt[i].i_vtsm_subpic_nb );
740 for( j=0 ; j<28 ; j++ )
743 /* FIXME : Fix endianness issue here */
746 // GETS( &atrt.p_vts_atrt[i].vtstt_video_atrt );
749 GETL( &atrt.p_vts_atrt[i].i_vtstt_audio_nb );
750 //fprintf( stderr, "tt audio nb : %d\n", atrt.p_vts_atrt[i].i_vtstt_audio_nb );
751 for( j=0 ; j<8 ; j++ )
756 GETC( &atrt.p_vts_atrt[i].i_vtstt_subpic_nb );
757 //fprintf( stderr, "tt subp nb : %d\n", atrt.p_vts_atrt[i].i_vtstt_subpic_nb );
758 for( j=0 ; j<28/*atrt.p_vts_atrt[i].i_vtstt_subpic_nb*/ ; j++ )
761 /* FIXME : Fix endianness issue here */
768 /*****************************************************************************
769 * ReadVMG : Parse video_ts.ifo file to fill the Video Manager structure.
770 *****************************************************************************/
771 static vmg_t ReadVMG( ifo_t* p_ifo )
775 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off, SEEK_SET);
776 vmg.mat = ReadVMGInfMat( p_ifo );
777 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
778 vmg.mat.i_fp_pgc_sbyte, SEEK_SET );
779 vmg.pgc = ReadPGC( p_ifo );
780 if( vmg.mat.i_ptt_srpt_ssector )
782 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
783 vmg.mat.i_ptt_srpt_ssector *DVD_LB_SIZE,
785 vmg.ptt_srpt = ReadVMGTitlePointer( p_ifo );
787 if( vmg.mat.i_pgci_ut_ssector )
789 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
790 vmg.mat.i_pgci_ut_ssector *DVD_LB_SIZE,
792 vmg.pgci_ut = ReadUnitTable( p_ifo );
794 if( vmg.mat.i_ptl_mait_ssector )
796 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
797 vmg.mat.i_ptl_mait_ssector *DVD_LB_SIZE,
799 vmg.ptl_mait = ReadParentalInf( p_ifo );
801 if( vmg.mat.i_vts_atrt_ssector )
803 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
804 vmg.mat.i_vts_atrt_ssector *DVD_LB_SIZE,
806 vmg.vts_atrt = ReadVTSAttr( p_ifo );
808 if( vmg.mat.i_c_adt_ssector )
810 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
811 vmg.mat.i_c_adt_ssector *DVD_LB_SIZE,
813 vmg.c_adt = ReadCellInf( p_ifo );
815 if( vmg.mat.i_vobu_admap_ssector )
817 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
818 vmg.mat.i_vobu_admap_ssector *DVD_LB_SIZE,
820 vmg.vobu_admap = ReadMap( p_ifo );
826 * Video Title Set Information Processing.
827 * This is what is contained in vts_*.ifo.
830 /*****************************************************************************
831 * ReadVTSInfMat : Fills the Title Set Information structure.
832 *****************************************************************************/
833 static vtsi_mat_t ReadVTSInfMat( ifo_t* p_ifo )
838 // off_t i_start = p_ifo->i_pos;
840 //fprintf( stderr, "VTSI\n" );
842 GET( mat.psz_id , 12 );
843 mat.psz_id[12] = '\0';
844 GETL( &mat.i_lsector );
846 GETL( &mat.i_i_lsector );
848 GETC( &mat.i_spec_ver );
851 GETL( &mat.i_mat_ebyte );
853 GETL( &mat.i_m_vobs_ssector );
854 GETL( &mat.i_tt_vobs_ssector );
855 GETL( &mat.i_ptt_srpt_ssector );
856 GETL( &mat.i_pgcit_ssector );
857 GETL( &mat.i_m_pgci_ut_ssector );
858 GETL( &mat.i_tmap_ti_ssector );
859 GETL( &mat.i_m_c_adt_ssector );
860 GETL( &mat.i_m_vobu_admap_ssector );
861 GETL( &mat.i_c_adt_ssector );
862 GETL( &mat.i_vobu_admap_ssector );
864 // GETS( &mat.m_video_atrt );
867 GETC( &mat.i_m_audio_nb );
868 for( i=0 ; i<8 ; i++ )
873 GETC( &mat.i_m_subpic_nb );
874 for( i=0 ; i<28 ; i++ )
877 /* FIXME : take care of endianness */
880 // GETS( &mat.video_atrt );
883 GETC( &mat.i_audio_nb );
884 //fprintf( stderr, "vtsi audio nb : %d\n", mat.i_audio_nb );
885 for( i=0 ; i<8 ; i++ )
888 //fprintf( stderr, "Audio %d: %llx\n", i, i_temp );
890 mat.p_audio_atrt[i].i_lang_code = i_temp & 0xffff;
892 mat.p_audio_atrt[i].i_num_channels = i_temp & 0x7;
894 mat.p_audio_atrt[i].i_sample_freq = i_temp & 0x3;
896 mat.p_audio_atrt[i].i_quantization = i_temp & 0x3;
898 mat.p_audio_atrt[i].i_appl_mode = i_temp & 0x3;
900 mat.p_audio_atrt[i].i_type = i_temp & 0x3;
902 mat.p_audio_atrt[i].i_multichannel_extension = i_temp & 0x1;
904 mat.p_audio_atrt[i].i_coding_mode = i_temp & 0x7;
907 GETC( &mat.i_subpic_nb );
908 //fprintf( stderr, "vtsi subpic nb : %d\n", mat.i_subpic_nb );
909 for( i=0 ; i<mat.i_subpic_nb ; i++ )
912 i_temp = hton64( i_temp ) >> 16;
913 //fprintf( stderr, "Subpic %d: %llx\n", i, i_temp );
914 mat.p_subpic_atrt[i].i_caption = i_temp & 0xff;
916 mat.p_subpic_atrt[i].i_lang_code = i_temp & 0xffff;
918 mat.p_subpic_atrt[i].i_prefix = i_temp & 0xffff;
924 /*****************************************************************************
925 * ReadVTSTitlePointer : Fills the Part Of Title Search Pointer structure.
926 *****************************************************************************/
927 static vts_ptt_srpt_t ReadVTSTitlePointer( ifo_t* p_ifo )
931 off_t i_start = p_ifo->i_pos;
933 //fprintf( stderr, "VTS PTR\n" );
935 GETS( &ptr.i_ttu_nb );
936 //fprintf( stderr, "VTS PTR nb: %d\n", ptr.i_ttu_nb );
938 GETL( &ptr.i_ebyte );
939 ptr.pi_ttu_sbyte = malloc( ptr.i_ttu_nb *sizeof(u32) );
940 if( ptr.pi_ttu_sbyte == NULL )
942 intf_ErrMsg( "Out of memory" );
946 for( i=0 ; i<ptr.i_ttu_nb ; i++ )
948 GETL( &ptr.pi_ttu_sbyte[i] );
951 ptr.p_ttu = malloc( ptr.i_ttu_nb *sizeof(ttu_t) );
952 if( ptr.p_ttu == NULL )
954 intf_ErrMsg( "Out of memory" );
958 for( i=0 ; i<ptr.i_ttu_nb ; i++ )
960 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start +
961 ptr.pi_ttu_sbyte[i], SEEK_SET );
962 GETS( &ptr.p_ttu[i].i_pgc_nb );
963 GETS( &ptr.p_ttu[i].i_prg_nb );
964 //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 );
970 /*****************************************************************************
971 * ReadVTSTimeMap : Fills the time map table
972 *****************************************************************************/
973 static vts_tmap_ti_t ReadVTSTimeMap( ifo_t* p_ifo )
977 // off_t i_start = p_ifo->i_pos;
979 //fprintf( stderr, "TMAP\n" );
983 GETL( &tmap.i_ebyte );
984 tmap.pi_sbyte = malloc( tmap.i_nb *sizeof(u32) );
985 if( tmap.pi_sbyte == NULL )
987 intf_ErrMsg( "Out of memory" );
991 for( i=0 ; i<tmap.i_nb ; i++ )
993 GETL( &tmap.pi_sbyte[i] );
995 tmap.p_tmap = malloc( tmap.i_nb *sizeof(tmap_t) );
996 if( tmap.p_tmap == NULL )
998 intf_ErrMsg( "Out of memory" );
1002 for( i=0 ; i<tmap.i_nb ; i++ )
1004 GETC( &tmap.p_tmap[i].i_time_unit );
1006 GETS( &tmap.p_tmap[i].i_entry_nb );
1007 tmap.p_tmap[i].pi_sector =
1008 malloc( tmap.p_tmap[i].i_entry_nb *sizeof(u32) );
1009 if( tmap.p_tmap[i].pi_sector == NULL )
1011 intf_ErrMsg( "Out of memory" );
1015 for( j=0 ; j<tmap.p_tmap[i].i_entry_nb ; j++ )
1017 GETL( &tmap.p_tmap[i].pi_sector[j] );
1025 /*****************************************************************************
1026 * IfoReadVTS : Parse vts*.ifo files to fill the Video Title Set structure.
1027 *****************************************************************************/
1028 int IfoReadVTS( ifo_t* p_ifo )
1034 intf_WarnMsg( 2, "ifo: initializing VTS %d", p_ifo->i_title );
1036 i_title = p_ifo->i_title;
1037 i_off = (off_t)( p_ifo->vmg.ptt_srpt.p_tts[i_title-1].i_ssector )
1041 p_ifo->i_pos = lseek( p_ifo->i_fd, i_off, SEEK_SET );
1043 vts.i_pos = p_ifo->i_pos;
1045 vts.mat = ReadVTSInfMat( p_ifo );
1046 if( vts.mat.i_ptt_srpt_ssector )
1048 p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
1049 vts.mat.i_ptt_srpt_ssector *DVD_LB_SIZE,
1051 vts.ptt_srpt = ReadVTSTitlePointer( p_ifo );
1053 if( vts.mat.i_m_pgci_ut_ssector )
1055 p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
1056 vts.mat.i_m_pgci_ut_ssector *DVD_LB_SIZE,
1058 vts.pgci_ut = ReadUnitTable( p_ifo );
1060 if( vts.mat.i_pgcit_ssector )
1062 p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
1063 vts.mat.i_pgcit_ssector *DVD_LB_SIZE,
1065 vts.pgci_ti = ReadUnit( p_ifo );
1067 if( vts.mat.i_tmap_ti_ssector )
1069 p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
1070 vts.mat.i_tmap_ti_ssector *DVD_LB_SIZE,
1072 vts.tmap_ti = ReadVTSTimeMap( p_ifo );
1074 if( vts.mat.i_m_c_adt_ssector )
1076 p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
1077 vts.mat.i_m_c_adt_ssector *DVD_LB_SIZE,
1079 vts.m_c_adt = ReadCellInf( p_ifo );
1081 if( vts.mat.i_m_vobu_admap_ssector )
1083 p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
1084 vts.mat.i_m_vobu_admap_ssector *DVD_LB_SIZE,
1086 vts.m_vobu_admap = ReadMap( p_ifo );
1088 if( vts.mat.i_c_adt_ssector )
1090 p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
1091 vts.mat.i_c_adt_ssector *DVD_LB_SIZE,
1093 vts.c_adt = ReadCellInf( p_ifo );
1095 if( vts.mat.i_vobu_admap_ssector )
1097 p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
1098 vts.mat.i_vobu_admap_ssector *DVD_LB_SIZE,
1100 vts.vobu_admap = ReadMap( p_ifo );
1109 * DVD Information Management
1112 /*****************************************************************************
1113 * IfoRead : Function that fills structure and calls specified functions
1115 *****************************************************************************/
1116 void IfoRead( ifo_t* p_ifo )
1121 /* Video Title Sets initialization */
1122 p_ifo->p_vts = malloc( p_ifo->vmg.mat.i_tts_nb *sizeof(vts_t) );
1123 if( p_ifo->p_vts == NULL )
1125 intf_ErrMsg( "Out of memory" );
1130 for( i=0 ; i<p_ifo->vmg.mat.i_tts_nb ; i++ )
1133 intf_WarnMsg( 2, "ifo: initializing VTS %d", i+1 );
1135 i_off = (off_t)( p_ifo->vmg.ptt_srpt.p_tts[i].i_ssector ) *DVD_LB_SIZE
1138 p_ifo->i_pos = lseek( p_ifo->i_fd, i_off, SEEK_SET );
1140 /* FIXME : I really don't know why udf find file
1141 * does not give the exact beginning of file */
1143 p_ifo->p_vts[i] = ReadVTS( p_ifo );
1151 * IFO virtual machine : a set of commands that give the
1152 * interactive behaviour of the dvd
1156 #define OP_VAL_16(i) (ntoh16( com.data.pi_16[i]))
1157 #define OP_VAL_8(i) ((com.data.pi_8[i]))
1159 static char ifo_reg[][80]=
1161 "Menu_Language_Code",
1163 "SubPicture_Stream_#",
1169 "Highlighted_Button_#",
1172 "Karaoke_audio_mixing_mode",
1173 "Parental_mgmt_country_code",
1177 "Audio_language_code_setting",
1178 "Audio_language_extension_code",
1179 "SPU_language_code_setting",
1180 "SPU_language_extension_code",
1181 "?Player_Regional_Code",
1187 static char * IfoMath( char val )
1189 static char math_op[][10] =
1209 return (char *) math_op[val & 0x0f];
1213 char ifo_cmp[][10] =
1225 char ifo_parental[][10] =
1237 char ifo_menu_id[][80] =
1249 char * IfoMenuName( char index )
1251 return ifo_menu_id[index&0x07];
1254 static void IfoRegister( u16 i_data, u8 i_direct)
1258 if( 0/*isalpha( i_data >> 8 & 0xff )*/ )
1260 printf("'%c%c'", i_data>>8&0xff, i_data&0xff);
1264 printf("0x%02x", i_data);
1279 printf("s[%s]", ifo_reg[i_data]);
1292 printf("r[0x%02x]", i_data);
1298 static void IfoAdvanced( u8 *pi_code )
1300 u8 i_cmd = pi_code[0];
1306 printf( " Highlight button %d; ", pi_code[1]>>2 );
1311 printf( " Illegal " );
1316 printf( "ReSuME %d", pi_code[7] );
1318 else if( ( i_cmd & 0x06) == 0x02 )
1320 printf ("Link to %s cell ", ( i_cmd & 0x01 ) ? "prev" : "next");
1324 printf( "advanced (0x%02x) ", i_cmd );
1329 static void IfoJmp( ifo_command_t com )
1334 switch( com.i_sub_cmd )
1340 printf( "VTS 0x%02x", OP_VAL_8(3) );
1343 printf( "This VTS Title 0x%02x", OP_VAL_8(3) );
1346 printf( "This VTS Title 0x%02x Part 0x%04x",
1348 OP_VAL_8(0)<<8|OP_VAL_8(1));
1352 printf ("in SystemSpace ");
1353 switch (OP_VAL_8(3)>>4) {
1355 printf ("to play first PGC");
1358 printf ("to menu \"%s\"", decode_menuname (OP_VAL_8(3)));
1362 printf ("to VTS 0x%02x and TTN 0x%02x", OP_VAL_8(1), OP_VAL_8(2));
1365 printf ("to VMGM PGC number 0x%02x", OP_VAL_8(0)<<8 | OP_VAL_8(1));
1368 printf ("vts 0x%02x lu 0x%02x menu \"%s\"", OP_VAL_8(2), OP_VAL_8(1), decode_menuname (OP_VAL_8(3)));
1371 switch( OP_VAL_8(3)>>6 )
1374 printf( "to play first PGC" );
1377 printf( "to VMG title menu (?)" );
1380 printf( "vts 0x%02x lu 0x%02x menu \"%s\"",
1383 IfoMenuName( OP_VAL_8(3)&0xF ) );
1386 printf( "vmg pgc 0x%04x (?)", ( OP_VAL_8(0)<<8) | OP_VAL_8(1) );
1393 switch(OP_VAL_8(3)>>4) {
1395 printf ("system first pgc");
1398 printf ("system title menu");
1401 printf ("system menu \"%s\"", decode_menuname (OP_VAL_8(3)));
1404 printf ("system vmg pgc %02x ????", OP_VAL_8(0)<<8|OP_VAL_8(1));
1407 printf ("system lu 0x%02x menu \"%s\"", OP_VAL_8(2), decode_menuname (OP_VAL_8(3)));
1410 printf ("system vmg pgc 0x%02x", OP_VAL_8(0)<<8|OP_VAL_8(1));
1414 // OP_VAL_8(2) is number of cell
1415 // it is processed BEFORE switch
1416 // under some conditions, it is ignored
1417 // I don't understand exactly what it means
1418 printf( " ( spec cell 0x%02X ) ", OP_VAL_8(2) );
1420 switch( OP_VAL_8(3)>>6 )
1423 printf( "to FP PGC" );
1426 printf( "to VMG root menu (?)" );
1429 printf( "to VTS menu \"%s\" (?)",
1430 IfoMenuName(OP_VAL_8(3)&0xF) );
1433 printf( "vmg pgc 0x%02x (?)", (OP_VAL_8(0)<<8)|OP_VAL_8(1) );
1441 static void IfoLnk( ifo_command_t com )
1443 u16 i_button=OP_VAL_8(4)>>2;
1447 switch( com.i_sub_cmd )
1450 IfoAdvanced( &OP_VAL_8(4) );
1454 printf( "PGC 0x%02x", OP_VAL_16(2) );
1458 printf( "PTT 0x%02x", OP_VAL_16(2) );
1462 printf( "Program 0x%02x this PGC", OP_VAL_8(5) );
1466 printf( "Cell 0x%02x this PGC", OP_VAL_8(5) );
1474 printf( ", Highlight 0x%02x", OP_VAL_8(4)>>2 );
1479 void IfoSetSystem( ifo_command_t com )
1486 for( i=1; i<=3; i++ )
1488 if( OP_VAL_8(i)&0x80 )
1492 printf ("s[%s] = 0x%02x;", ifo_reg[i], OP_VAL_8(i)&0xf);
1496 printf ("s[%s] = r[0x%02x];", ifo_reg[i], OP_VAL_8(i)&0xf);
1502 if(OP_VAL_8(1]&0x80)
1503 printf ("s[%s] = 0x%02x;", reg_name[1], OP_VAL_8(1]&0xf);
1504 if(OP_VAL_8(2)&0x80)
1505 //DENT: lwhat about 0x7f here ???
1506 printf ("s[%s] = 0x%02x;", reg_name[2], OP_VAL_8(2)&0x7f);
1507 if(OP_VAL_8(3)&0x80)
1508 printf ("s[%s] = 0x%02x;", reg_name[3], OP_VAL_8(3)&0xf);
1510 if(OP_VAL_8(1)&0x80)
1511 printf ("s[%s] = r[0x%02x];", reg_name[1], OP_VAL_8(1)&0xf);
1512 if(OP_VAL_8(2)&0x80)
1513 printf ("s[%s] = r[0x%02x];", reg_name[2], OP_VAL_8(2)&0xf);
1514 if(OP_VAL_8(3)&0x80)
1515 printf ("s[%s] = r[0x%02x];", reg_name[3], OP_VAL_8(3)&0xf);
1523 printf( "s[%s] = 0x%02x", ifo_reg[9], OP_VAL_16(0) );
1527 printf( "s[%s] = r[0x%02x]", ifo_reg[9], OP_VAL_8(1)&0x0f );
1530 printf( "s[%s] = (s[%s]&0x7FFF)|0x%02x",
1531 ifo_reg[10], ifo_reg[10], OP_VAL_16(1)&0x8000);
1536 printf( "r[0x%02x] = 0x%02x", OP_VAL_8(3)&0x0f, OP_VAL_16(0) );
1540 printf ("r[r[0x%02x]] = r[0x%02x]",
1541 OP_VAL_8(3)&0x0f, OP_VAL_8(1)&0x0f);
1545 //actually only bits 00011100 00011100 are set
1548 printf ("s[%s] = 0x%02x", ifo_reg[11], OP_VAL_16(1));
1552 printf ("s[%s] = r[0x%02x]", ifo_reg[11], OP_VAL_8(3)&0x0f );
1557 //s[%s]=(r[%s]&0x3FF) | (0x%02x << 0xA);
1558 //but it is way too ugly
1561 printf( "s[%s] = 0x%02x", ifo_reg[8], OP_VAL_8(2)>>2 );
1565 printf( "s[%s] = r[0x%02x]", ifo_reg[8], OP_VAL_8(3)&0x0f );
1573 static void IfoSet( ifo_command_t com )
1575 IfoRegister( OP_VAL_16(0), 0 );
1576 printf( " %s ", IfoMath( com.i_cmd ) );
1577 IfoRegister( OP_VAL_16(1), com.i_direct );
1580 /*****************************************************************************
1581 * CommandRead : translates the command strings in ifo into command
1583 *****************************************************************************/
1584 void CommandRead( ifo_command_t com )
1586 u8* pi_code = (u8*)(&com);
1588 switch( com.i_type )
1601 printf ("if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
1602 ifo_cmp[com.i_cmp]);
1603 IfoRegister (OP_VAL_16(1), com.i_dir_cmp);
1608 switch( com.i_sub_cmd )
1611 printf( "goto Line 0x%02x", OP_VAL_16(2) );
1615 printf( "stop VM" );
1619 printf( "Set Parental Level To %s and goto Line 0x%02x",
1620 ifo_parental[OP_VAL_8(4)&0x7],
1625 printf( "Illegal" );
1644 printf( "if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f,
1645 ifo_cmp[com.i_cmp] );
1646 IfoRegister( OP_VAL_8(5), 0 );
1657 printf( "if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
1658 ifo_cmp[com.i_cmp] );
1659 IfoRegister( OP_VAL_16(1), com.i_dir_cmp );
1673 IfoSetSystem( com );
1675 else if( com.i_cmp && !com.i_sub_cmd )
1677 printf ("if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f, ifo_cmp[com.i_cmp]);
1678 IfoRegister( OP_VAL_8(5), 0 );
1680 IfoSetSystem( com );
1682 else if( !com.i_cmp && com.i_sub_cmd )
1685 IfoSetSystem( com );
1701 else if( com.i_cmp && !com.i_sub_cmd )
1703 printf ("if (r[0x%02x] %s ", OP_VAL_8(0)&0x0f, ifo_cmp[com.i_cmp]);
1704 IfoRegister( OP_VAL_16(2), com.i_dir_cmp );
1708 else if( !com.i_cmp && com.i_sub_cmd )
1722 * math command on r[opcode[1]] and
1723 * direct?be2me_16(OP_VAL_8(0)):reg[OP_VAL_8(1)] is executed
1724 * ( unless command is swap; then r[opcode[1]] and r[OP_VAL_8(1)]
1726 * boolean operation cmp on r[opcode[1]] and
1727 * dir_cmp?be2me_16(OP_VAL_8(1)[1]):reg[OP_VAL_8(3)] is executed
1728 * on true result, buttons(c[6], c[7]) is called
1729 * problem is 'what is buttons()'
1732 printf( "r[0x%X] ", pi_code[1] );
1733 printf( " %s ", IfoMath( com.i_cmd ) );
1734 if( com.i_cmd == 2 )
1736 printf( "r[0x%X] ", OP_VAL_8(1) );
1740 IfoRegister( OP_VAL_16(0), com.i_direct );
1744 printf( "if ( r[%d] %s ", pi_code[1], ifo_cmp[com.i_cmp] );
1745 IfoRegister( OP_VAL_8(1), com.i_dir_cmp );
1746 printf( " ) then {" );
1747 IfoAdvanced( &OP_VAL_8(4) );
1752 * opposite to case 4: boolean, math and buttons.
1758 if( !com.i_direct && com.i_dir_cmp )
1760 printf( "0x%X", OP_VAL_16(1) );
1764 IfoRegister( OP_VAL_8(3), 0 );
1765 if( OP_VAL_8(3)&0x80 )
1767 printf( "s[%s]", ifo_reg[OP_VAL_8(3)&0x1F] );
1771 printf( "r[0x%X]", OP_VAL_8(3)&0x1F);
1772 // 0x1F is either not a mistake,
1773 // or Microsoft programmer's mistake!!!
1777 printf( " %s r[0x%X] ", ifo_cmp[com.i_cmp],
1778 com.i_direct ? OP_VAL_8(2) : OP_VAL_8(1) );
1779 printf( " ) then {" );
1780 printf( "r[0x%X] ", pi_code[1] & 0xF );
1781 printf( " %s ", IfoMath( com.i_cmd ) );
1783 if( com.i_cmd == 0x02 ) // swap
1785 printf("r[0x%X] ", OP_VAL_8(0)&0x1F);
1791 printf( "0x%X", OP_VAL_16(0) );
1795 if( OP_VAL_8(0) & 0x80 )
1797 printf("s[%s]", ifo_reg[OP_VAL_8(0) & 0x1F] );
1801 printf("r[0x%X]", OP_VAL_8(0) & 0x1F );
1807 IfoAdvanced( &OP_VAL_8(4) );
1813 printf( "Unknown Command\n" );
1820 /*****************************************************************************
1821 * CommandPrint : print in clear text (I hope so !) what a command does
1822 *****************************************************************************/
1823 void CommandPrint( ifo_t ifo )