1 /*****************************************************************************
2 * dvd_ifo.c: Functions for ifo parsing
3 *****************************************************************************
4 * Copyright (C) 1999-2001 VideoLAN
5 * $Id: dvd_ifo.c,v 1.8 2001/02/15 21:03:27 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 *****************************************************************************/
41 #include "input_dvd.h"
43 void CommandRead( ifo_command_t );
49 /*****************************************************************************
50 * IfoFindVMG : When reading directly on a device, finds the offset to the
51 * beginning of video_ts.ifo.
52 *****************************************************************************/
53 static int IfoFindVMG( ifo_t* p_ifo )
55 char psz_ifo_start[12] = "DVDVIDEO-VMG";
58 read( p_ifo->i_fd, psz_test, 12 );
60 while( strncmp( psz_test, psz_ifo_start, 12 ) != 0 )
62 /* The start of ifo file is on a sector boundary */
63 p_ifo->i_pos = lseek( p_ifo->i_fd,
64 p_ifo->i_pos + DVD_LB_SIZE,
66 read( p_ifo->i_fd, psz_test, 12 );
68 p_ifo->i_off = p_ifo->i_pos;
70 fprintf( stderr, "VMG Off : %lld\n", (long long)(p_ifo->i_off) );
75 /*****************************************************************************
76 * IfoFindVTS : beginning of vts_*.ifo.
77 *****************************************************************************/
78 static int IfoFindVTS( ifo_t* p_ifo )
80 char psz_ifo_start[12] = "DVDVIDEO-VTS";
83 read( p_ifo->i_fd, psz_test, 12 );
85 while( strncmp( psz_test, psz_ifo_start, 12 ) != 0 )
87 /* The start of ifo file is on a sector boundary */
88 p_ifo->i_pos = lseek( p_ifo->i_fd,
89 p_ifo->i_pos + DVD_LB_SIZE,
91 read( p_ifo->i_fd, psz_test, 12 );
93 p_ifo->i_off = p_ifo->i_pos;
95 fprintf( stderr, "VTS Off : %lld\n", (long long)(p_ifo->i_off) );
100 /*****************************************************************************
101 * IfoInit : Creates an ifo structure and prepares for parsing directly
103 *****************************************************************************/
104 ifo_t IfoInit( int i_fd )
108 /* If we are here the dvd device has already been opened */
110 /* No data at the beginning of the disk
111 * 512000 bytes is just another value :) */
112 ifo.i_pos = lseek( ifo.i_fd, 250 *DVD_LB_SIZE, SEEK_SET );
113 /* FIXME : use udf filesystem to find the beginning of the file */
119 /*****************************************************************************
120 * IfoEnd : Frees all the memory allocated to ifo structures
121 *****************************************************************************/
122 void IfoEnd( ifo_t* p_ifo )
126 /* Free structures from video title sets */
127 for( j=0 ; j<p_ifo->vmg.mat.i_tts_nb ; j++ )
129 free( p_ifo->p_vts[j].vobu_admap.pi_vobu_ssector );
130 free( p_ifo->p_vts[j].c_adt.p_cell_inf );
131 free( p_ifo->p_vts[j].m_vobu_admap.pi_vobu_ssector );
132 free( p_ifo->p_vts[j].m_c_adt.p_cell_inf );
133 for( i=0 ; i<p_ifo->p_vts[j].tmap_ti.i_nb ; i++ )
135 free( p_ifo->p_vts[j].tmap_ti.p_tmap[i].pi_sector );
137 free( p_ifo->p_vts[j].tmap_ti.pi_sbyte );
138 free( p_ifo->p_vts[j].tmap_ti.p_tmap );
139 free( p_ifo->p_vts[j].pgci_ti.p_srp );
140 for( i=0 ; i<p_ifo->p_vts[j].pgci_ut.i_lu_nb ; i++ )
142 free( p_ifo->p_vts[j].pgci_ut.p_pgci_inf[i].p_srp );
144 free( p_ifo->p_vts[j].pgci_ut.p_pgci_inf );
145 free( p_ifo->p_vts[j].pgci_ut.p_lu );
148 free( p_ifo->p_vts );
150 /* Free structures from video manager */
151 free( p_ifo->vmg.vobu_admap.pi_vobu_ssector );
152 free( p_ifo->vmg.c_adt.p_cell_inf );
153 for( i=0 ; i<p_ifo->vmg.pgci_ut.i_lu_nb ; i++ )
155 free( p_ifo->vmg.pgci_ut.p_pgci_inf[i].p_srp );
157 free( p_ifo->vmg.pgci_ut.p_pgci_inf );
158 free( p_ifo->vmg.pgci_ut.p_lu );
159 for( i=1 ; i<=8 ; i++ )
161 free( p_ifo->vmg.ptl_mait.p_ptl_mask->ppi_ptl_mask[i] );
163 free( p_ifo->vmg.ptl_mait.p_ptl_desc );
164 free( p_ifo->vmg.ptl_mait.p_ptl_mask );
165 free( p_ifo->vmg.vts_atrt.pi_vts_atrt_sbyte );
166 free( p_ifo->vmg.vts_atrt.p_vts_atrt );
167 free( p_ifo->vmg.pgc.p_cell_pos_inf );
168 free( p_ifo->vmg.pgc.p_cell_play_inf );
169 free( p_ifo->vmg.pgc.prg_map.pi_entry_cell );
170 free( p_ifo->vmg.pgc.com_tab.p_cell_com );
171 free( p_ifo->vmg.pgc.com_tab.p_post_com );
172 free( p_ifo->vmg.pgc.com_tab.p_pre_com );
178 * Macros to process ifo files
181 #define GET( p_field , i_len ) \
183 read( p_ifo->i_fd , (p_field) , (i_len) ); \
184 /*fprintf(stderr, "Pos : %lld Val : %llx\n", \
185 (long long)(p_ifo->i_pos - i_start), \
186 (long long)*(p_field) ); */ \
187 p_ifo->i_pos += i_len; \
190 #define GETC( p_field ) \
192 read( p_ifo->i_fd , (p_field) , 1 ); \
193 /*fprintf(stderr, "Pos : %lld Value : %d\n", \
194 (long long)(p_ifo->i_pos - i_start), \
199 #define GETS( p_field ) \
201 read( p_ifo->i_fd , (p_field) , 2 ); \
202 *(p_field) = ntohs( *(p_field) ); \
203 /*fprintf(stderr, "Pos : %lld Value : %d\n", \
204 (long long)(p_ifo->i_pos - i_start), \
209 #define GETL( p_field ) \
211 read( p_ifo->i_fd , (p_field) , 4 ); \
212 *(p_field) = ntohl( *(p_field) ); \
213 /*fprintf(stderr, "Pos : %lld Value : %d\n", \
214 (long long)(p_ifo->i_pos - i_start), \
219 #define GETLL( p_field ) \
221 read( p_ifo->i_fd , (p_field) , 8 ); \
222 *(p_field) = ntoh64( *(p_field) ); \
223 /*fprintf(stderr, "Pos : %lld Value : %lld\n", \
224 (long long)(p_ifo->i_pos - i_start), \
229 #define FLUSH( i_len ) \
231 /*fprintf(stderr, "Pos : %lld\n", (long long)(p_ifo->i_pos - i_start));*/ \
232 p_ifo->i_pos = lseek( p_ifo->i_fd , \
233 p_ifo->i_pos + (i_len), SEEK_SET ); \
237 * Function common to Video Manager and Video Title set Processing
240 /*****************************************************************************
241 * ReadPGC : Fills the Program Chain structure.
242 *****************************************************************************/
243 #define GETCOMMAND( p_com ) \
245 read( p_ifo->i_fd , (p_com) , 8 ); \
246 /*fprintf(stderr, "Pos : %lld Type : %d direct : %d cmd : %d dircmp : %d cmp : %d subcmd : %d v0 : %d v2 : %d v4 : %d\n", \
247 (long long)(p_ifo->i_pos - i_start), \
248 (int)((p_com)->i_type), \
249 (int)((p_com)->i_direct), \
250 (int)((p_com)->i_cmd), \
251 (int)((p_com)->i_dir_cmp), \
252 (int)((p_com)->i_cmp), \
253 (int)((p_com)->i_sub_cmd), \
254 (int)((p_com)->data.pi_16[0]), \
255 (int)((p_com)->data.pi_16[1]), \
256 (int)((p_com)->data.pi_16[2]));*/ \
257 /* CommandRead( *(p_com) );*/ \
261 static pgc_t ReadPGC( ifo_t* p_ifo )
265 off_t i_start = p_ifo->i_pos;
267 //fprintf( stderr, "PGC\n" );
270 GETC( &pgc.i_prg_nb );
271 GETC( &pgc.i_cell_nb );
272 GETL( &pgc.i_play_time );
273 GETL( &pgc.i_prohibited_user_op );
274 for( i=0 ; i<8 ; i++ )
276 GETS( &pgc.pi_audio_status[i] );
278 for( i=0 ; i<32 ; i++ )
280 GETL( &pgc.pi_subpic_status[i] );
282 GETS( &pgc.i_next_pgc_nb );
283 GETS( &pgc.i_prev_pgc_nb );
284 GETS( &pgc.i_goup_pgc_nb );
285 GETC( &pgc.i_still_time );
286 GETC( &pgc.i_play_mode );
287 for( i=0 ; i<16 ; i++ )
289 GETL( &pgc.pi_yuv_color[i] );
290 /* FIXME : We have to erase the extra bit */
292 GETS( &pgc.i_com_tab_sbyte );
293 GETS( &pgc.i_prg_map_sbyte );
294 GETS( &pgc.i_cell_play_inf_sbyte );
295 GETS( &pgc.i_cell_pos_inf_sbyte );
297 /* Parsing of pgc_com_tab_t */
298 if( pgc.i_com_tab_sbyte )
300 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
301 + pgc.i_com_tab_sbyte, SEEK_SET );
302 GETS( &pgc.com_tab.i_pre_com_nb );
303 GETS( &pgc.com_tab.i_post_com_nb );
304 GETS( &pgc.com_tab.i_cell_com_nb );
306 if( pgc.com_tab.i_pre_com_nb )
308 pgc.com_tab.p_pre_com =
309 malloc(pgc.com_tab.i_pre_com_nb *sizeof(ifo_command_t));
310 if( pgc.com_tab.p_pre_com == NULL )
312 intf_ErrMsg( "Out of memory" );
316 for( i=0 ; i<pgc.com_tab.i_pre_com_nb ; i++ )
318 GETCOMMAND( &pgc.com_tab.p_pre_com[i] );
321 if( pgc.com_tab.i_post_com_nb )
323 pgc.com_tab.p_post_com =
324 malloc(pgc.com_tab.i_post_com_nb *sizeof(ifo_command_t));
325 if( pgc.com_tab.p_post_com == NULL )
327 intf_ErrMsg( "Out of memory" );
331 for( i=0 ; i<pgc.com_tab.i_post_com_nb ; i++ )
333 GETCOMMAND( &pgc.com_tab.p_post_com[i] );
336 if( pgc.com_tab.i_cell_com_nb )
338 pgc.com_tab.p_cell_com =
339 malloc(pgc.com_tab.i_cell_com_nb *sizeof(ifo_command_t));
340 if( pgc.com_tab.p_cell_com == NULL )
342 intf_ErrMsg( "Out of memory" );
346 for( i=0 ; i<pgc.com_tab.i_cell_com_nb ; i++ )
348 GETCOMMAND( &pgc.com_tab.p_cell_com[i] );
352 /* Parsing of pgc_prg_map_t */
353 if( pgc.i_prg_map_sbyte )
355 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
356 + pgc.i_prg_map_sbyte, SEEK_SET );
357 pgc.prg_map.pi_entry_cell = malloc( pgc.i_prg_nb *sizeof(u8) );
358 if( pgc.prg_map.pi_entry_cell == NULL )
360 intf_ErrMsg( "Out of memory" );
364 GET( pgc.prg_map.pi_entry_cell, pgc.i_prg_nb );
365 /* FIXME : check endianness here */
367 /* Parsing of cell_play_inf_t */
368 if( pgc.i_cell_play_inf_sbyte )
370 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
371 + pgc.i_cell_play_inf_sbyte, SEEK_SET );
372 pgc.p_cell_play_inf = malloc( pgc.i_cell_nb *sizeof(cell_play_inf_t) );
373 if( pgc.p_cell_play_inf == NULL )
375 intf_ErrMsg( "Out of memory" );
379 for( i=0 ; i<pgc.i_cell_nb ; i++ )
381 GETS( &pgc.p_cell_play_inf[i].i_cat );
382 GETC( &pgc.p_cell_play_inf[i].i_still_time );
383 GETC( &pgc.p_cell_play_inf[i].i_com_nb );
384 GETL( &pgc.p_cell_play_inf[i].i_play_time );
385 GETL( &pgc.p_cell_play_inf[i].i_entry_sector );
386 GETL( &pgc.p_cell_play_inf[i].i_first_ilvu_vobu_esector );
387 GETL( &pgc.p_cell_play_inf[i].i_lvobu_ssector );
388 GETL( &pgc.p_cell_play_inf[i].i_lsector );
391 /* Parsing of cell_pos_inf_map */
392 if( pgc.i_cell_pos_inf_sbyte )
394 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
395 + pgc.i_cell_pos_inf_sbyte, SEEK_SET );
396 pgc.p_cell_pos_inf = malloc( pgc.i_cell_nb *sizeof(cell_pos_inf_t) );
397 if( pgc.p_cell_play_inf == NULL )
399 intf_ErrMsg( "Out of memory" );
403 for( i=0 ; i<pgc.i_cell_nb ; i++ )
405 GETS( &pgc.p_cell_pos_inf[i].i_vob_id );
407 GETC( &pgc.p_cell_pos_inf[i].i_cell_id );
414 /*****************************************************************************
415 * ReadUnit : Fills Menu Language Unit Table/ PGC Info Table
416 *****************************************************************************/
417 static pgci_inf_t ReadUnit( ifo_t* p_ifo )
421 off_t i_start = p_ifo->i_pos;
423 //fprintf( stderr, "Unit\n" );
425 GETS( &inf.i_srp_nb );
427 GETL( &inf.i_lu_ebyte );
428 inf.p_srp = malloc( inf.i_srp_nb *sizeof(pgci_srp_t) );
429 if( inf.p_srp == NULL )
431 intf_ErrMsg( "Out of memory" );
435 for( i=0 ; i<inf.i_srp_nb ; i++ )
437 GETC( &inf.p_srp[i].i_pgc_cat_mask );
438 GETC( &inf.p_srp[i].i_pgc_cat );
439 GETS( &inf.p_srp[i].i_par_mask );
440 GETL( &inf.p_srp[i].i_pgci_sbyte );
442 for( i=0 ; i<inf.i_srp_nb ; i++ )
444 p_ifo->i_pos = lseek( p_ifo->i_fd,
445 i_start + inf.p_srp[i].i_pgci_sbyte,
447 inf.p_srp[i].pgc = ReadPGC( p_ifo );
453 /*****************************************************************************
454 * ReadUnitTable : Fills the PGCI Unit structure.
455 *****************************************************************************/
456 static pgci_ut_t ReadUnitTable( ifo_t* p_ifo )
460 off_t i_start = p_ifo->i_pos;
462 //fprintf( stderr, "Unit Table\n" );
464 GETS( &pgci.i_lu_nb );
466 GETL( &pgci.i_ebyte );
467 pgci.p_lu = malloc( pgci.i_lu_nb *sizeof(pgci_lu_t) );
468 if( pgci.p_lu == NULL )
470 intf_ErrMsg( "Out of memory" );
474 for( i=0 ; i<pgci.i_lu_nb ; i++ )
476 GET( pgci.p_lu[i].ps_lang_code, 2 );
478 GETC( &pgci.p_lu[i].i_existence_mask );
479 GETL( &pgci.p_lu[i].i_lu_sbyte );
481 pgci.p_pgci_inf = malloc( pgci.i_lu_nb *sizeof(pgci_inf_t) );
482 if( pgci.p_pgci_inf == NULL )
484 intf_ErrMsg( "Out of memory" );
488 for( i=0 ; i<pgci.i_lu_nb ; i++ )
490 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start +
491 pgci.p_lu[i].i_lu_sbyte,
493 pgci.p_pgci_inf[i] = ReadUnit( p_ifo );
499 /*****************************************************************************
500 * ReadCellInf : Fills the Cell Information structure.
501 *****************************************************************************/
502 static c_adt_t ReadCellInf( ifo_t* p_ifo )
505 off_t i_start = p_ifo->i_pos;
508 //fprintf( stderr, "CELL ADD\n" );
510 GETS( &c_adt.i_vob_nb );
512 GETL( &c_adt.i_ebyte );
514 ( i_start + c_adt.i_ebyte + 1 - p_ifo->i_pos ) / sizeof(cell_inf_t);
515 c_adt.p_cell_inf = malloc( c_adt.i_cell_nb *sizeof(cell_inf_t) );
516 if( c_adt.p_cell_inf == NULL )
518 intf_ErrMsg( "Out of memory" );
522 for( i = 0 ; i < c_adt.i_cell_nb ; i++ )
524 GETS( &c_adt.p_cell_inf[i].i_vob_id );
525 GETC( &c_adt.p_cell_inf[i].i_cell_id );
527 GETL( &c_adt.p_cell_inf[i].i_ssector );
528 GETL( &c_adt.p_cell_inf[i].i_esector );
534 /*****************************************************************************
535 * ReadMap : Fills the VOBU Map structure.
536 *****************************************************************************/
537 static vobu_admap_t ReadMap( ifo_t* p_ifo )
541 off_t i_start = p_ifo->i_pos;
543 //fprintf( stderr, "VOBU ADMAP\n" );
545 GETL( &map.i_ebyte );
546 i_max = ( i_start + map.i_ebyte + 1 - p_ifo->i_pos ) / sizeof(u32);
547 map.pi_vobu_ssector = malloc( i_max *sizeof(u32) );
548 for( i=0 ; i<i_max ; i++ )
550 GETL( &map.pi_vobu_ssector[i] );
557 * Video Manager Information Processing.
558 * This is what is contained in video_ts.ifo.
561 /*****************************************************************************
562 * ReadVMGInfMat : Fills the Management Information structure.
563 *****************************************************************************/
564 static vmgi_mat_t ReadVMGInfMat( ifo_t* p_ifo )
568 // off_t i_start = p_ifo->i_pos;
570 //fprintf( stderr, "VMGI\n" );
572 GET( mat.psz_id , 12 );
573 mat.psz_id[12] = '\0';
574 GETL( &mat.i_lsector );
576 GETL( &mat.i_i_lsector );
578 GETC( &mat.i_spec_ver );
580 GETS( &mat.i_vol_nb );
582 GETC( &mat.i_disc_side );
584 GETS( &mat.i_tts_nb );
585 GET( mat.ps_provider_id, 32 );
586 GETLL( &mat.i_pos_code );
588 GETL( &mat.i_i_mat_ebyte );
589 GETL( &mat.i_fp_pgc_sbyte );
591 GETL( &mat.i_vobs_ssector );
592 GETL( &mat.i_ptt_srpt_ssector );
593 GETL( &mat.i_pgci_ut_ssector );
594 GETL( &mat.i_ptl_mait_ssector );
595 GETL( &mat.i_vts_atrt_ssector );
596 GETL( &mat.i_txtdt_mg_ssector );
597 GETL( &mat.i_c_adt_ssector );
598 GETL( &mat.i_vobu_admap_ssector );
600 GETS( &mat.i_video_atrt );
602 GETC( &mat.i_audio_nb );
603 //fprintf( stderr, "vmgi audio nb : %d\n", mat.i_audio_nb );
604 for( i=0 ; i < 8 ; i++ )
606 GETLL( &mat.pi_audio_atrt[i] );
609 GETC( &mat.i_subpic_nb );
610 //fprintf( stderr, "vmgi subpic nb : %d\n", mat.i_subpic_nb );
611 for( i=0 ; i < mat.i_subpic_nb ; i++ )
613 GET( &mat.pi_subpic_atrt[i], 6 );
614 /* FIXME : take care of endianness */
620 /*****************************************************************************
621 * ReadVMGTitlePointer : Fills the Part Of Title Search Pointer structure.
622 *****************************************************************************/
623 static vmg_ptt_srpt_t ReadVMGTitlePointer( ifo_t* p_ifo )
627 // off_t i_start = p_ifo->i_pos;
629 //fprintf( stderr, "PTR\n" );
631 GETS( &ptr.i_ttu_nb );
633 GETL( &ptr.i_ebyte );
635 ptr.p_tts = malloc( ptr.i_ttu_nb *sizeof(tts_t) );
636 if( ptr.p_tts == NULL )
638 intf_ErrMsg( "Out of memory" );
642 for( i=0 ; i<ptr.i_ttu_nb ; i++ )
644 GETC( &ptr.p_tts[i].i_play_type );
645 GETC( &ptr.p_tts[i].i_angle_nb );
646 GETS( &ptr.p_tts[i].i_ptt_nb );
647 GETS( &ptr.p_tts[i].i_parental_id );
648 GETC( &ptr.p_tts[i].i_tts_nb );
649 GETC( &ptr.p_tts[i].i_vts_ttn );
650 GETL( &ptr.p_tts[i].i_ssector );
656 /*****************************************************************************
657 * ReadParentalInf : Fills the Parental Management structure.
658 *****************************************************************************/
659 static vmg_ptl_mait_t ReadParentalInf( ifo_t* p_ifo )
663 off_t i_start = p_ifo->i_pos;
665 //fprintf( stderr, "PTL\n" );
667 GETS( &par.i_country_nb );
668 GETS( &par.i_vts_nb );
669 GETL( &par.i_ebyte );
670 par.p_ptl_desc = malloc( par.i_country_nb *sizeof(vmg_ptl_mai_desc_t) );
671 if( par.p_ptl_desc == NULL )
673 intf_ErrMsg( "Out of memory" );
677 for( i=0 ; i<par.i_country_nb ; i++ )
679 GET( par.p_ptl_desc[i].ps_country_code, 2 );
681 GETS( &par.p_ptl_desc[i].i_ptl_mai_sbyte );
684 par.p_ptl_mask = malloc( par.i_country_nb *sizeof(vmg_ptl_mask_t) );
685 if( par.p_ptl_mask == NULL )
687 intf_ErrMsg( "Out of memory" );
691 for( i=0 ; i<par.i_country_nb ; i++ )
693 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start +
694 par.p_ptl_desc[i].i_ptl_mai_sbyte, SEEK_SET );
695 for( j=1 ; j<=8 ; j++ )
697 par.p_ptl_mask[i].ppi_ptl_mask[j] =
698 malloc( par.i_vts_nb *sizeof(u16) );
699 if( par.p_ptl_mask[i].ppi_ptl_mask[j] == NULL )
701 intf_ErrMsg( "Out of memory" );
705 for( k=0 ; k<par.i_vts_nb ; k++ )
707 GETS( &par.p_ptl_mask[i].ppi_ptl_mask[j][k] );
715 /*****************************************************************************
716 * ReadVTSAttr : Fills the structure about VTS attributes.
717 *****************************************************************************/
718 static vmg_vts_atrt_t ReadVTSAttr( ifo_t* p_ifo )
722 off_t i_start = p_ifo->i_pos;
724 //fprintf( stderr, "VTS ATTR\n" );
726 GETS( &atrt.i_vts_nb );
728 GETL( &atrt.i_ebyte );
729 atrt.pi_vts_atrt_sbyte = malloc( atrt.i_vts_nb *sizeof(u32) );
730 if( atrt.pi_vts_atrt_sbyte == NULL )
732 intf_ErrMsg( "Out of memory" );
736 for( i=0 ; i<atrt.i_vts_nb ; i++ )
738 GETL( &atrt.pi_vts_atrt_sbyte[i] );
740 atrt.p_vts_atrt = malloc( atrt.i_vts_nb *sizeof(vts_atrt_t) );
741 if( atrt.p_vts_atrt == NULL )
743 intf_ErrMsg( "Out of memory" );
747 for( i=0 ; i<atrt.i_vts_nb ; i++ )
749 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start +
750 atrt.pi_vts_atrt_sbyte[i],
752 GETL( &atrt.p_vts_atrt[i].i_ebyte );
753 GETL( &atrt.p_vts_atrt[i].i_cat_app_type );
754 GETS( &atrt.p_vts_atrt[i].i_vtsm_video_atrt );
756 GETC( &atrt.p_vts_atrt[i].i_vtsm_audio_nb );
757 //fprintf( stderr, "m audio nb : %d\n", atrt.p_vts_atrt[i].i_vtsm_audio_nb );
758 for( j=0 ; j<8 ; j++ )
760 GETLL( &atrt.p_vts_atrt[i].pi_vtsm_audio_atrt[j] );
763 GETC( &atrt.p_vts_atrt[i].i_vtsm_subpic_nb );
764 //fprintf( stderr, "m subp nb : %d\n", atrt.p_vts_atrt[i].i_vtsm_subpic_nb );
765 for( j=0 ; j<28 ; j++ )
767 GET( &atrt.p_vts_atrt[i].pi_vtsm_subpic_atrt[j], 6 );
768 /* FIXME : Fix endianness issue here */
771 GETS( &atrt.p_vts_atrt[i].i_vtstt_video_atrt );
773 GETL( &atrt.p_vts_atrt[i].i_vtstt_audio_nb );
774 //fprintf( stderr, "tt audio nb : %d\n", atrt.p_vts_atrt[i].i_vtstt_audio_nb );
775 for( j=0 ; j<8 ; j++ )
777 GETLL( &atrt.p_vts_atrt[i].pi_vtstt_audio_atrt[j] );
780 GETC( &atrt.p_vts_atrt[i].i_vtstt_subpic_nb );
781 //fprintf( stderr, "tt subp nb : %d\n", atrt.p_vts_atrt[i].i_vtstt_subpic_nb );
782 for( j=0 ; j<28/*atrt.p_vts_atrt[i].i_vtstt_subpic_nb*/ ; j++ )
784 GET( &atrt.p_vts_atrt[i].pi_vtstt_subpic_atrt[j], 6 );
785 /* FIXME : Fix endianness issue here */
792 /*****************************************************************************
793 * ReadVMG : Parse video_ts.ifo file to fill the Video Manager structure.
794 *****************************************************************************/
795 static vmg_t ReadVMG( ifo_t* p_ifo )
799 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off, SEEK_SET);
800 vmg.mat = ReadVMGInfMat( p_ifo );
801 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
802 vmg.mat.i_fp_pgc_sbyte, SEEK_SET );
803 vmg.pgc = ReadPGC( p_ifo );
804 if( vmg.mat.i_ptt_srpt_ssector )
806 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
807 vmg.mat.i_ptt_srpt_ssector *DVD_LB_SIZE,
809 vmg.ptt_srpt = ReadVMGTitlePointer( p_ifo );
811 if( vmg.mat.i_pgci_ut_ssector )
813 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
814 vmg.mat.i_pgci_ut_ssector *DVD_LB_SIZE,
816 vmg.pgci_ut = ReadUnitTable( p_ifo );
818 if( vmg.mat.i_ptl_mait_ssector )
820 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
821 vmg.mat.i_ptl_mait_ssector *DVD_LB_SIZE,
823 vmg.ptl_mait = ReadParentalInf( p_ifo );
825 if( vmg.mat.i_vts_atrt_ssector )
827 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
828 vmg.mat.i_vts_atrt_ssector *DVD_LB_SIZE,
830 vmg.vts_atrt = ReadVTSAttr( p_ifo );
832 if( vmg.mat.i_c_adt_ssector )
834 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
835 vmg.mat.i_c_adt_ssector *DVD_LB_SIZE,
837 vmg.c_adt = ReadCellInf( p_ifo );
839 if( vmg.mat.i_vobu_admap_ssector )
841 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
842 vmg.mat.i_vobu_admap_ssector *DVD_LB_SIZE,
844 vmg.vobu_admap = ReadMap( p_ifo );
850 * Video Title Set Information Processing.
851 * This is what is contained in vts_*.ifo.
854 /*****************************************************************************
855 * ReadVTSInfMat : Fills the Title Set Information structure.
856 *****************************************************************************/
857 static vtsi_mat_t ReadVTSInfMat( ifo_t* p_ifo )
861 // off_t i_start = p_ifo->i_pos;
863 //fprintf( stderr, "VTSI\n" );
865 GET( mat.psz_id , 12 );
866 mat.psz_id[12] = '\0';
867 GETL( &mat.i_lsector );
869 GETL( &mat.i_i_lsector );
871 GETC( &mat.i_spec_ver );
874 GETL( &mat.i_mat_ebyte );
876 GETL( &mat.i_m_vobs_ssector );
877 GETL( &mat.i_tt_vobs_ssector );
878 GETL( &mat.i_ptt_srpt_ssector );
879 GETL( &mat.i_pgcit_ssector );
880 GETL( &mat.i_m_pgci_ut_ssector );
881 GETL( &mat.i_tmap_ti_ssector );
882 GETL( &mat.i_m_c_adt_ssector );
883 GETL( &mat.i_m_vobu_admap_ssector );
884 GETL( &mat.i_c_adt_ssector );
885 GETL( &mat.i_vobu_admap_ssector );
887 GETS( &mat.i_m_video_atrt );
889 GETC( &mat.i_m_audio_nb );
890 for( i=0 ; i<8 ; i++ )
892 GETLL( &mat.pi_m_audio_atrt[i] );
895 GETC( &mat.i_m_subpic_nb );
896 for( i=0 ; i<28 ; i++ )
898 GET( &mat.pi_m_subpic_atrt[i], 6 );
899 /* FIXME : take care of endianness */
902 GETS( &mat.i_video_atrt );
904 GETC( &mat.i_audio_nb );
905 //fprintf( stderr, "vtsi audio nb : %d\n", mat.i_audio_nb );
906 for( i=0 ; i<8 ; i++ )
908 GETLL( &mat.pi_audio_atrt[i] );
911 GETC( &mat.i_subpic_nb );
912 //fprintf( stderr, "vtsi subpic nb : %d\n", mat.i_subpic_nb );
913 for( i=0 ; i<mat.i_subpic_nb ; i++ )
915 GET( &mat.pi_subpic_atrt[i], 6 );
916 /* FIXME : take care of endianness */
922 /*****************************************************************************
923 * ReadVTSTitlePointer : Fills the Part Of Title Search Pointer structure.
924 *****************************************************************************/
925 static vts_ptt_srpt_t ReadVTSTitlePointer( ifo_t* p_ifo )
929 off_t i_start = p_ifo->i_pos;
931 //fprintf( stderr, "PTR\n" );
933 GETS( &ptr.i_ttu_nb );
935 GETL( &ptr.i_ebyte );
936 ptr.pi_ttu_sbyte = malloc( ptr.i_ttu_nb *sizeof(u32) );
937 if( ptr.pi_ttu_sbyte == NULL )
939 intf_ErrMsg( "Out of memory" );
943 for( i=0 ; i<ptr.i_ttu_nb ; i++ )
945 GETL( &ptr.pi_ttu_sbyte[i] );
948 ptr.p_ttu = malloc( ptr.i_ttu_nb *sizeof(ttu_t) );
949 if( ptr.p_ttu == NULL )
951 intf_ErrMsg( "Out of memory" );
955 for( i=0 ; i<ptr.i_ttu_nb ; i++ )
957 p_ifo->i_pos = lseek( p_ifo->i_fd, i_start +
958 ptr.pi_ttu_sbyte[i], SEEK_SET );
959 GETS( &ptr.p_ttu[i].i_pgc_nb );
960 GETS( &ptr.p_ttu[i].i_prg_nb );
966 /*****************************************************************************
967 * ReadVTSTimeMap : Fills the time map table
968 *****************************************************************************/
969 static vts_tmap_ti_t ReadVTSTimeMap( ifo_t* p_ifo )
973 // off_t i_start = p_ifo->i_pos;
975 //fprintf( stderr, "TMAP\n" );
979 GETL( &tmap.i_ebyte );
980 tmap.pi_sbyte = malloc( tmap.i_nb *sizeof(u32) );
981 if( tmap.pi_sbyte == NULL )
983 intf_ErrMsg( "Out of memory" );
987 for( i=0 ; i<tmap.i_nb ; i++ )
989 GETL( &tmap.pi_sbyte[i] );
991 tmap.p_tmap = malloc( tmap.i_nb *sizeof(tmap_t) );
992 if( tmap.p_tmap == NULL )
994 intf_ErrMsg( "Out of memory" );
998 for( i=0 ; i<tmap.i_nb ; i++ )
1000 GETC( &tmap.p_tmap[i].i_time_unit );
1002 GETS( &tmap.p_tmap[i].i_entry_nb );
1003 tmap.p_tmap[i].pi_sector =
1004 malloc( tmap.p_tmap[i].i_entry_nb *sizeof(u32) );
1005 if( tmap.p_tmap[i].pi_sector == NULL )
1007 intf_ErrMsg( "Out of memory" );
1011 for( j=0 ; j<tmap.p_tmap[i].i_entry_nb ; j++ )
1013 GETL( &tmap.p_tmap[i].pi_sector[j] );
1021 /*****************************************************************************
1022 * ReadVTS : Parse vts*.ifo files to fill the Video Title Set structure.
1023 *****************************************************************************/
1024 static vts_t ReadVTS( ifo_t* p_ifo )
1028 vts.i_pos = p_ifo->i_pos;
1030 vts.mat = ReadVTSInfMat( p_ifo );
1031 if( vts.mat.i_ptt_srpt_ssector )
1033 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
1034 vts.mat.i_ptt_srpt_ssector *DVD_LB_SIZE,
1036 vts.ptt_srpt = ReadVTSTitlePointer( p_ifo );
1038 if( vts.mat.i_m_pgci_ut_ssector )
1040 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
1041 vts.mat.i_m_pgci_ut_ssector *DVD_LB_SIZE,
1043 vts.pgci_ut = ReadUnitTable( p_ifo );
1045 if( vts.mat.i_pgcit_ssector )
1047 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
1048 vts.mat.i_pgcit_ssector *DVD_LB_SIZE,
1050 vts.pgci_ti = ReadUnit( p_ifo );
1052 if( vts.mat.i_tmap_ti_ssector )
1054 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
1055 vts.mat.i_tmap_ti_ssector *DVD_LB_SIZE,
1057 vts.tmap_ti = ReadVTSTimeMap( p_ifo );
1059 if( vts.mat.i_m_c_adt_ssector )
1061 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
1062 vts.mat.i_m_c_adt_ssector *DVD_LB_SIZE,
1064 vts.m_c_adt = ReadCellInf( p_ifo );
1066 if( vts.mat.i_m_vobu_admap_ssector )
1068 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
1069 vts.mat.i_m_vobu_admap_ssector *DVD_LB_SIZE,
1071 vts.m_vobu_admap = ReadMap( p_ifo );
1073 if( vts.mat.i_c_adt_ssector )
1075 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
1076 vts.mat.i_c_adt_ssector *DVD_LB_SIZE,
1078 vts.c_adt = ReadCellInf( p_ifo );
1080 if( vts.mat.i_vobu_admap_ssector )
1082 p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
1083 vts.mat.i_vobu_admap_ssector *DVD_LB_SIZE,
1085 vts.vobu_admap = ReadMap( p_ifo );
1092 * DVD Information Management
1095 /*****************************************************************************
1096 * IfoRead : Function that fills structure and calls specified functions
1098 *****************************************************************************/
1099 void IfoRead( ifo_t* p_ifo )
1104 /* Video Manager Initialization */
1105 intf_WarnMsg( 2, "ifo: initializing VMG" );
1106 p_ifo->vmg = ReadVMG( p_ifo );
1108 /* Video Title Sets initialization */
1109 p_ifo->p_vts = malloc( p_ifo->vmg.mat.i_tts_nb *sizeof(vts_t) );
1110 if( p_ifo->p_vts == NULL )
1112 intf_ErrMsg( "Out of memory" );
1116 for( i=0 ; i<p_ifo->vmg.mat.i_tts_nb ; i++ )
1119 intf_WarnMsg( 2, "ifo: initializing VTS %d", i+1 );
1121 i_off = (off_t)(p_ifo->vmg.ptt_srpt.p_tts[i].i_ssector) *DVD_LB_SIZE;
1122 p_ifo->i_pos = lseek( p_ifo->i_fd, i_off, SEEK_SET );
1123 fprintf( stderr, "%lld\n" , p_ifo->i_pos );
1125 /* FIXME : use udf filesystem to avoid this */
1126 IfoFindVTS( p_ifo );
1127 p_ifo->p_vts[i] = ReadVTS( p_ifo );
1133 * IFO virtual machine : a set of commands that give the
1134 * interactive behaviour of the dvd
1138 #define OP_VAL_16(i) (ntoh16( com.data.pi_16[i]))
1139 #define OP_VAL_8(i) ((com.data.pi_8[i]))
1141 static char ifo_reg[][80]=
1143 "Menu_Language_Code",
1145 "SubPicture_Stream_#",
1151 "Highlighted_Button_#",
1154 "Karaoke_audio_mixing_mode",
1155 "Parental_mgmt_country_code",
1159 "Audio_language_code_setting",
1160 "Audio_language_extension_code",
1161 "SPU_language_code_setting",
1162 "SPU_language_extension_code",
1163 "?Player_Regional_Code",
1169 static char * IfoMath( char val )
1171 static char math_op[][10] =
1191 return (char *) math_op[val & 0x0f];
1195 char ifo_cmp[][10] =
1207 char ifo_parental[][10] =
1219 char ifo_menu_id[][80] =
1231 char * IfoMenuName( char index )
1233 return ifo_menu_id[index&0x07];
1236 static void IfoRegister( u16 i_data, u8 i_direct)
1240 if( 0/*isalpha( i_data >> 8 & 0xff )*/ )
1242 printf("'%c%c'", i_data>>8&0xff, i_data&0xff);
1246 printf("0x%02x", i_data);
1261 printf("s[%s]", ifo_reg[i_data]);
1274 printf("r[0x%02x]", i_data);
1280 static void IfoAdvanced( u8 *pi_code )
1282 u8 i_cmd = pi_code[0];
1288 printf( " Highlight button %d; ", pi_code[1]>>2 );
1293 printf( " Illegal " );
1298 printf( "ReSuME %d", pi_code[7] );
1300 else if( ( i_cmd & 0x06) == 0x02 )
1302 printf ("Link to %s cell ", ( i_cmd & 0x01 ) ? "prev" : "next");
1306 printf( "advanced (0x%02x) ", i_cmd );
1311 static void IfoJmp( ifo_command_t com )
1316 switch( com.i_sub_cmd )
1322 printf( "VTS 0x%02x", OP_VAL_8(3) );
1325 printf( "This VTS Title 0x%02x", OP_VAL_8(3) );
1328 printf( "This VTS Title 0x%02x Part 0x%04x",
1330 OP_VAL_8(0)<<8|OP_VAL_8(1));
1334 printf ("in SystemSpace ");
1335 switch (OP_VAL_8(3)>>4) {
1337 printf ("to play first PGC");
1340 printf ("to menu \"%s\"", decode_menuname (OP_VAL_8(3)));
1344 printf ("to VTS 0x%02x and TTN 0x%02x", OP_VAL_8(1), OP_VAL_8(2));
1347 printf ("to VMGM PGC number 0x%02x", OP_VAL_8(0)<<8 | OP_VAL_8(1));
1350 printf ("vts 0x%02x lu 0x%02x menu \"%s\"", OP_VAL_8(2), OP_VAL_8(1), decode_menuname (OP_VAL_8(3)));
1353 switch( OP_VAL_8(3)>>6 )
1356 printf( "to play first PGC" );
1359 printf( "to VMG title menu (?)" );
1362 printf( "vts 0x%02x lu 0x%02x menu \"%s\"",
1365 IfoMenuName( OP_VAL_8(3)&0xF ) );
1368 printf( "vmg pgc 0x%04x (?)", ( OP_VAL_8(0)<<8) | OP_VAL_8(1) );
1375 switch(OP_VAL_8(3)>>4) {
1377 printf ("system first pgc");
1380 printf ("system title menu");
1383 printf ("system menu \"%s\"", decode_menuname (OP_VAL_8(3)));
1386 printf ("system vmg pgc %02x ????", OP_VAL_8(0)<<8|OP_VAL_8(1));
1389 printf ("system lu 0x%02x menu \"%s\"", OP_VAL_8(2), decode_menuname (OP_VAL_8(3)));
1392 printf ("system vmg pgc 0x%02x", OP_VAL_8(0)<<8|OP_VAL_8(1));
1396 // OP_VAL_8(2) is number of cell
1397 // it is processed BEFORE switch
1398 // under some conditions, it is ignored
1399 // I don't understand exactly what it means
1400 printf( " ( spec cell 0x%02X ) ", OP_VAL_8(2) );
1402 switch( OP_VAL_8(3)>>6 )
1405 printf( "to FP PGC" );
1408 printf( "to VMG root menu (?)" );
1411 printf( "to VTS menu \"%s\" (?)",
1412 IfoMenuName(OP_VAL_8(3)&0xF) );
1415 printf( "vmg pgc 0x%02x (?)", (OP_VAL_8(0)<<8)|OP_VAL_8(1) );
1423 static void IfoLnk( ifo_command_t com )
1425 u16 i_button=OP_VAL_8(4)>>2;
1429 switch( com.i_sub_cmd )
1432 IfoAdvanced( &OP_VAL_8(4) );
1436 printf( "PGC 0x%02x", OP_VAL_16(2) );
1440 printf( "PTT 0x%02x", OP_VAL_16(2) );
1444 printf( "Program 0x%02x this PGC", OP_VAL_8(5) );
1448 printf( "Cell 0x%02x this PGC", OP_VAL_8(5) );
1456 printf( ", Highlight 0x%02x", OP_VAL_8(4)>>2 );
1461 void IfoSetSystem( ifo_command_t com )
1468 for( i=1; i<=3; i++ )
1470 if( OP_VAL_8(i)&0x80 )
1474 printf ("s[%s] = 0x%02x;", ifo_reg[i], OP_VAL_8(i)&0xf);
1478 printf ("s[%s] = r[0x%02x];", ifo_reg[i], OP_VAL_8(i)&0xf);
1484 if(OP_VAL_8(1]&0x80)
1485 printf ("s[%s] = 0x%02x;", reg_name[1], OP_VAL_8(1]&0xf);
1486 if(OP_VAL_8(2)&0x80)
1487 //DENT: lwhat about 0x7f here ???
1488 printf ("s[%s] = 0x%02x;", reg_name[2], OP_VAL_8(2)&0x7f);
1489 if(OP_VAL_8(3)&0x80)
1490 printf ("s[%s] = 0x%02x;", reg_name[3], OP_VAL_8(3)&0xf);
1492 if(OP_VAL_8(1)&0x80)
1493 printf ("s[%s] = r[0x%02x];", reg_name[1], OP_VAL_8(1)&0xf);
1494 if(OP_VAL_8(2)&0x80)
1495 printf ("s[%s] = r[0x%02x];", reg_name[2], OP_VAL_8(2)&0xf);
1496 if(OP_VAL_8(3)&0x80)
1497 printf ("s[%s] = r[0x%02x];", reg_name[3], OP_VAL_8(3)&0xf);
1505 printf( "s[%s] = 0x%02x", ifo_reg[9], OP_VAL_16(0) );
1509 printf( "s[%s] = r[0x%02x]", ifo_reg[9], OP_VAL_8(1)&0x0f );
1512 printf( "s[%s] = (s[%s]&0x7FFF)|0x%02x",
1513 ifo_reg[10], ifo_reg[10], OP_VAL_16(1)&0x8000);
1518 printf( "r[0x%02x] = 0x%02x", OP_VAL_8(3)&0x0f, OP_VAL_16(0) );
1522 printf ("r[r[0x%02x]] = r[0x%02x]",
1523 OP_VAL_8(3)&0x0f, OP_VAL_8(1)&0x0f);
1527 //actually only bits 00011100 00011100 are set
1530 printf ("s[%s] = 0x%02x", ifo_reg[11], OP_VAL_16(1));
1534 printf ("s[%s] = r[0x%02x]", ifo_reg[11], OP_VAL_8(3)&0x0f );
1539 //s[%s]=(r[%s]&0x3FF) | (0x%02x << 0xA);
1540 //but it is way too ugly
1543 printf( "s[%s] = 0x%02x", ifo_reg[8], OP_VAL_8(2)>>2 );
1547 printf( "s[%s] = r[0x%02x]", ifo_reg[8], OP_VAL_8(3)&0x0f );
1555 static void IfoSet( ifo_command_t com )
1557 IfoRegister( OP_VAL_16(0), 0 );
1558 printf( " %s ", IfoMath( com.i_cmd ) );
1559 IfoRegister( OP_VAL_16(1), com.i_direct );
1562 /*****************************************************************************
1563 * CommandRead : translates the command strings in ifo into command
1565 *****************************************************************************/
1566 void CommandRead( ifo_command_t com )
1568 u8* pi_code = (u8*)(&com);
1570 switch( com.i_type )
1583 printf ("if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
1584 ifo_cmp[com.i_cmp]);
1585 IfoRegister (OP_VAL_16(1), com.i_dir_cmp);
1590 switch( com.i_sub_cmd )
1593 printf( "goto Line 0x%02x", OP_VAL_16(2) );
1597 printf( "stop VM" );
1601 printf( "Set Parental Level To %s and goto Line 0x%02x",
1602 ifo_parental[OP_VAL_8(4)&0x7],
1607 printf( "Illegal" );
1626 printf( "if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f,
1627 ifo_cmp[com.i_cmp] );
1628 IfoRegister( OP_VAL_8(5), 0 );
1639 printf( "if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
1640 ifo_cmp[com.i_cmp] );
1641 IfoRegister( OP_VAL_16(1), com.i_dir_cmp );
1655 IfoSetSystem( com );
1657 else if( com.i_cmp && !com.i_sub_cmd )
1659 printf ("if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f, ifo_cmp[com.i_cmp]);
1660 IfoRegister( OP_VAL_8(5), 0 );
1662 IfoSetSystem( com );
1664 else if( !com.i_cmp && com.i_sub_cmd )
1667 IfoSetSystem( com );
1683 else if( com.i_cmp && !com.i_sub_cmd )
1685 printf ("if (r[0x%02x] %s ", OP_VAL_8(0)&0x0f, ifo_cmp[com.i_cmp]);
1686 IfoRegister( OP_VAL_16(2), com.i_dir_cmp );
1690 else if( !com.i_cmp && com.i_sub_cmd )
1704 * math command on r[opcode[1]] and
1705 * direct?be2me_16(OP_VAL_8(0)):reg[OP_VAL_8(1)] is executed
1706 * ( unless command is swap; then r[opcode[1]] and r[OP_VAL_8(1)]
1708 * boolean operation cmp on r[opcode[1]] and
1709 * dir_cmp?be2me_16(OP_VAL_8(1)[1]):reg[OP_VAL_8(3)] is executed
1710 * on true result, buttons(c[6], c[7]) is called
1711 * problem is 'what is buttons()'
1714 printf( "r[0x%X] ", pi_code[1] );
1715 printf( " %s ", IfoMath( com.i_cmd ) );
1716 if( com.i_cmd == 2 )
1718 printf( "r[0x%X] ", OP_VAL_8(1) );
1722 IfoRegister( OP_VAL_16(0), com.i_direct );
1726 printf( "if ( r[%d] %s ", pi_code[1], ifo_cmp[com.i_cmp] );
1727 IfoRegister( OP_VAL_8(1), com.i_dir_cmp );
1728 printf( " ) then {" );
1729 IfoAdvanced( &OP_VAL_8(4) );
1734 * opposite to case 4: boolean, math and buttons.
1740 if( !com.i_direct && com.i_dir_cmp )
1742 printf( "0x%X", OP_VAL_16(1) );
1746 IfoRegister( OP_VAL_8(3), 0 );
1747 if( OP_VAL_8(3)&0x80 )
1749 printf( "s[%s]", ifo_reg[OP_VAL_8(3)&0x1F] );
1753 printf( "r[0x%X]", OP_VAL_8(3)&0x1F);
1754 // 0x1F is either not a mistake,
1755 // or Microsoft programmer's mistake!!!
1759 printf( " %s r[0x%X] ", ifo_cmp[com.i_cmp],
1760 com.i_direct ? OP_VAL_8(2) : OP_VAL_8(1) );
1761 printf( " ) then {" );
1762 printf( "r[0x%X] ", pi_code[1] & 0xF );
1763 printf( " %s ", IfoMath( com.i_cmd ) );
1765 if( com.i_cmd == 0x02 ) // swap
1767 printf("r[0x%X] ", OP_VAL_8(0)&0x1F);
1773 printf( "0x%X", OP_VAL_16(0) );
1777 if( OP_VAL_8(0) & 0x80 )
1779 printf("s[%s]", ifo_reg[OP_VAL_8(0) & 0x1F] );
1783 printf("r[0x%X]", OP_VAL_8(0) & 0x1F );
1789 IfoAdvanced( &OP_VAL_8(4) );
1795 printf( "Unknown Command\n" );
1802 /*****************************************************************************
1803 * CommandPrint : print in clear text (I hope so !) what a command does
1804 *****************************************************************************/
1805 void CommandPrint( ifo_t ifo )