1 /*****************************************************************************
2 * dvd_ifo.c: Functions for ifo parsing
3 *****************************************************************************
4 * Copyright (C) 1999-2001 VideoLAN
5 * $Id: dvd_ifo.c,v 1.7 2001/02/14 04:11:01 stef Exp $
7 * Author: Stéphane Borel <stef@via.ecp.fr>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
36 #include "input_dvd.h"
38 void CommandRead( ifo_command_t );
44 /*****************************************************************************
45 * IfoFindVMG : When reading directly on a device, finds the offset to the
46 * beginning of video_ts.ifo.
47 *****************************************************************************/
48 static int IfoFindVMG( ifo_t* p_ifo )
50 char psz_ifo_start[12] = "DVDVIDEO-VMG";
53 read( p_ifo->i_fd, psz_test, 12 );
55 while( strncmp( psz_test, psz_ifo_start, 12 ) != 0 )
57 /* The start of ifo file is on a sector boundary */
58 p_ifo->i_pos = lseek( p_ifo->i_fd,
59 p_ifo->i_pos + DVD_LB_SIZE,
61 read( p_ifo->i_fd, psz_test, 12 );
63 p_ifo->i_off = p_ifo->i_pos;
65 //fprintf( stderr, "VMG Off : %lld\n", (long long)(p_ifo->i_off) );
70 /*****************************************************************************
71 * IfoFindVTS : beginning of vts_*.ifo.
72 *****************************************************************************/
73 static int IfoFindVTS( ifo_t* p_ifo )
75 char psz_ifo_start[12] = "DVDVIDEO-VTS";
78 read( p_ifo->i_fd, psz_test, 12 );
80 while( strncmp( psz_test, psz_ifo_start, 12 ) != 0 )
82 /* The start of ifo file is on a sector boundary */
83 p_ifo->i_pos = lseek( p_ifo->i_fd,
84 p_ifo->i_pos + DVD_LB_SIZE,
86 read( p_ifo->i_fd, psz_test, 12 );
88 p_ifo->i_off = p_ifo->i_pos;
90 //fprintf( stderr, "VTS Off : %lld\n", (long long)(p_ifo->i_off) );
95 /*****************************************************************************
96 * IfoInit : Creates an ifo structure and prepares for parsing directly
98 *****************************************************************************/
99 ifo_t IfoInit( int i_fd )
103 /* If we are here the dvd device has already been opened */
105 /* No data at the beginning of the disk
106 * 512000 bytes is just another value :) */
107 ifo.i_pos = lseek( ifo.i_fd, 250 *DVD_LB_SIZE, SEEK_SET );
108 /* FIXME : use udf filesystem to find the beginning of the file */
114 /*****************************************************************************
115 * IfoEnd : Frees all the memory allocated to ifo structures
116 *****************************************************************************/
117 void IfoEnd( ifo_t* p_ifo )
121 /* Free structures from video title sets */
122 for( j=0 ; j<p_ifo->vmg.mat.i_tts_nb ; j++ )
124 free( p_ifo->p_vts[j].vobu_admap.pi_vobu_ssector );
125 free( p_ifo->p_vts[j].c_adt.p_cell_inf );
126 free( p_ifo->p_vts[j].m_vobu_admap.pi_vobu_ssector );
127 free( p_ifo->p_vts[j].m_c_adt.p_cell_inf );
128 for( i=0 ; i<p_ifo->p_vts[j].tmap_ti.i_nb ; i++ )
130 free( p_ifo->p_vts[j].tmap_ti.p_tmap[i].pi_sector );
132 free( p_ifo->p_vts[j].tmap_ti.pi_sbyte );
133 free( p_ifo->p_vts[j].tmap_ti.p_tmap );
134 free( p_ifo->p_vts[j].pgci_ti.p_srp );
135 for( i=0 ; i<p_ifo->p_vts[j].pgci_ut.i_lu_nb ; i++ )
137 free( p_ifo->p_vts[j].pgci_ut.p_pgci_inf[i].p_srp );
139 free( p_ifo->p_vts[j].pgci_ut.p_pgci_inf );
140 free( p_ifo->p_vts[j].pgci_ut.p_lu );
143 free( p_ifo->p_vts );
145 /* Free structures from video manager */
146 free( p_ifo->vmg.vobu_admap.pi_vobu_ssector );
147 free( p_ifo->vmg.c_adt.p_cell_inf );
148 for( i=0 ; i<p_ifo->vmg.pgci_ut.i_lu_nb ; i++ )
150 free( p_ifo->vmg.pgci_ut.p_pgci_inf[i].p_srp );
152 free( p_ifo->vmg.pgci_ut.p_pgci_inf );
153 free( p_ifo->vmg.pgci_ut.p_lu );
154 for( i=1 ; i<=8 ; i++ )
156 free( p_ifo->vmg.ptl_mait.p_ptl_mask->ppi_ptl_mask[i] );
158 free( p_ifo->vmg.ptl_mait.p_ptl_desc );
159 free( p_ifo->vmg.ptl_mait.p_ptl_mask );
160 free( p_ifo->vmg.vts_atrt.pi_vts_atrt_sbyte );
161 free( p_ifo->vmg.vts_atrt.p_vts_atrt );
162 free( p_ifo->vmg.pgc.p_cell_pos_inf );
163 free( p_ifo->vmg.pgc.p_cell_play_inf );
164 free( p_ifo->vmg.pgc.prg_map.pi_entry_cell );
165 free( p_ifo->vmg.pgc.com_tab.p_cell_com );
166 free( p_ifo->vmg.pgc.com_tab.p_post_com );
167 free( p_ifo->vmg.pgc.com_tab.p_pre_com );
173 * Macros to process ifo files
176 #define GET( p_field , i_len ) \
178 read( p_ifo->i_fd , (p_field) , (i_len) ); \
179 /*fprintf(stderr, "Pos : %lld Val : %llx\n", \
180 (long long)(p_ifo->i_pos - i_start), \
181 (long long)*(p_field) ); */ \
182 p_ifo->i_pos += i_len; \
185 #define GETC( p_field ) \
187 read( p_ifo->i_fd , (p_field) , 1 ); \
188 /*fprintf(stderr, "Pos : %lld Value : %d\n", \
189 (long long)(p_ifo->i_pos - i_start), \
194 #define GETS( p_field ) \
196 read( p_ifo->i_fd , (p_field) , 2 ); \
197 *(p_field) = ntohs( *(p_field) ); \
198 /*fprintf(stderr, "Pos : %lld Value : %d\n", \
199 (long long)(p_ifo->i_pos - i_start), \
204 #define GETL( p_field ) \
206 read( p_ifo->i_fd , (p_field) , 4 ); \
207 *(p_field) = ntohl( *(p_field) ); \
208 /*fprintf(stderr, "Pos : %lld Value : %d\n", \
209 (long long)(p_ifo->i_pos - i_start), \
214 #define GETLL( p_field ) \
216 read( p_ifo->i_fd , (p_field) , 8 ); \
217 *(p_field) = ntoh64( *(p_field) ); \
218 /*fprintf(stderr, "Pos : %lld Value : %lld\n", \
219 (long long)(p_ifo->i_pos - i_start), \
224 #define FLUSH( i_len ) \
226 /*fprintf(stderr, "Pos : %lld\n", (long long)(p_ifo->i_pos - i_start));*/ \
227 p_ifo->i_pos = lseek( p_ifo->i_fd , \
228 p_ifo->i_pos + (i_len), SEEK_SET ); \
232 * Function common to Video Manager and Video Title set Processing
235 /*****************************************************************************
236 * ReadPGC : Fills the Program Chain structure.
237 *****************************************************************************/
238 #define GETCOMMAND( p_com ) \
240 read( p_ifo->i_fd , (p_com) , 8 ); \
241 /*fprintf(stderr, "Pos : %lld Type : %d direct : %d cmd : %d dircmp : %d cmp : %d subcmd : %d v0 : %d v2 : %d v4 : %d\n", \
242 (long long)(p_ifo->i_pos - i_start), \
243 (int)((p_com)->i_type), \
244 (int)((p_com)->i_direct), \
245 (int)((p_com)->i_cmd), \
246 (int)((p_com)->i_dir_cmp), \
247 (int)((p_com)->i_cmp), \
248 (int)((p_com)->i_sub_cmd), \
249 (int)((p_com)->data.pi_16[0]), \
250 (int)((p_com)->data.pi_16[1]), \
251 (int)((p_com)->data.pi_16[2]));*/ \
252 /* CommandRead( *(p_com) );*/ \
256 static pgc_t ReadPGC( ifo_t* p_ifo )
260 off_t i_start = p_ifo->i_pos;
262 //fprintf( stderr, "PGC\n" );
265 GETC( &pgc.i_prg_nb );
266 GETC( &pgc.i_cell_nb );
267 GETL( &pgc.i_play_time );
268 GETL( &pgc.i_prohibited_user_op );
269 for( i=0 ; i<8 ; i++ )
271 GETS( &pgc.pi_audio_status[i] );
273 for( i=0 ; i<32 ; i++ )
275 GETL( &pgc.pi_subpic_status[i] );
277 GETS( &pgc.i_next_pgc_nb );
278 GETS( &pgc.i_prev_pgc_nb );
279 GETS( &pgc.i_goup_pgc_nb );
280 GETC( &pgc.i_still_time );
281 GETC( &pgc.i_play_mode );
282 for( i=0 ; i<16 ; i++ )
284 GETL( &pgc.pi_yuv_color[i] );
285 /* FIXME : We have to erase the extra bit */
287 GETS( &pgc.i_com_tab_sbyte );
288 GETS( &pgc.i_prg_map_sbyte );
289 GETS( &pgc.i_cell_play_inf_sbyte );
290 GETS( &pgc.i_cell_pos_inf_sbyte );
292 /* Parsing of pgc_com_tab_t */
293 if( pgc.i_com_tab_sbyte )
295 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
296 + pgc.i_com_tab_sbyte, SEEK_SET );
297 GETS( &pgc.com_tab.i_pre_com_nb );
298 GETS( &pgc.com_tab.i_post_com_nb );
299 GETS( &pgc.com_tab.i_cell_com_nb );
301 if( pgc.com_tab.i_pre_com_nb )
303 pgc.com_tab.p_pre_com =
304 malloc(pgc.com_tab.i_pre_com_nb *sizeof(ifo_command_t));
305 if( pgc.com_tab.p_pre_com == NULL )
307 intf_ErrMsg( "Out of memory" );
311 for( i=0 ; i<pgc.com_tab.i_pre_com_nb ; i++ )
313 GETCOMMAND( &pgc.com_tab.p_pre_com[i] );
316 if( pgc.com_tab.i_post_com_nb )
318 pgc.com_tab.p_post_com =
319 malloc(pgc.com_tab.i_post_com_nb *sizeof(ifo_command_t));
320 if( pgc.com_tab.p_post_com == NULL )
322 intf_ErrMsg( "Out of memory" );
326 for( i=0 ; i<pgc.com_tab.i_post_com_nb ; i++ )
328 GETCOMMAND( &pgc.com_tab.p_post_com[i] );
331 if( pgc.com_tab.i_cell_com_nb )
333 pgc.com_tab.p_cell_com =
334 malloc(pgc.com_tab.i_cell_com_nb *sizeof(ifo_command_t));
335 if( pgc.com_tab.p_cell_com == NULL )
337 intf_ErrMsg( "Out of memory" );
341 for( i=0 ; i<pgc.com_tab.i_cell_com_nb ; i++ )
343 GETCOMMAND( &pgc.com_tab.p_cell_com[i] );
347 /* Parsing of pgc_prg_map_t */
348 if( pgc.i_prg_map_sbyte )
350 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
351 + pgc.i_prg_map_sbyte, SEEK_SET );
352 pgc.prg_map.pi_entry_cell = malloc( pgc.i_prg_nb *sizeof(u8) );
353 if( pgc.prg_map.pi_entry_cell == NULL )
355 intf_ErrMsg( "Out of memory" );
359 GET( pgc.prg_map.pi_entry_cell, pgc.i_prg_nb );
360 /* FIXME : check endianness here */
362 /* Parsing of cell_play_inf_t */
363 if( pgc.i_cell_play_inf_sbyte )
365 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
366 + pgc.i_cell_play_inf_sbyte, SEEK_SET );
367 pgc.p_cell_play_inf = malloc( pgc.i_cell_nb *sizeof(cell_play_inf_t) );
368 if( pgc.p_cell_play_inf == NULL )
370 intf_ErrMsg( "Out of memory" );
374 for( i=0 ; i<pgc.i_cell_nb ; i++ )
376 GETS( &pgc.p_cell_play_inf[i].i_cat );
377 GETC( &pgc.p_cell_play_inf[i].i_still_time );
378 GETC( &pgc.p_cell_play_inf[i].i_com_nb );
379 GETL( &pgc.p_cell_play_inf[i].i_play_time );
380 GETL( &pgc.p_cell_play_inf[i].i_entry_sector );
381 GETL( &pgc.p_cell_play_inf[i].i_first_ilvu_vobu_esector );
382 GETL( &pgc.p_cell_play_inf[i].i_lvobu_ssector );
383 GETL( &pgc.p_cell_play_inf[i].i_lsector );
386 /* Parsing of cell_pos_inf_map */
387 if( pgc.i_cell_pos_inf_sbyte )
389 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
390 + pgc.i_cell_pos_inf_sbyte, SEEK_SET );
391 pgc.p_cell_pos_inf = malloc( pgc.i_cell_nb *sizeof(cell_pos_inf_t) );
392 if( pgc.p_cell_play_inf == NULL )
394 intf_ErrMsg( "Out of memory" );
398 for( i=0 ; i<pgc.i_cell_nb ; i++ )
400 GETS( &pgc.p_cell_pos_inf[i].i_vob_id );
402 GETC( &pgc.p_cell_pos_inf[i].i_cell_id );
409 /*****************************************************************************
410 * ReadUnit : Fills Menu Language Unit Table/ PGC Info Table
411 *****************************************************************************/
412 static pgci_inf_t ReadUnit( ifo_t* p_ifo )
416 off_t i_start = p_ifo->i_pos;
418 //fprintf( stderr, "Unit\n" );
420 GETS( &inf.i_srp_nb );
422 GETL( &inf.i_lu_ebyte );
423 inf.p_srp = malloc( inf.i_srp_nb *sizeof(pgci_srp_t) );
424 if( inf.p_srp == NULL )
426 intf_ErrMsg( "Out of memory" );
430 for( i=0 ; i<inf.i_srp_nb ; i++ )
432 GETC( &inf.p_srp[i].i_pgc_cat_mask );
433 GETC( &inf.p_srp[i].i_pgc_cat );
434 GETS( &inf.p_srp[i].i_par_mask );
435 GETL( &inf.p_srp[i].i_pgci_sbyte );
437 for( i=0 ; i<inf.i_srp_nb ; i++ )
439 p_ifo->i_pos = lseek( p_ifo->i_fd,
440 i_start + inf.p_srp[i].i_pgci_sbyte,
442 inf.p_srp[i].pgc = ReadPGC( p_ifo );
448 /*****************************************************************************
449 * ReadUnitTable : Fills the PGCI Unit structure.
450 *****************************************************************************/
451 static pgci_ut_t ReadUnitTable( ifo_t* p_ifo )
455 off_t i_start = p_ifo->i_pos;
457 //fprintf( stderr, "Unit Table\n" );
459 GETS( &pgci.i_lu_nb );
461 GETL( &pgci.i_ebyte );
462 pgci.p_lu = malloc( pgci.i_lu_nb *sizeof(pgci_lu_t) );
463 if( pgci.p_lu == NULL )
465 intf_ErrMsg( "Out of memory" );
469 for( i=0 ; i<pgci.i_lu_nb ; i++ )
471 GET( pgci.p_lu[i].ps_lang_code, 2 );
473 GETC( &pgci.p_lu[i].i_existence_mask );
474 GETL( &pgci.p_lu[i].i_lu_sbyte );
476 pgci.p_pgci_inf = malloc( pgci.i_lu_nb *sizeof(pgci_inf_t) );
477 if( pgci.p_pgci_inf == NULL )
479 intf_ErrMsg( "Out of memory" );
483 for( i=0 ; i<pgci.i_lu_nb ; i++ )
485 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start +
486 pgci.p_lu[i].i_lu_sbyte,
488 pgci.p_pgci_inf[i] = ReadUnit( p_ifo );
494 /*****************************************************************************
495 * ReadCellInf : Fills the Cell Information structure.
496 *****************************************************************************/
497 static c_adt_t ReadCellInf( ifo_t* p_ifo )
500 off_t i_start = p_ifo->i_pos;
503 //fprintf( stderr, "CELL ADD\n" );
505 GETS( &c_adt.i_vob_nb );
507 GETL( &c_adt.i_ebyte );
509 ( i_start + c_adt.i_ebyte + 1 - p_ifo->i_pos ) / sizeof(cell_inf_t);
510 c_adt.p_cell_inf = malloc( c_adt.i_cell_nb *sizeof(cell_inf_t) );
511 if( c_adt.p_cell_inf == NULL )
513 intf_ErrMsg( "Out of memory" );
517 for( i = 0 ; i < c_adt.i_cell_nb ; i++ )
519 GETS( &c_adt.p_cell_inf[i].i_vob_id );
520 GETC( &c_adt.p_cell_inf[i].i_cell_id );
522 GETL( &c_adt.p_cell_inf[i].i_ssector );
523 GETL( &c_adt.p_cell_inf[i].i_esector );
529 /*****************************************************************************
530 * ReadMap : Fills the VOBU Map structure.
531 *****************************************************************************/
532 static vobu_admap_t ReadMap( ifo_t* p_ifo )
536 off_t i_start = p_ifo->i_pos;
538 //fprintf( stderr, "VOBU ADMAP\n" );
540 GETL( &map.i_ebyte );
541 i_max = ( i_start + map.i_ebyte + 1 - p_ifo->i_pos ) / sizeof(u32);
542 map.pi_vobu_ssector = malloc( i_max *sizeof(u32) );
543 for( i=0 ; i<i_max ; i++ )
545 GETL( &map.pi_vobu_ssector[i] );
552 * Video Manager Information Processing.
553 * This is what is contained in video_ts.ifo.
556 /*****************************************************************************
557 * ReadVMGInfMat : Fills the Management Information structure.
558 *****************************************************************************/
559 static vmgi_mat_t ReadVMGInfMat( ifo_t* p_ifo )
563 // off_t i_start = p_ifo->i_pos;
565 //fprintf( stderr, "VMGI\n" );
567 GET( mat.psz_id , 12 );
568 mat.psz_id[12] = '\0';
569 GETL( &mat.i_lsector );
571 GETL( &mat.i_i_lsector );
573 GETC( &mat.i_spec_ver );
575 GETS( &mat.i_vol_nb );
577 GETC( &mat.i_disc_side );
579 GETS( &mat.i_tts_nb );
580 GET( mat.ps_provider_id, 32 );
581 GETLL( &mat.i_pos_code );
583 GETL( &mat.i_i_mat_ebyte );
584 GETL( &mat.i_fp_pgc_sbyte );
586 GETL( &mat.i_vobs_ssector );
587 GETL( &mat.i_ptt_srpt_ssector );
588 GETL( &mat.i_pgci_ut_ssector );
589 GETL( &mat.i_ptl_mait_ssector );
590 GETL( &mat.i_vts_atrt_ssector );
591 GETL( &mat.i_txtdt_mg_ssector );
592 GETL( &mat.i_c_adt_ssector );
593 GETL( &mat.i_vobu_admap_ssector );
595 GETS( &mat.i_video_atrt );
597 GETC( &mat.i_audio_nb );
598 //fprintf( stderr, "vmgi audio nb : %d\n", mat.i_audio_nb );
599 for( i=0 ; i < 8 ; i++ )
601 GETLL( &mat.pi_audio_atrt[i] );
604 GETC( &mat.i_subpic_nb );
605 //fprintf( stderr, "vmgi subpic nb : %d\n", mat.i_subpic_nb );
606 for( i=0 ; i < mat.i_subpic_nb ; i++ )
608 GET( &mat.pi_subpic_atrt[i], 6 );
609 /* FIXME : take care of endianness */
615 /*****************************************************************************
616 * ReadVMGTitlePointer : Fills the Part Of Title Search Pointer structure.
617 *****************************************************************************/
618 static vmg_ptt_srpt_t ReadVMGTitlePointer( ifo_t* p_ifo )
622 // off_t i_start = p_ifo->i_pos;
624 //fprintf( stderr, "PTR\n" );
626 GETS( &ptr.i_ttu_nb );
628 GETL( &ptr.i_ebyte );
630 ptr.p_tts = malloc( ptr.i_ttu_nb *sizeof(tts_t) );
631 if( ptr.p_tts == NULL )
633 intf_ErrMsg( "Out of memory" );
637 for( i=0 ; i<ptr.i_ttu_nb ; i++ )
639 GETC( &ptr.p_tts[i].i_play_type );
640 GETC( &ptr.p_tts[i].i_angle_nb );
641 GETS( &ptr.p_tts[i].i_ptt_nb );
642 GETS( &ptr.p_tts[i].i_parental_id );
643 GETC( &ptr.p_tts[i].i_tts_nb );
644 GETC( &ptr.p_tts[i].i_vts_ttn );
645 GETL( &ptr.p_tts[i].i_ssector );
651 /*****************************************************************************
652 * ReadParentalInf : Fills the Parental Management structure.
653 *****************************************************************************/
654 static vmg_ptl_mait_t ReadParentalInf( ifo_t* p_ifo )
658 off_t i_start = p_ifo->i_pos;
660 //fprintf( stderr, "PTL\n" );
662 GETS( &par.i_country_nb );
663 GETS( &par.i_vts_nb );
664 GETL( &par.i_ebyte );
665 par.p_ptl_desc = malloc( par.i_country_nb *sizeof(vmg_ptl_mai_desc_t) );
666 if( par.p_ptl_desc == NULL )
668 intf_ErrMsg( "Out of memory" );
672 for( i=0 ; i<par.i_country_nb ; i++ )
674 GET( par.p_ptl_desc[i].ps_country_code, 2 );
676 GETS( &par.p_ptl_desc[i].i_ptl_mai_sbyte );
679 par.p_ptl_mask = malloc( par.i_country_nb *sizeof(vmg_ptl_mask_t) );
680 if( par.p_ptl_mask == NULL )
682 intf_ErrMsg( "Out of memory" );
686 for( i=0 ; i<par.i_country_nb ; i++ )
688 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start +
689 par.p_ptl_desc[i].i_ptl_mai_sbyte, SEEK_SET );
690 for( j=1 ; j<=8 ; j++ )
692 par.p_ptl_mask[i].ppi_ptl_mask[j] =
693 malloc( par.i_vts_nb *sizeof(u16) );
694 if( par.p_ptl_mask[i].ppi_ptl_mask[j] == NULL )
696 intf_ErrMsg( "Out of memory" );
700 for( k=0 ; k<par.i_vts_nb ; k++ )
702 GETS( &par.p_ptl_mask[i].ppi_ptl_mask[j][k] );
710 /*****************************************************************************
711 * ReadVTSAttr : Fills the structure about VTS attributes.
712 *****************************************************************************/
713 static vmg_vts_atrt_t ReadVTSAttr( ifo_t* p_ifo )
717 off_t i_start = p_ifo->i_pos;
719 //fprintf( stderr, "VTS ATTR\n" );
721 GETS( &atrt.i_vts_nb );
723 GETL( &atrt.i_ebyte );
724 atrt.pi_vts_atrt_sbyte = malloc( atrt.i_vts_nb *sizeof(u32) );
725 if( atrt.pi_vts_atrt_sbyte == NULL )
727 intf_ErrMsg( "Out of memory" );
731 for( i=0 ; i<atrt.i_vts_nb ; i++ )
733 GETL( &atrt.pi_vts_atrt_sbyte[i] );
735 atrt.p_vts_atrt = malloc( atrt.i_vts_nb *sizeof(vts_atrt_t) );
736 if( atrt.p_vts_atrt == NULL )
738 intf_ErrMsg( "Out of memory" );
742 for( i=0 ; i<atrt.i_vts_nb ; i++ )
744 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start +
745 atrt.pi_vts_atrt_sbyte[i],
747 GETL( &atrt.p_vts_atrt[i].i_ebyte );
748 GETL( &atrt.p_vts_atrt[i].i_cat_app_type );
749 GETS( &atrt.p_vts_atrt[i].i_vtsm_video_atrt );
751 GETC( &atrt.p_vts_atrt[i].i_vtsm_audio_nb );
752 //fprintf( stderr, "m audio nb : %d\n", atrt.p_vts_atrt[i].i_vtsm_audio_nb );
753 for( j=0 ; j<8 ; j++ )
755 GETLL( &atrt.p_vts_atrt[i].pi_vtsm_audio_atrt[j] );
758 GETC( &atrt.p_vts_atrt[i].i_vtsm_subpic_nb );
759 //fprintf( stderr, "m subp nb : %d\n", atrt.p_vts_atrt[i].i_vtsm_subpic_nb );
760 for( j=0 ; j<28 ; j++ )
762 GET( &atrt.p_vts_atrt[i].pi_vtsm_subpic_atrt[j], 6 );
763 /* FIXME : Fix endianness issue here */
766 GETS( &atrt.p_vts_atrt[i].i_vtstt_video_atrt );
768 GETL( &atrt.p_vts_atrt[i].i_vtstt_audio_nb );
769 //fprintf( stderr, "tt audio nb : %d\n", atrt.p_vts_atrt[i].i_vtstt_audio_nb );
770 for( j=0 ; j<8 ; j++ )
772 GETLL( &atrt.p_vts_atrt[i].pi_vtstt_audio_atrt[j] );
775 GETC( &atrt.p_vts_atrt[i].i_vtstt_subpic_nb );
776 //fprintf( stderr, "tt subp nb : %d\n", atrt.p_vts_atrt[i].i_vtstt_subpic_nb );
777 for( j=0 ; j<28/*atrt.p_vts_atrt[i].i_vtstt_subpic_nb*/ ; j++ )
779 GET( &atrt.p_vts_atrt[i].pi_vtstt_subpic_atrt[j], 6 );
780 /* FIXME : Fix endianness issue here */
787 /*****************************************************************************
788 * ReadVMG : Parse video_ts.ifo file to fill the Video Manager structure.
789 *****************************************************************************/
790 static vmg_t ReadVMG( ifo_t* p_ifo )
794 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off, SEEK_SET);
795 vmg.mat = ReadVMGInfMat( p_ifo );
796 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
797 vmg.mat.i_fp_pgc_sbyte, SEEK_SET );
798 vmg.pgc = ReadPGC( p_ifo );
799 if( vmg.mat.i_ptt_srpt_ssector )
801 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
802 vmg.mat.i_ptt_srpt_ssector *DVD_LB_SIZE,
804 vmg.ptt_srpt = ReadVMGTitlePointer( p_ifo );
806 if( vmg.mat.i_pgci_ut_ssector )
808 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
809 vmg.mat.i_pgci_ut_ssector *DVD_LB_SIZE,
811 vmg.pgci_ut = ReadUnitTable( p_ifo );
813 if( vmg.mat.i_ptl_mait_ssector )
815 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
816 vmg.mat.i_ptl_mait_ssector *DVD_LB_SIZE,
818 vmg.ptl_mait = ReadParentalInf( p_ifo );
820 if( vmg.mat.i_vts_atrt_ssector )
822 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
823 vmg.mat.i_vts_atrt_ssector *DVD_LB_SIZE,
825 vmg.vts_atrt = ReadVTSAttr( p_ifo );
827 if( vmg.mat.i_c_adt_ssector )
829 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
830 vmg.mat.i_c_adt_ssector *DVD_LB_SIZE,
832 vmg.c_adt = ReadCellInf( p_ifo );
834 if( vmg.mat.i_vobu_admap_ssector )
836 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
837 vmg.mat.i_vobu_admap_ssector *DVD_LB_SIZE,
839 vmg.vobu_admap = ReadMap( p_ifo );
845 * Video Title Set Information Processing.
846 * This is what is contained in vts_*.ifo.
849 /*****************************************************************************
850 * ReadVTSInfMat : Fills the Title Set Information structure.
851 *****************************************************************************/
852 static vtsi_mat_t ReadVTSInfMat( ifo_t* p_ifo )
856 // off_t i_start = p_ifo->i_pos;
858 //fprintf( stderr, "VTSI\n" );
860 GET( mat.psz_id , 12 );
861 mat.psz_id[12] = '\0';
862 GETL( &mat.i_lsector );
864 GETL( &mat.i_i_lsector );
866 GETC( &mat.i_spec_ver );
869 GETL( &mat.i_mat_ebyte );
871 GETL( &mat.i_m_vobs_ssector );
872 GETL( &mat.i_tt_vobs_ssector );
873 GETL( &mat.i_ptt_srpt_ssector );
874 GETL( &mat.i_pgcit_ssector );
875 GETL( &mat.i_m_pgci_ut_ssector );
876 GETL( &mat.i_tmap_ti_ssector );
877 GETL( &mat.i_m_c_adt_ssector );
878 GETL( &mat.i_m_vobu_admap_ssector );
879 GETL( &mat.i_c_adt_ssector );
880 GETL( &mat.i_vobu_admap_ssector );
882 GETS( &mat.i_m_video_atrt );
884 GETC( &mat.i_m_audio_nb );
885 for( i=0 ; i<8 ; i++ )
887 GETLL( &mat.pi_m_audio_atrt[i] );
890 GETC( &mat.i_m_subpic_nb );
891 for( i=0 ; i<28 ; i++ )
893 GET( &mat.pi_m_subpic_atrt[i], 6 );
894 /* FIXME : take care of endianness */
897 GETS( &mat.i_video_atrt );
899 GETC( &mat.i_audio_nb );
900 //fprintf( stderr, "vtsi audio nb : %d\n", mat.i_audio_nb );
901 for( i=0 ; i<8 ; i++ )
903 GETLL( &mat.pi_audio_atrt[i] );
906 GETC( &mat.i_subpic_nb );
907 //fprintf( stderr, "vtsi subpic nb : %d\n", mat.i_subpic_nb );
908 for( i=0 ; i<mat.i_subpic_nb ; i++ )
910 GET( &mat.pi_subpic_atrt[i], 6 );
911 /* FIXME : take care of endianness */
917 /*****************************************************************************
918 * ReadVTSTitlePointer : Fills the Part Of Title Search Pointer structure.
919 *****************************************************************************/
920 static vts_ptt_srpt_t ReadVTSTitlePointer( ifo_t* p_ifo )
924 off_t i_start = p_ifo->i_pos;
926 //fprintf( stderr, "PTR\n" );
928 GETS( &ptr.i_ttu_nb );
930 GETL( &ptr.i_ebyte );
931 ptr.pi_ttu_sbyte = malloc( ptr.i_ttu_nb *sizeof(u32) );
932 if( ptr.pi_ttu_sbyte == NULL )
934 intf_ErrMsg( "Out of memory" );
938 for( i=0 ; i<ptr.i_ttu_nb ; i++ )
940 GETL( &ptr.pi_ttu_sbyte[i] );
943 ptr.p_ttu = malloc( ptr.i_ttu_nb *sizeof(ttu_t) );
944 if( ptr.p_ttu == NULL )
946 intf_ErrMsg( "Out of memory" );
950 for( i=0 ; i<ptr.i_ttu_nb ; i++ )
952 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start +
953 ptr.pi_ttu_sbyte[i], SEEK_SET );
954 GETS( &ptr.p_ttu[i].i_pgc_nb );
955 GETS( &ptr.p_ttu[i].i_prg_nb );
961 /*****************************************************************************
962 * ReadVTSTimeMap : Fills the time map table
963 *****************************************************************************/
964 static vts_tmap_ti_t ReadVTSTimeMap( ifo_t* p_ifo )
968 // off_t i_start = p_ifo->i_pos;
970 //fprintf( stderr, "TMAP\n" );
974 GETL( &tmap.i_ebyte );
975 tmap.pi_sbyte = malloc( tmap.i_nb *sizeof(u32) );
976 if( tmap.pi_sbyte == NULL )
978 intf_ErrMsg( "Out of memory" );
982 for( i=0 ; i<tmap.i_nb ; i++ )
984 GETL( &tmap.pi_sbyte[i] );
986 tmap.p_tmap = malloc( tmap.i_nb *sizeof(tmap_t) );
987 if( tmap.p_tmap == NULL )
989 intf_ErrMsg( "Out of memory" );
993 for( i=0 ; i<tmap.i_nb ; i++ )
995 GETC( &tmap.p_tmap[i].i_time_unit );
997 GETS( &tmap.p_tmap[i].i_entry_nb );
998 tmap.p_tmap[i].pi_sector =
999 malloc( tmap.p_tmap[i].i_entry_nb *sizeof(u32) );
1000 if( tmap.p_tmap[i].pi_sector == NULL )
1002 intf_ErrMsg( "Out of memory" );
1006 for( j=0 ; j<tmap.p_tmap[i].i_entry_nb ; j++ )
1008 GETL( &tmap.p_tmap[i].pi_sector[j] );
1016 /*****************************************************************************
1017 * ReadVTS : Parse vts*.ifo files to fill the Video Title Set structure.
1018 *****************************************************************************/
1019 static vts_t ReadVTS( ifo_t* p_ifo )
1023 vts.i_pos = p_ifo->i_pos;
1025 vts.mat = ReadVTSInfMat( p_ifo );
1026 if( vts.mat.i_ptt_srpt_ssector )
1028 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
1029 vts.mat.i_ptt_srpt_ssector *DVD_LB_SIZE,
1031 vts.ptt_srpt = ReadVTSTitlePointer( p_ifo );
1033 if( vts.mat.i_m_pgci_ut_ssector )
1035 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
1036 vts.mat.i_m_pgci_ut_ssector *DVD_LB_SIZE,
1038 vts.pgci_ut = ReadUnitTable( p_ifo );
1040 if( vts.mat.i_pgcit_ssector )
1042 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
1043 vts.mat.i_pgcit_ssector *DVD_LB_SIZE,
1045 vts.pgci_ti = ReadUnit( p_ifo );
1047 if( vts.mat.i_tmap_ti_ssector )
1049 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
1050 vts.mat.i_tmap_ti_ssector *DVD_LB_SIZE,
1052 vts.tmap_ti = ReadVTSTimeMap( p_ifo );
1054 if( vts.mat.i_m_c_adt_ssector )
1056 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
1057 vts.mat.i_m_c_adt_ssector *DVD_LB_SIZE,
1059 vts.m_c_adt = ReadCellInf( p_ifo );
1061 if( vts.mat.i_m_vobu_admap_ssector )
1063 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
1064 vts.mat.i_m_vobu_admap_ssector *DVD_LB_SIZE,
1066 vts.m_vobu_admap = ReadMap( p_ifo );
1068 if( vts.mat.i_c_adt_ssector )
1070 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
1071 vts.mat.i_c_adt_ssector *DVD_LB_SIZE,
1073 vts.c_adt = ReadCellInf( p_ifo );
1075 if( vts.mat.i_vobu_admap_ssector )
1077 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
1078 vts.mat.i_vobu_admap_ssector *DVD_LB_SIZE,
1080 vts.vobu_admap = ReadMap( p_ifo );
1087 * DVD Information Management
1090 /*****************************************************************************
1091 * IfoRead : Function that fills structure and calls specified functions
1093 *****************************************************************************/
1094 void IfoRead( ifo_t* p_ifo )
1099 /* Video Manager Initialization */
1100 intf_WarnMsg( 2, "ifo: initializing VMG" );
1101 p_ifo->vmg = ReadVMG( p_ifo );
1103 /* Video Title Sets initialization */
1104 p_ifo->p_vts = malloc( p_ifo->vmg.mat.i_tts_nb *sizeof(vts_t) );
1105 if( p_ifo->p_vts == NULL )
1107 intf_ErrMsg( "Out of memory" );
1111 for( i=0 ; i<p_ifo->vmg.mat.i_tts_nb ; i++ )
1114 intf_WarnMsg( 2, "ifo: initializing VTS %d", i+1 );
1116 i_off = (off_t)(p_ifo->vmg.ptt_srpt.p_tts[i].i_ssector) *DVD_LB_SIZE;
1117 p_ifo->i_pos = lseek( p_ifo->i_fd, i_off, SEEK_SET );
1118 //fprintf( stderr, "%lld\n" , p_ifo->i_pos );
1120 /* FIXME : use udf filesystem to avoid this */
1121 IfoFindVTS( p_ifo );
1122 p_ifo->p_vts[i] = ReadVTS( p_ifo );
1128 * IFO virtual machine : a set of commands that give the
1129 * interactive behaviour of the dvd
1133 #define OP_VAL_16(i) (ntoh16( com.data.pi_16[i]))
1134 #define OP_VAL_8(i) ((com.data.pi_8[i]))
1136 static char ifo_reg[][80]=
1138 "Menu_Language_Code",
1140 "SubPicture_Stream_#",
1146 "Highlighted_Button_#",
1149 "Karaoke_audio_mixing_mode",
1150 "Parental_mgmt_country_code",
1154 "Audio_language_code_setting",
1155 "Audio_language_extension_code",
1156 "SPU_language_code_setting",
1157 "SPU_language_extension_code",
1158 "?Player_Regional_Code",
1164 static char * IfoMath( char val )
1166 static char math_op[][10] =
1186 return (char *) math_op[val & 0x0f];
1190 char ifo_cmp[][10] =
1202 char ifo_parental[][10] =
1214 char ifo_menu_id[][80] =
1226 char * IfoMenuName( char index )
1228 return ifo_menu_id[index&0x07];
1231 static void IfoRegister( u16 i_data, u8 i_direct)
1235 if( 0/*isalpha( i_data >> 8 & 0xff )*/ )
1237 printf("'%c%c'", i_data>>8&0xff, i_data&0xff);
1241 printf("0x%02x", i_data);
1256 printf("s[%s]", ifo_reg[i_data]);
1269 printf("r[0x%02x]", i_data);
1275 static void IfoAdvanced( u8 *pi_code )
1277 u8 i_cmd = pi_code[0];
1283 printf( " Highlight button %d; ", pi_code[1]>>2 );
1288 printf( " Illegal " );
1293 printf( "ReSuME %d", pi_code[7] );
1295 else if( ( i_cmd & 0x06) == 0x02 )
1297 printf ("Link to %s cell ", ( i_cmd & 0x01 ) ? "prev" : "next");
1301 printf( "advanced (0x%02x) ", i_cmd );
1306 static void IfoJmp( ifo_command_t com )
1311 switch( com.i_sub_cmd )
1317 printf( "VTS 0x%02x", OP_VAL_8(3) );
1320 printf( "This VTS Title 0x%02x", OP_VAL_8(3) );
1323 printf( "This VTS Title 0x%02x Part 0x%04x",
1325 OP_VAL_8(0)<<8|OP_VAL_8(1));
1329 printf ("in SystemSpace ");
1330 switch (OP_VAL_8(3)>>4) {
1332 printf ("to play first PGC");
1335 printf ("to menu \"%s\"", decode_menuname (OP_VAL_8(3)));
1339 printf ("to VTS 0x%02x and TTN 0x%02x", OP_VAL_8(1), OP_VAL_8(2));
1342 printf ("to VMGM PGC number 0x%02x", OP_VAL_8(0)<<8 | OP_VAL_8(1));
1345 printf ("vts 0x%02x lu 0x%02x menu \"%s\"", OP_VAL_8(2), OP_VAL_8(1), decode_menuname (OP_VAL_8(3)));
1348 switch( OP_VAL_8(3)>>6 )
1351 printf( "to play first PGC" );
1354 printf( "to VMG title menu (?)" );
1357 printf( "vts 0x%02x lu 0x%02x menu \"%s\"",
1360 IfoMenuName( OP_VAL_8(3)&0xF ) );
1363 printf( "vmg pgc 0x%04x (?)", ( OP_VAL_8(0)<<8) | OP_VAL_8(1) );
1370 switch(OP_VAL_8(3)>>4) {
1372 printf ("system first pgc");
1375 printf ("system title menu");
1378 printf ("system menu \"%s\"", decode_menuname (OP_VAL_8(3)));
1381 printf ("system vmg pgc %02x ????", OP_VAL_8(0)<<8|OP_VAL_8(1));
1384 printf ("system lu 0x%02x menu \"%s\"", OP_VAL_8(2), decode_menuname (OP_VAL_8(3)));
1387 printf ("system vmg pgc 0x%02x", OP_VAL_8(0)<<8|OP_VAL_8(1));
1391 // OP_VAL_8(2) is number of cell
1392 // it is processed BEFORE switch
1393 // under some conditions, it is ignored
1394 // I don't understand exactly what it means
1395 printf( " ( spec cell 0x%02X ) ", OP_VAL_8(2) );
1397 switch( OP_VAL_8(3)>>6 )
1400 printf( "to FP PGC" );
1403 printf( "to VMG root menu (?)" );
1406 printf( "to VTS menu \"%s\" (?)",
1407 IfoMenuName(OP_VAL_8(3)&0xF) );
1410 printf( "vmg pgc 0x%02x (?)", (OP_VAL_8(0)<<8)|OP_VAL_8(1) );
1418 static void IfoLnk( ifo_command_t com )
1420 u16 i_button=OP_VAL_8(4)>>2;
1424 switch( com.i_sub_cmd )
1427 IfoAdvanced( &OP_VAL_8(4) );
1431 printf( "PGC 0x%02x", OP_VAL_16(2) );
1435 printf( "PTT 0x%02x", OP_VAL_16(2) );
1439 printf( "Program 0x%02x this PGC", OP_VAL_8(5) );
1443 printf( "Cell 0x%02x this PGC", OP_VAL_8(5) );
1451 printf( ", Highlight 0x%02x", OP_VAL_8(4)>>2 );
1456 void IfoSetSystem( ifo_command_t com )
1463 for( i=1; i<=3; i++ )
1465 if( OP_VAL_8(i)&0x80 )
1469 printf ("s[%s] = 0x%02x;", ifo_reg[i], OP_VAL_8(i)&0xf);
1473 printf ("s[%s] = r[0x%02x];", ifo_reg[i], OP_VAL_8(i)&0xf);
1479 if(OP_VAL_8(1]&0x80)
1480 printf ("s[%s] = 0x%02x;", reg_name[1], OP_VAL_8(1]&0xf);
1481 if(OP_VAL_8(2)&0x80)
1482 //DENT: lwhat about 0x7f here ???
1483 printf ("s[%s] = 0x%02x;", reg_name[2], OP_VAL_8(2)&0x7f);
1484 if(OP_VAL_8(3)&0x80)
1485 printf ("s[%s] = 0x%02x;", reg_name[3], OP_VAL_8(3)&0xf);
1487 if(OP_VAL_8(1)&0x80)
1488 printf ("s[%s] = r[0x%02x];", reg_name[1], OP_VAL_8(1)&0xf);
1489 if(OP_VAL_8(2)&0x80)
1490 printf ("s[%s] = r[0x%02x];", reg_name[2], OP_VAL_8(2)&0xf);
1491 if(OP_VAL_8(3)&0x80)
1492 printf ("s[%s] = r[0x%02x];", reg_name[3], OP_VAL_8(3)&0xf);
1500 printf( "s[%s] = 0x%02x", ifo_reg[9], OP_VAL_16(0) );
1504 printf( "s[%s] = r[0x%02x]", ifo_reg[9], OP_VAL_8(1)&0x0f );
1507 printf( "s[%s] = (s[%s]&0x7FFF)|0x%02x",
1508 ifo_reg[10], ifo_reg[10], OP_VAL_16(1)&0x8000);
1513 printf( "r[0x%02x] = 0x%02x", OP_VAL_8(3)&0x0f, OP_VAL_16(0) );
1517 printf ("r[r[0x%02x]] = r[0x%02x]",
1518 OP_VAL_8(3)&0x0f, OP_VAL_8(1)&0x0f);
1522 //actually only bits 00011100 00011100 are set
1525 printf ("s[%s] = 0x%02x", ifo_reg[11], OP_VAL_16(1));
1529 printf ("s[%s] = r[0x%02x]", ifo_reg[11], OP_VAL_8(3)&0x0f );
1534 //s[%s]=(r[%s]&0x3FF) | (0x%02x << 0xA);
1535 //but it is way too ugly
1538 printf( "s[%s] = 0x%02x", ifo_reg[8], OP_VAL_8(2)>>2 );
1542 printf( "s[%s] = r[0x%02x]", ifo_reg[8], OP_VAL_8(3)&0x0f );
1550 static void IfoSet( ifo_command_t com )
1552 IfoRegister( OP_VAL_16(0), 0 );
1553 printf( " %s ", IfoMath( com.i_cmd ) );
1554 IfoRegister( OP_VAL_16(1), com.i_direct );
1557 /*****************************************************************************
1558 * CommandRead : translates the command strings in ifo into command
1560 *****************************************************************************/
1561 void CommandRead( ifo_command_t com )
1563 u8* pi_code = (u8*)(&com);
1565 switch( com.i_type )
1578 printf ("if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
1579 ifo_cmp[com.i_cmp]);
1580 IfoRegister (OP_VAL_16(1), com.i_dir_cmp);
1585 switch( com.i_sub_cmd )
1588 printf( "goto Line 0x%02x", OP_VAL_16(2) );
1592 printf( "stop VM" );
1596 printf( "Set Parental Level To %s and goto Line 0x%02x",
1597 ifo_parental[OP_VAL_8(4)&0x7],
1602 printf( "Illegal" );
1621 printf( "if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f,
1622 ifo_cmp[com.i_cmp] );
1623 IfoRegister( OP_VAL_8(5), 0 );
1634 printf( "if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
1635 ifo_cmp[com.i_cmp] );
1636 IfoRegister( OP_VAL_16(1), com.i_dir_cmp );
1650 IfoSetSystem( com );
1652 else if( com.i_cmp && !com.i_sub_cmd )
1654 printf ("if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f, ifo_cmp[com.i_cmp]);
1655 IfoRegister( OP_VAL_8(5), 0 );
1657 IfoSetSystem( com );
1659 else if( !com.i_cmp && com.i_sub_cmd )
1662 IfoSetSystem( com );
1678 else if( com.i_cmp && !com.i_sub_cmd )
1680 printf ("if (r[0x%02x] %s ", OP_VAL_8(0)&0x0f, ifo_cmp[com.i_cmp]);
1681 IfoRegister( OP_VAL_16(2), com.i_dir_cmp );
1685 else if( !com.i_cmp && com.i_sub_cmd )
1699 * math command on r[opcode[1]] and
1700 * direct?be2me_16(OP_VAL_8(0)):reg[OP_VAL_8(1)] is executed
1701 * ( unless command is swap; then r[opcode[1]] and r[OP_VAL_8(1)]
1703 * boolean operation cmp on r[opcode[1]] and
1704 * dir_cmp?be2me_16(OP_VAL_8(1)[1]):reg[OP_VAL_8(3)] is executed
1705 * on true result, buttons(c[6], c[7]) is called
1706 * problem is 'what is buttons()'
1709 printf( "r[0x%X] ", pi_code[1] );
1710 printf( " %s ", IfoMath( com.i_cmd ) );
1711 if( com.i_cmd == 2 )
1713 printf( "r[0x%X] ", OP_VAL_8(1) );
1717 IfoRegister( OP_VAL_16(0), com.i_direct );
1721 printf( "if ( r[%d] %s ", pi_code[1], ifo_cmp[com.i_cmp] );
1722 IfoRegister( OP_VAL_8(1), com.i_dir_cmp );
1723 printf( " ) then {" );
1724 IfoAdvanced( &OP_VAL_8(4) );
1729 * opposite to case 4: boolean, math and buttons.
1735 if( !com.i_direct && com.i_dir_cmp )
1737 printf( "0x%X", OP_VAL_16(1) );
1741 IfoRegister( OP_VAL_8(3), 0 );
1742 if( OP_VAL_8(3)&0x80 )
1744 printf( "s[%s]", ifo_reg[OP_VAL_8(3)&0x1F] );
1748 printf( "r[0x%X]", OP_VAL_8(3)&0x1F);
1749 // 0x1F is either not a mistake,
1750 // or Microsoft programmer's mistake!!!
1754 printf( " %s r[0x%X] ", ifo_cmp[com.i_cmp],
1755 com.i_direct ? OP_VAL_8(2) : OP_VAL_8(1) );
1756 printf( " ) then {" );
1757 printf( "r[0x%X] ", pi_code[1] & 0xF );
1758 printf( " %s ", IfoMath( com.i_cmd ) );
1760 if( com.i_cmd == 0x02 ) // swap
1762 printf("r[0x%X] ", OP_VAL_8(0)&0x1F);
1768 printf( "0x%X", OP_VAL_16(0) );
1772 if( OP_VAL_8(0) & 0x80 )
1774 printf("s[%s]", ifo_reg[OP_VAL_8(0) & 0x1F] );
1778 printf("r[0x%X]", OP_VAL_8(0) & 0x1F );
1784 IfoAdvanced( &OP_VAL_8(4) );
1790 printf( "Unknown Command\n" );
1797 /*****************************************************************************
1798 * CommandPrint : print in clear text (I hope so !) what a command does
1799 *****************************************************************************/
1800 void CommandPrint( ifo_t ifo )