]> git.sesse.net Git - vlc/blob - plugins/dvd/dvd_ifo.c
Removed flooding debug info :)
[vlc] / plugins / dvd / dvd_ifo.c
1 /*****************************************************************************
2  * dvd_ifo.c: Functions for ifo parsing
3  *****************************************************************************
4  * Copyright (C) 1999-2001 VideoLAN
5  * $Id: dvd_ifo.c,v 1.12 2001/02/20 02:56:50 stef Exp $
6  *
7  * Author: Stéphane Borel <stef@via.ecp.fr>
8  *
9  * based on:
10  *  - libifo by Thomas Mirlacher <dent@cosy.sbg.ac.at>
11  *  - IFO structure documentation by Thomas Mirlacher, Björn Englund,
12  *  Håkan Hjort
13  *
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.
18  *
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.
23  *
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  *****************************************************************************/
28
29 /*****************************************************************************
30  * Preamble
31  *****************************************************************************/
32 #include <stdio.h>
33 #include <unistd.h>
34 #include <string.h>
35 #include <fcntl.h>
36
37 #include "common.h"
38
39 #include "intf_msg.h"
40 #include "dvd_ifo.h"
41 #include "dvd_udf.h"
42 #include "input_dvd.h"
43
44 /*
45  * Local prototypes
46  */
47 static vmg_t ReadVMG    ( ifo_t* );
48 void         CommandRead( ifo_command_t );
49
50 /*
51  * IFO Management.
52  */
53
54 /*****************************************************************************
55  * IfoInit : Creates an ifo structure and prepares for parsing directly
56  * on DVD device.
57  *****************************************************************************/
58 ifo_t IfoInit( int i_fd )
59 {
60     ifo_t       ifo;
61     u32         i_lba;
62     
63     /* If we are here the dvd device has already been opened */
64     ifo.i_fd = i_fd;
65
66     i_lba = UDFFindFile( i_fd, "/VIDEO_TS/VIDEO_TS.IFO");
67
68     ifo.i_off = (off_t)(i_lba) * DVD_LB_SIZE;
69     ifo.i_pos = lseek( ifo.i_fd, ifo.i_off, SEEK_SET );
70
71     /* Video Manager Initialization */
72     intf_WarnMsg( 2, "ifo: initializing VMG" );
73     ifo.vmg = ReadVMG( &ifo );
74
75     return ifo;
76 }
77
78 /*****************************************************************************
79  * IfoEnd : Frees all the memory allocated to ifo structures
80  *****************************************************************************/
81 void IfoEnd( ifo_t* p_ifo )
82 {
83 #if 0
84     int     i,j;
85
86     /* Free structures from video title sets */
87     for( j=0 ; j<p_ifo->vmg.mat.i_tts_nb ; j++ )
88     {
89         free( p_ifo->p_vts[j].vobu_admap.pi_vobu_ssector );
90         free( p_ifo->p_vts[j].c_adt.p_cell_inf );
91         free( p_ifo->p_vts[j].m_vobu_admap.pi_vobu_ssector );
92         free( p_ifo->p_vts[j].m_c_adt.p_cell_inf );
93         for( i=0 ; i<p_ifo->p_vts[j].tmap_ti.i_nb ; i++ )
94         {
95             free( p_ifo->p_vts[j].tmap_ti.p_tmap[i].pi_sector );
96         }
97         free( p_ifo->p_vts[j].tmap_ti.pi_sbyte );
98         free( p_ifo->p_vts[j].tmap_ti.p_tmap );
99         free( p_ifo->p_vts[j].pgci_ti.p_srp );
100         for( i=0 ; i<p_ifo->p_vts[j].pgci_ut.i_lu_nb ; i++ )
101         {
102             free( p_ifo->p_vts[j].pgci_ut.p_pgci_inf[i].p_srp );
103         }
104         free( p_ifo->p_vts[j].pgci_ut.p_pgci_inf );
105         free( p_ifo->p_vts[j].pgci_ut.p_lu );
106     }
107
108     free( p_ifo->p_vts );
109
110     /* Free structures from video manager */
111     free( p_ifo->vmg.vobu_admap.pi_vobu_ssector );
112     free( p_ifo->vmg.c_adt.p_cell_inf );
113     for( i=0 ; i<p_ifo->vmg.pgci_ut.i_lu_nb ; i++ )
114     {
115         free( p_ifo->vmg.pgci_ut.p_pgci_inf[i].p_srp );
116     }
117     free( p_ifo->vmg.pgci_ut.p_pgci_inf );
118     free( p_ifo->vmg.pgci_ut.p_lu );
119     for( i=1 ; i<=8 ; i++ )
120     {
121         free( p_ifo->vmg.ptl_mait.p_ptl_mask->ppi_ptl_mask[i] );
122     }
123     free( p_ifo->vmg.ptl_mait.p_ptl_desc );
124     free( p_ifo->vmg.ptl_mait.p_ptl_mask );
125     free( p_ifo->vmg.vts_atrt.pi_vts_atrt_sbyte );
126     free( p_ifo->vmg.vts_atrt.p_vts_atrt );
127     free( p_ifo->vmg.pgc.p_cell_pos_inf );
128     free( p_ifo->vmg.pgc.p_cell_play_inf );
129     free( p_ifo->vmg.pgc.prg_map.pi_entry_cell );
130     free( p_ifo->vmg.pgc.com_tab.p_cell_com );
131     free( p_ifo->vmg.pgc.com_tab.p_post_com );
132     free( p_ifo->vmg.pgc.com_tab.p_pre_com );
133 #endif
134     return;
135 }
136
137 /*
138  * Macros to process ifo files
139  */
140  
141 #define GET( p_field , i_len )                                              \
142     {                                                                       \
143         read( p_ifo->i_fd , (p_field) , (i_len) );                          \
144 /*fprintf(stderr, "Pos : %lld Val : %llx\n",                                  \
145                                 (long long)(p_ifo->i_pos - i_start),        \
146                                 (long long)*(p_field) );    */                \
147         p_ifo->i_pos += i_len;                                              \
148     }
149
150 #define GETC( p_field )                                                     \
151     {                                                                       \
152         read( p_ifo->i_fd , (p_field) , 1 );                                \
153 /*fprintf(stderr, "Pos : %lld Value : %d\n",                                  \
154                                 (long long)(p_ifo->i_pos - i_start),        \
155                                           *(p_field) );*/                     \
156         p_ifo->i_pos += 1;                                                  \
157     }
158
159 #define GETS( p_field )                                                     \
160     {                                                                       \
161         read( p_ifo->i_fd , (p_field) , 2 );                                \
162         *(p_field) = ntohs( *(p_field) );                                   \
163 /*fprintf(stderr, "Pos : %lld Value : %d\n",                                  \
164                                 (long long)(p_ifo->i_pos - i_start),        \
165                                           *(p_field) );*/                     \
166         p_ifo->i_pos += 2;                                                  \
167     }
168
169 #define GETL( p_field )                                                     \
170     {                                                                       \
171         read( p_ifo->i_fd , (p_field) , 4 );                                \
172         *(p_field) = ntohl( *(p_field) );                                   \
173 /*fprintf(stderr, "Pos : %lld Value : %d\n",                                  \
174                                 (long long)(p_ifo->i_pos - i_start),        \
175                                           *(p_field) );*/                     \
176         p_ifo->i_pos += 4;                                                  \
177     }
178
179 #define GETLL( p_field )                                                    \
180     {                                                                       \
181         read( p_ifo->i_fd , (p_field) , 8 );                                \
182         *(p_field) = ntoh64( *(p_field) );                                  \
183 /*fprintf(stderr, "Pos : %lld Value : %lld\n",                                \
184                                 (long long)(p_ifo->i_pos - i_start),        \
185                                             *(p_field) );*/                   \
186         p_ifo->i_pos += 8;                                                  \
187     }
188
189 #define FLUSH( i_len )                                                      \
190     {                                                                       \
191 /*fprintf(stderr, "Pos : %lld\n", (long long)(p_ifo->i_pos - i_start));*/       \
192         p_ifo->i_pos = lseek( p_ifo->i_fd ,                               \
193                               p_ifo->i_pos + (i_len), SEEK_SET );           \
194     }
195
196 /*
197  * Function common to Video Manager and Video Title set Processing
198  */
199
200 /*****************************************************************************
201  * ReadPGC : Fills the Program Chain structure.
202  *****************************************************************************/
203 #define GETCOMMAND( p_com )                                                 \
204     {                                                                       \
205         read( p_ifo->i_fd , (p_com) , 8 );                                  \
206 /*fprintf(stderr, "Pos : %lld Type : %d direct : %d cmd : %d dircmp : %d cmp : %d subcmd : %d v0 : %d v2 : %d v4 : %d\n",                                  \
207                                 (long long)(p_ifo->i_pos - i_start),        \
208                                 (int)((p_com)->i_type),                     \
209                                 (int)((p_com)->i_direct),                   \
210                                 (int)((p_com)->i_cmd),                      \
211                                 (int)((p_com)->i_dir_cmp),                  \
212                                 (int)((p_com)->i_cmp),                      \
213                                 (int)((p_com)->i_sub_cmd),                  \
214                                 (int)((p_com)->data.pi_16[0]),              \
215                                 (int)((p_com)->data.pi_16[1]),              \
216                                 (int)((p_com)->data.pi_16[2]));*/             \
217 /*        CommandRead( *(p_com) );*/                                            \
218         p_ifo->i_pos += 8;                                                  \
219     }
220
221 static pgc_t ReadPGC( ifo_t* p_ifo )
222 {
223     pgc_t   pgc;
224     int     i;
225     off_t   i_start = p_ifo->i_pos;
226
227 //fprintf( stderr, "PGC\n" );
228
229     FLUSH(2);
230     GETC( &pgc.i_prg_nb );
231     GETC( &pgc.i_cell_nb );
232 //fprintf( stderr, "PGC: Prg: %d Cell: %d\n", pgc.i_prg_nb, pgc.i_cell_nb );
233     GETL( &pgc.i_play_time );
234     GETL( &pgc.i_prohibited_user_op );
235     for( i=0 ; i<8 ; i++ )
236     {
237         GETS( &pgc.pi_audio_status[i] );
238     }
239     for( i=0 ; i<32 ; i++ )
240     {
241         GETL( &pgc.pi_subpic_status[i] );
242     }
243     GETS( &pgc.i_next_pgc_nb );
244     GETS( &pgc.i_prev_pgc_nb );
245     GETS( &pgc.i_goup_pgc_nb );
246 //fprintf( stderr, "PGC: Prev: %d Next: %d Up: %d\n",pgc.i_prev_pgc_nb ,pgc.i_next_pgc_nb, pgc.i_goup_pgc_nb );
247     GETC( &pgc.i_still_time );
248     GETC( &pgc.i_play_mode );
249     for( i=0 ; i<16 ; i++ )
250     {
251         GETL( &pgc.pi_yuv_color[i] );
252         /* FIXME : We have to erase the extra bit */
253     }
254     GETS( &pgc.i_com_tab_sbyte );
255     GETS( &pgc.i_prg_map_sbyte );
256     GETS( &pgc.i_cell_play_inf_sbyte );
257     GETS( &pgc.i_cell_pos_inf_sbyte );
258
259     /* Parsing of pgc_com_tab_t */
260     if( pgc.i_com_tab_sbyte )
261     {
262         p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
263                             + pgc.i_com_tab_sbyte, SEEK_SET );
264         GETS( &pgc.com_tab.i_pre_com_nb );
265         GETS( &pgc.com_tab.i_post_com_nb );
266         GETS( &pgc.com_tab.i_cell_com_nb );
267         FLUSH( 2 );
268         if( pgc.com_tab.i_pre_com_nb )
269         {
270             pgc.com_tab.p_pre_com =
271                       malloc(pgc.com_tab.i_pre_com_nb *sizeof(ifo_command_t));
272             if( pgc.com_tab.p_pre_com == NULL )
273             {
274                 intf_ErrMsg( "Out of memory" );
275                 p_ifo->b_error = 1;
276                 return pgc;
277             }
278             for( i=0 ; i<pgc.com_tab.i_pre_com_nb ; i++ )
279             {
280                 GETCOMMAND( &pgc.com_tab.p_pre_com[i] );
281             }
282         }
283         if( pgc.com_tab.i_post_com_nb )
284         {
285             pgc.com_tab.p_post_com =
286                       malloc(pgc.com_tab.i_post_com_nb *sizeof(ifo_command_t));
287             if( pgc.com_tab.p_post_com == NULL )
288             {
289                 intf_ErrMsg( "Out of memory" );
290                 p_ifo->b_error = 1;
291                 return pgc;
292             }
293             for( i=0 ; i<pgc.com_tab.i_post_com_nb ; i++ )
294             {
295                 GETCOMMAND( &pgc.com_tab.p_post_com[i] );
296             }
297         }
298         if( pgc.com_tab.i_cell_com_nb )
299         {
300             pgc.com_tab.p_cell_com =
301                       malloc(pgc.com_tab.i_cell_com_nb *sizeof(ifo_command_t));
302             if( pgc.com_tab.p_cell_com == NULL )
303             {
304                 intf_ErrMsg( "Out of memory" );
305                 p_ifo->b_error = 1;
306                 return pgc;
307             }
308             for( i=0 ; i<pgc.com_tab.i_cell_com_nb ; i++ )
309             {
310                 GETCOMMAND( &pgc.com_tab.p_cell_com[i] );
311             }
312         }
313     }
314     /* Parsing of pgc_prg_map_t */
315     if( pgc.i_prg_map_sbyte )
316     {
317         p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
318                             + pgc.i_prg_map_sbyte, SEEK_SET );
319         pgc.prg_map.pi_entry_cell = malloc( pgc.i_prg_nb *sizeof(u8) );
320         if( pgc.prg_map.pi_entry_cell == NULL )
321         {
322             intf_ErrMsg( "Out of memory" );
323             p_ifo->b_error = 1;
324             return pgc;
325         }
326         GET( pgc.prg_map.pi_entry_cell, pgc.i_prg_nb );
327         /* FIXME : check endianness here */
328     }
329     /* Parsing of cell_play_inf_t */
330     if( pgc.i_cell_play_inf_sbyte )
331     {
332         p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
333                             + pgc.i_cell_play_inf_sbyte, SEEK_SET );
334         pgc.p_cell_play_inf = malloc( pgc.i_cell_nb *sizeof(cell_play_inf_t) );
335         if( pgc.p_cell_play_inf == NULL )
336         {
337             intf_ErrMsg( "Out of memory" );
338             p_ifo->b_error = 1;
339             return pgc;
340         }
341         for( i=0 ; i<pgc.i_cell_nb ; i++ )
342         {
343             GETS( &pgc.p_cell_play_inf[i].i_cat );
344             GETC( &pgc.p_cell_play_inf[i].i_still_time );
345             GETC( &pgc.p_cell_play_inf[i].i_com_nb );
346             GETL( &pgc.p_cell_play_inf[i].i_play_time );
347             GETL( &pgc.p_cell_play_inf[i].i_entry_sector );
348             GETL( &pgc.p_cell_play_inf[i].i_first_ilvu_vobu_esector );
349             GETL( &pgc.p_cell_play_inf[i].i_lvobu_ssector );
350             GETL( &pgc.p_cell_play_inf[i].i_lsector );
351         }
352     }
353     /* Parsing of cell_pos_inf_map */
354     if( pgc.i_cell_pos_inf_sbyte )
355     {
356         p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
357                             + pgc.i_cell_pos_inf_sbyte, SEEK_SET );
358         pgc.p_cell_pos_inf = malloc( pgc.i_cell_nb *sizeof(cell_pos_inf_t) );
359         if( pgc.p_cell_pos_inf == NULL )
360         {
361             intf_ErrMsg( "Out of memory" );
362             p_ifo->b_error = 1;
363             return pgc;
364         }
365         for( i=0 ; i<pgc.i_cell_nb ; i++ )
366         {
367             GETS( &pgc.p_cell_pos_inf[i].i_vob_id );
368             FLUSH( 1 );
369             GETC( &pgc.p_cell_pos_inf[i].i_cell_id );
370         }
371     } 
372
373     return pgc;
374 }
375
376 /*****************************************************************************
377  * ReadUnit : Fills Menu Language Unit Table/ PGC Info Table
378  *****************************************************************************/
379 static pgci_inf_t ReadUnit( ifo_t* p_ifo )
380 {
381     pgci_inf_t      inf;
382     int             i;
383     off_t           i_start = p_ifo->i_pos;
384
385 //fprintf( stderr, "Unit\n" );
386
387     GETS( &inf.i_srp_nb );
388     FLUSH( 2 );
389     GETL( &inf.i_lu_ebyte );
390     inf.p_srp = malloc( inf.i_srp_nb *sizeof(pgci_srp_t) );
391     if( inf.p_srp == NULL )
392     {
393         intf_ErrMsg( "Out of memory" );
394         p_ifo->b_error = 1;
395         return inf;
396     }
397     for( i=0 ; i<inf.i_srp_nb ; i++ )
398     {
399         GETC( &inf.p_srp[i].i_pgc_cat_mask );
400         GETC( &inf.p_srp[i].i_pgc_cat );
401         GETS( &inf.p_srp[i].i_par_mask );
402         GETL( &inf.p_srp[i].i_pgci_sbyte );
403     }
404     for( i=0 ; i<inf.i_srp_nb ; i++ )
405     {
406         p_ifo->i_pos = lseek( p_ifo->i_fd,
407                          i_start + inf.p_srp[i].i_pgci_sbyte,
408                          SEEK_SET );
409 //fprintf( stderr, "Unit: PGC %d\n", i );
410         inf.p_srp[i].pgc = ReadPGC( p_ifo );
411     }
412
413     return inf;
414 }
415
416 /*****************************************************************************
417  * ReadUnitTable : Fills the PGCI Unit structure.
418  *****************************************************************************/
419 static pgci_ut_t ReadUnitTable( ifo_t* p_ifo )
420 {
421     pgci_ut_t       pgci;
422     int             i;
423     off_t           i_start = p_ifo->i_pos;
424
425 //fprintf( stderr, "Unit Table\n" );
426
427     GETS( &pgci.i_lu_nb );
428     FLUSH( 2 );
429     GETL( &pgci.i_ebyte );
430     pgci.p_lu = malloc( pgci.i_lu_nb *sizeof(pgci_lu_t) );
431     if( pgci.p_lu == NULL )
432     {
433         intf_ErrMsg( "Out of memory" );
434         p_ifo->b_error = 1;
435         return pgci;
436     }
437     for( i=0 ; i<pgci.i_lu_nb ; i++ )
438     {
439         GET( pgci.p_lu[i].ps_lang_code, 2 );
440         FLUSH( 1 );
441         GETC( &pgci.p_lu[i].i_existence_mask );
442         GETL( &pgci.p_lu[i].i_lu_sbyte );
443     }
444     pgci.p_pgci_inf = malloc( pgci.i_lu_nb *sizeof(pgci_inf_t) );
445     if( pgci.p_pgci_inf == NULL )
446     {
447         intf_ErrMsg( "Out of memory" );
448         p_ifo->b_error = 1;
449         return pgci;
450     }
451     for( i=0 ; i<pgci.i_lu_nb ; i++ )
452     {
453         p_ifo->i_pos = lseek( p_ifo->i_fd, i_start +
454                                 pgci.p_lu[i].i_lu_sbyte,
455                                 SEEK_SET );
456         pgci.p_pgci_inf[i] = ReadUnit( p_ifo );
457     }
458
459     return pgci;
460 }
461
462 /*****************************************************************************
463  * ReadCellInf : Fills the Cell Information structure.
464  *****************************************************************************/
465 static c_adt_t ReadCellInf( ifo_t* p_ifo )
466 {
467     c_adt_t         c_adt;
468     off_t           i_start = p_ifo->i_pos;
469     int             i;
470
471 //fprintf( stderr, "CELL ADD\n" );
472
473     GETS( &c_adt.i_vob_nb );
474     FLUSH( 2 );
475     GETL( &c_adt.i_ebyte );
476     c_adt.i_cell_nb =
477         ( i_start + c_adt.i_ebyte + 1 - p_ifo->i_pos ) / sizeof(cell_inf_t);
478     c_adt.p_cell_inf = malloc( c_adt.i_cell_nb *sizeof(cell_inf_t) );
479     if( c_adt.p_cell_inf == NULL )
480     {
481         intf_ErrMsg( "Out of memory" );
482         p_ifo->b_error = 1;
483         return c_adt;
484     }
485     for( i = 0 ; i < c_adt.i_cell_nb ; i++ )
486     {
487         GETS( &c_adt.p_cell_inf[i].i_vob_id );
488         GETC( &c_adt.p_cell_inf[i].i_cell_id );
489         FLUSH( 1 );
490         GETL( &c_adt.p_cell_inf[i].i_ssector );
491         GETL( &c_adt.p_cell_inf[i].i_esector );
492     }
493     
494     return c_adt;
495 }
496
497 /*****************************************************************************
498  * ReadMap : Fills the VOBU Map structure.
499  *****************************************************************************/
500 static vobu_admap_t ReadMap( ifo_t* p_ifo )
501 {
502     vobu_admap_t        map;
503     int                 i, i_max;
504     off_t               i_start = p_ifo->i_pos;
505     
506 //fprintf( stderr, "VOBU ADMAP\n" );
507
508     GETL( &map.i_ebyte );
509     i_max = ( i_start + map.i_ebyte + 1 - p_ifo->i_pos ) / sizeof(u32);
510     map.pi_vobu_ssector = malloc( i_max *sizeof(u32) );
511     for( i=0 ; i<i_max ; i++ )
512     {
513         GETL( &map.pi_vobu_ssector[i] );
514     }
515
516     return map;
517 }
518  
519 /*
520  * Video Manager Information Processing.
521  * This is what is contained in video_ts.ifo.
522  */
523
524 /*****************************************************************************
525  * ReadVMGInfMat : Fills the Management Information structure.
526  *****************************************************************************/
527 static vmgi_mat_t ReadVMGInfMat( ifo_t* p_ifo )
528 {
529     vmgi_mat_t  mat;
530     int         i;
531 //    off_t     i_start = p_ifo->i_pos;
532
533 //fprintf( stderr, "VMGI\n" );
534
535     GET( mat.psz_id , 12 );
536     mat.psz_id[12] = '\0';
537     GETL( &mat.i_lsector );
538     FLUSH( 12 );
539     GETL( &mat.i_i_lsector );
540     FLUSH( 1 );
541     GETC( &mat.i_spec_ver );
542     GETL( &mat.i_cat );
543     GETS( &mat.i_vol_nb );
544     GETS( &mat.i_vol );
545     GETC( &mat.i_disc_side );
546     FLUSH( 19 );
547     GETS( &mat.i_tts_nb );
548     GET( mat.ps_provider_id, 32 );
549     GETLL( &mat.i_pos_code );
550     FLUSH( 24 );
551     GETL( &mat.i_i_mat_ebyte );
552     GETL( &mat.i_fp_pgc_sbyte );
553     FLUSH( 56 );
554     GETL( &mat.i_vobs_ssector );
555     GETL( &mat.i_ptt_srpt_ssector );
556     GETL( &mat.i_pgci_ut_ssector );
557     GETL( &mat.i_ptl_mait_ssector );
558     GETL( &mat.i_vts_atrt_ssector );
559     GETL( &mat.i_txtdt_mg_ssector );
560     GETL( &mat.i_c_adt_ssector );
561     GETL( &mat.i_vobu_admap_ssector );
562     FLUSH( 32 );
563     GETS( &mat.i_video_atrt );
564     FLUSH( 1 );
565     GETC( &mat.i_audio_nb );
566 //fprintf( stderr, "vmgi audio nb : %d\n", mat.i_audio_nb );
567     for( i=0 ; i < 8 ; i++ )
568     {
569         GETLL( &mat.pi_audio_atrt[i] );
570     }
571     FLUSH( 17 );
572     GETC( &mat.i_subpic_nb );
573 //fprintf( stderr, "vmgi subpic nb : %d\n", mat.i_subpic_nb );
574     for( i=0 ; i < mat.i_subpic_nb ; i++ )
575     {
576         GET( &mat.pi_subpic_atrt[i], 6 );
577         /* FIXME : take care of endianness */
578     }
579
580     return mat;
581 }
582
583 /*****************************************************************************
584  * ReadVMGTitlePointer : Fills the Part Of Title Search Pointer structure.
585  *****************************************************************************/
586 static vmg_ptt_srpt_t ReadVMGTitlePointer( ifo_t* p_ifo )
587 {
588     vmg_ptt_srpt_t  ptr;
589     int             i;
590 //    off_t           i_start = p_ifo->i_pos;
591
592 //fprintf( stderr, "PTR\n" );
593
594     GETS( &ptr.i_ttu_nb );
595 //fprintf( stderr, "PTR: TTU nb %d\n", ptr.i_ttu_nb );
596     FLUSH( 2 );
597     GETL( &ptr.i_ebyte );
598     /* Parsing of tts */
599     ptr.p_tts = malloc( ptr.i_ttu_nb *sizeof(tts_t) );
600     if( ptr.p_tts == NULL )
601     {
602         intf_ErrMsg( "Out of memory" );
603         p_ifo->b_error = 1;
604         return ptr;
605     }
606     for( i=0 ; i<ptr.i_ttu_nb ; i++ )
607     {
608         GETC( &ptr.p_tts[i].i_play_type );
609         GETC( &ptr.p_tts[i].i_angle_nb );
610         GETS( &ptr.p_tts[i].i_ptt_nb );
611         GETS( &ptr.p_tts[i].i_parental_id );
612         GETC( &ptr.p_tts[i].i_tts_nb );
613         GETC( &ptr.p_tts[i].i_vts_ttn );
614         GETL( &ptr.p_tts[i].i_ssector );
615 //fprintf( stderr, "PTR: %d %d %d\n", ptr.p_tts[i].i_ptt_nb, ptr.p_tts[i].i_tts_nb,ptr.p_tts[i].i_vts_ttn );
616     }
617
618     return ptr;
619 }
620
621 /*****************************************************************************
622  * ReadParentalInf : Fills the Parental Management structure.
623  *****************************************************************************/
624 static vmg_ptl_mait_t ReadParentalInf( ifo_t* p_ifo )
625 {
626     vmg_ptl_mait_t  par;
627     int             i, j, k;
628     off_t           i_start = p_ifo->i_pos;
629
630 //fprintf( stderr, "PTL\n" );
631
632     GETS( &par.i_country_nb );
633     GETS( &par.i_vts_nb );
634     GETL( &par.i_ebyte );
635     par.p_ptl_desc = malloc( par.i_country_nb *sizeof(vmg_ptl_mai_desc_t) );
636     if( par.p_ptl_desc == NULL )
637     {
638         intf_ErrMsg( "Out of memory" );
639         p_ifo->b_error = 1;
640         return par;
641     }
642     for( i=0 ; i<par.i_country_nb ; i++ )
643     {
644         GET( par.p_ptl_desc[i].ps_country_code, 2 );
645         FLUSH( 2 );
646         GETS( &par.p_ptl_desc[i].i_ptl_mai_sbyte );
647         FLUSH( 2 );
648     }
649     par.p_ptl_mask = malloc( par.i_country_nb *sizeof(vmg_ptl_mask_t) );
650     if( par.p_ptl_mask == NULL )
651     {
652         intf_ErrMsg( "Out of memory" );
653         p_ifo->b_error = 1;
654         return par;
655     }
656     for( i=0 ; i<par.i_country_nb ; i++ )
657     {
658         p_ifo->i_pos = lseek( p_ifo->i_fd, i_start +
659                          par.p_ptl_desc[i].i_ptl_mai_sbyte, SEEK_SET );
660         for( j=1 ; j<=8 ; j++ )
661         {
662             par.p_ptl_mask[i].ppi_ptl_mask[j] =
663                                     malloc( par.i_vts_nb *sizeof(u16) );
664             if( par.p_ptl_mask[i].ppi_ptl_mask[j] == NULL )
665             {
666                 intf_ErrMsg( "Out of memory" );
667                 p_ifo->b_error = 1;
668                 return par;
669             }        
670             for( k=0 ; k<par.i_vts_nb ; k++ )
671             {
672                 GETS( &par.p_ptl_mask[i].ppi_ptl_mask[j][k] );
673             }
674         }
675     }
676
677     return par;
678 }
679
680 /*****************************************************************************
681  * ReadVTSAttr : Fills the structure about VTS attributes.
682  *****************************************************************************/
683 static vmg_vts_atrt_t ReadVTSAttr( ifo_t* p_ifo )
684 {
685     vmg_vts_atrt_t  atrt;
686     int             i, j;
687     off_t           i_start = p_ifo->i_pos;
688
689 //fprintf( stderr, "VTS ATTR\n" );
690
691     GETS( &atrt.i_vts_nb );
692 //fprintf( stderr, "VTS ATTR Nb: %d\n", atrt.i_vts_nb );
693     FLUSH( 2 );
694     GETL( &atrt.i_ebyte );
695     atrt.pi_vts_atrt_sbyte = malloc( atrt.i_vts_nb *sizeof(u32) );
696     if( atrt.pi_vts_atrt_sbyte == NULL )
697     {
698         intf_ErrMsg( "Out of memory" );
699         p_ifo->b_error = 1;
700         return atrt;
701     }
702     for( i=0 ; i<atrt.i_vts_nb ; i++ )
703     {
704         GETL( &atrt.pi_vts_atrt_sbyte[i] );
705     }
706     atrt.p_vts_atrt = malloc( atrt.i_vts_nb *sizeof(vts_atrt_t) );
707     if( atrt.p_vts_atrt == NULL )
708     {
709         intf_ErrMsg( "Out of memory" );
710         p_ifo->b_error = 1;
711         return atrt;
712     }
713     for( i=0 ; i<atrt.i_vts_nb ; i++ )
714     {
715         p_ifo->i_pos = lseek( p_ifo->i_fd, i_start +
716                                 atrt.pi_vts_atrt_sbyte[i],
717                                 SEEK_SET );
718         GETL( &atrt.p_vts_atrt[i].i_ebyte );
719         GETL( &atrt.p_vts_atrt[i].i_cat_app_type );
720         GETS( &atrt.p_vts_atrt[i].i_vtsm_video_atrt );
721         FLUSH( 1 );
722         GETC( &atrt.p_vts_atrt[i].i_vtsm_audio_nb );
723 //fprintf( stderr, "m audio nb : %d\n", atrt.p_vts_atrt[i].i_vtsm_audio_nb );
724         for( j=0 ; j<8 ; j++ )
725         {
726             GETLL( &atrt.p_vts_atrt[i].pi_vtsm_audio_atrt[j] );
727         }
728         FLUSH( 17 );
729         GETC( &atrt.p_vts_atrt[i].i_vtsm_subpic_nb );
730 //fprintf( stderr, "m subp nb : %d\n", atrt.p_vts_atrt[i].i_vtsm_subpic_nb );
731         for( j=0 ; j<28 ; j++ )
732         {
733             GET( &atrt.p_vts_atrt[i].pi_vtsm_subpic_atrt[j], 6 );
734             /* FIXME : Fix endianness issue here */
735         }
736         FLUSH( 2 );
737         GETS( &atrt.p_vts_atrt[i].i_vtstt_video_atrt );
738         FLUSH( 1 );
739         GETL( &atrt.p_vts_atrt[i].i_vtstt_audio_nb );
740 //fprintf( stderr, "tt audio nb : %d\n", atrt.p_vts_atrt[i].i_vtstt_audio_nb );
741         for( j=0 ; j<8 ; j++ )
742         {
743             GETLL( &atrt.p_vts_atrt[i].pi_vtstt_audio_atrt[j] );
744         }
745         FLUSH( 17 );
746         GETC( &atrt.p_vts_atrt[i].i_vtstt_subpic_nb );
747 //fprintf( stderr, "tt subp nb : %d\n", atrt.p_vts_atrt[i].i_vtstt_subpic_nb );
748         for( j=0 ; j<28/*atrt.p_vts_atrt[i].i_vtstt_subpic_nb*/ ; j++ )
749         {
750             GET( &atrt.p_vts_atrt[i].pi_vtstt_subpic_atrt[j], 6 );
751             /* FIXME : Fix endianness issue here */
752         }
753     }
754
755     return atrt;
756 }
757                            
758 /*****************************************************************************
759  * ReadVMG : Parse video_ts.ifo file to fill the Video Manager structure.
760  *****************************************************************************/
761 static vmg_t ReadVMG( ifo_t* p_ifo )
762 {
763     vmg_t       vmg;
764
765     p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off, SEEK_SET);
766     vmg.mat = ReadVMGInfMat( p_ifo );
767     p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off + 
768                               vmg.mat.i_fp_pgc_sbyte, SEEK_SET );
769     vmg.pgc = ReadPGC( p_ifo );
770     if( vmg.mat.i_ptt_srpt_ssector )
771     {
772         p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
773                         vmg.mat.i_ptt_srpt_ssector *DVD_LB_SIZE,
774                         SEEK_SET );
775         vmg.ptt_srpt = ReadVMGTitlePointer( p_ifo );
776     }
777     if( vmg.mat.i_pgci_ut_ssector )
778     {
779         p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
780                         vmg.mat.i_pgci_ut_ssector *DVD_LB_SIZE,
781                         SEEK_SET );
782         vmg.pgci_ut = ReadUnitTable( p_ifo );
783     }
784     if( vmg.mat.i_ptl_mait_ssector )
785     {
786         p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
787                         vmg.mat.i_ptl_mait_ssector *DVD_LB_SIZE,
788                         SEEK_SET );
789         vmg.ptl_mait = ReadParentalInf( p_ifo );
790     }
791     if( vmg.mat.i_vts_atrt_ssector )
792     {
793         p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
794                         vmg.mat.i_vts_atrt_ssector *DVD_LB_SIZE,
795                         SEEK_SET );
796         vmg.vts_atrt = ReadVTSAttr( p_ifo );
797     }
798     if( vmg.mat.i_c_adt_ssector )
799     {
800         p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
801                         vmg.mat.i_c_adt_ssector *DVD_LB_SIZE,
802                         SEEK_SET );
803         vmg.c_adt = ReadCellInf( p_ifo );
804     }
805     if( vmg.mat.i_vobu_admap_ssector )
806     {
807         p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
808                         vmg.mat.i_vobu_admap_ssector *DVD_LB_SIZE,
809                         SEEK_SET );
810         vmg.vobu_admap = ReadMap( p_ifo );
811     }
812     return vmg;
813 }
814
815 /*
816  * Video Title Set Information Processing.
817  * This is what is contained in vts_*.ifo.
818  */
819
820 /*****************************************************************************
821  * ReadVTSInfMat : Fills the Title Set Information structure.
822  *****************************************************************************/
823 static vtsi_mat_t ReadVTSInfMat( ifo_t* p_ifo )
824 {
825     vtsi_mat_t  mat;
826     int         i;
827 //    off_t       i_start = p_ifo->i_pos;
828
829 //fprintf( stderr, "VTSI\n" );
830
831     GET( mat.psz_id , 12 );
832     mat.psz_id[12] = '\0';
833     GETL( &mat.i_lsector );
834     FLUSH( 12 );
835     GETL( &mat.i_i_lsector );
836     FLUSH( 1 );
837     GETC( &mat.i_spec_ver );
838     GETL( &mat.i_cat );
839     FLUSH( 90 );
840     GETL( &mat.i_mat_ebyte );
841     FLUSH( 60 );
842     GETL( &mat.i_m_vobs_ssector );
843     GETL( &mat.i_tt_vobs_ssector );
844     GETL( &mat.i_ptt_srpt_ssector );
845     GETL( &mat.i_pgcit_ssector );
846     GETL( &mat.i_m_pgci_ut_ssector );
847     GETL( &mat.i_tmap_ti_ssector );
848     GETL( &mat.i_m_c_adt_ssector );
849     GETL( &mat.i_m_vobu_admap_ssector );
850     GETL( &mat.i_c_adt_ssector );
851     GETL( &mat.i_vobu_admap_ssector );
852     FLUSH( 24 );
853     GETS( &mat.i_m_video_atrt );
854     FLUSH( 1 );
855     GETC( &mat.i_m_audio_nb );
856     for( i=0 ; i<8 ; i++ )
857     {
858         GETLL( &mat.pi_m_audio_atrt[i] );
859     }
860     FLUSH( 17 );
861     GETC( &mat.i_m_subpic_nb );
862     for( i=0 ; i<28 ; i++ )
863     {
864         GET( &mat.pi_m_subpic_atrt[i], 6 );
865         /* FIXME : take care of endianness */
866     }
867     FLUSH( 2 );
868     GETS( &mat.i_video_atrt );
869     FLUSH( 1 );
870     GETC( &mat.i_audio_nb );
871 //fprintf( stderr, "vtsi audio nb : %d\n", mat.i_audio_nb );
872     for( i=0 ; i<8 ; i++ )
873     {
874         GETLL( &mat.pi_audio_atrt[i] );
875     }
876     FLUSH( 17 );
877     GETC( &mat.i_subpic_nb );
878 //fprintf( stderr, "vtsi subpic nb : %d\n", mat.i_subpic_nb );
879     for( i=0 ; i<mat.i_subpic_nb ; i++ )
880     {
881         GET( &mat.pi_subpic_atrt[i], 6 );
882         /* FIXME : take care of endianness */
883     }
884
885     return mat;
886 }
887
888 /*****************************************************************************
889  * ReadVTSTitlePointer : Fills the Part Of Title Search Pointer structure.
890  *****************************************************************************/
891 static vts_ptt_srpt_t ReadVTSTitlePointer( ifo_t* p_ifo )
892 {
893     vts_ptt_srpt_t  ptr;
894     int             i;
895     off_t           i_start = p_ifo->i_pos;
896
897 //fprintf( stderr, "VTS PTR\n" );
898
899     GETS( &ptr.i_ttu_nb );
900 //fprintf( stderr, "VTS PTR nb: %d\n", ptr.i_ttu_nb );
901     FLUSH( 2 );
902     GETL( &ptr.i_ebyte );
903     ptr.pi_ttu_sbyte = malloc( ptr.i_ttu_nb *sizeof(u32) );
904     if( ptr.pi_ttu_sbyte == NULL )
905     {
906         intf_ErrMsg( "Out of memory" );
907         p_ifo->b_error = 1;
908         return ptr;
909     }
910     for( i=0 ; i<ptr.i_ttu_nb ; i++ )
911     {
912         GETL( &ptr.pi_ttu_sbyte[i] );
913     }
914     /* Parsing of tts */
915     ptr.p_ttu = malloc( ptr.i_ttu_nb *sizeof(ttu_t) );
916     if( ptr.p_ttu == NULL )
917     {
918         intf_ErrMsg( "Out of memory" );
919         p_ifo->b_error = 1;
920         return ptr;
921     }
922     for( i=0 ; i<ptr.i_ttu_nb ; i++ )
923     {
924         p_ifo->i_pos = lseek( p_ifo->i_fd, i_start +
925                         ptr.pi_ttu_sbyte[i], SEEK_SET );
926         GETS( &ptr.p_ttu[i].i_pgc_nb );
927         GETS( &ptr.p_ttu[i].i_prg_nb );
928 //fprintf( stderr, "VTS %d PTR Pgc: %d Prg: %d\n", i,ptr.p_ttu[i].i_pgc_nb, ptr.p_ttu[i].i_prg_nb );
929     }
930
931     return ptr;
932 }
933
934 /*****************************************************************************
935  * ReadVTSTimeMap : Fills the time map table
936  *****************************************************************************/
937 static vts_tmap_ti_t ReadVTSTimeMap( ifo_t* p_ifo )
938 {
939     vts_tmap_ti_t   tmap;
940     int             i,j;
941 //    off_t           i_start = p_ifo->i_pos;
942
943 //fprintf( stderr, "TMAP\n" );
944
945     GETS( &tmap.i_nb );
946     FLUSH( 2 );
947     GETL( &tmap.i_ebyte );
948     tmap.pi_sbyte = malloc( tmap.i_nb *sizeof(u32) );
949     if( tmap.pi_sbyte == NULL )
950     {
951         intf_ErrMsg( "Out of memory" );
952         p_ifo->b_error = 1;
953         return tmap;
954     }
955     for( i=0 ; i<tmap.i_nb ; i++ )
956     {    
957         GETL( &tmap.pi_sbyte[i] );
958     }
959     tmap.p_tmap = malloc( tmap.i_nb *sizeof(tmap_t) );
960     if( tmap.p_tmap == NULL )
961     {
962         intf_ErrMsg( "Out of memory" );
963         p_ifo->b_error = 1;
964         return tmap;
965     }
966     for( i=0 ; i<tmap.i_nb ; i++ )
967     {    
968         GETC( &tmap.p_tmap[i].i_time_unit );
969         FLUSH( 1 );
970         GETS( &tmap.p_tmap[i].i_entry_nb );
971         tmap.p_tmap[i].pi_sector =
972                     malloc( tmap.p_tmap[i].i_entry_nb *sizeof(u32) );
973         if( tmap.p_tmap[i].pi_sector == NULL )
974         {
975             intf_ErrMsg( "Out of memory" );
976             p_ifo->b_error = 1;
977             return tmap;
978         }
979         for( j=0 ; j<tmap.p_tmap[i].i_entry_nb ; j++ )
980         {
981             GETL( &tmap.p_tmap[i].pi_sector[j] );
982         }
983     }
984
985     return tmap;
986 }
987     
988
989 /*****************************************************************************
990  * IfoReadVTS : Parse vts*.ifo files to fill the Video Title Set structure.
991  *****************************************************************************/
992 int IfoReadVTS( ifo_t* p_ifo )
993 {
994     vts_t       vts;
995     off_t       i_off;
996     int         i_title;
997
998     intf_WarnMsg( 2, "ifo: initializing VTS %d", p_ifo->i_title );
999
1000     i_title = p_ifo->i_title;
1001     i_off = (off_t)( p_ifo->vmg.ptt_srpt.p_tts[i_title].i_ssector ) *DVD_LB_SIZE
1002                    + p_ifo->i_off;
1003
1004     p_ifo->i_pos = lseek( p_ifo->i_fd, i_off, SEEK_SET );
1005
1006     vts.i_pos = p_ifo->i_pos;
1007
1008     vts.mat = ReadVTSInfMat( p_ifo );
1009     if( vts.mat.i_ptt_srpt_ssector )
1010     {
1011         p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
1012                         vts.mat.i_ptt_srpt_ssector *DVD_LB_SIZE,
1013                         SEEK_SET );
1014         vts.ptt_srpt = ReadVTSTitlePointer( p_ifo );
1015     }
1016     if( vts.mat.i_m_pgci_ut_ssector )
1017     {
1018         p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
1019                         vts.mat.i_m_pgci_ut_ssector *DVD_LB_SIZE,
1020                         SEEK_SET );
1021         vts.pgci_ut = ReadUnitTable( p_ifo );
1022     }
1023     if( vts.mat.i_pgcit_ssector )
1024     {
1025         p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
1026                         vts.mat.i_pgcit_ssector *DVD_LB_SIZE,
1027                         SEEK_SET );
1028         vts.pgci_ti = ReadUnit( p_ifo );
1029     }
1030     if( vts.mat.i_tmap_ti_ssector )
1031     {
1032         p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
1033                         vts.mat.i_tmap_ti_ssector *DVD_LB_SIZE,
1034                         SEEK_SET );
1035         vts.tmap_ti = ReadVTSTimeMap( p_ifo );
1036     }
1037     if( vts.mat.i_m_c_adt_ssector )
1038     {
1039         p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
1040                         vts.mat.i_m_c_adt_ssector *DVD_LB_SIZE,
1041                         SEEK_SET );
1042         vts.m_c_adt = ReadCellInf( p_ifo );
1043     }
1044     if( vts.mat.i_m_vobu_admap_ssector )
1045     {
1046         p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
1047                         vts.mat.i_m_vobu_admap_ssector *DVD_LB_SIZE,
1048                         SEEK_SET );
1049         vts.m_vobu_admap = ReadMap( p_ifo );
1050     }
1051     if( vts.mat.i_c_adt_ssector )
1052     {
1053         p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
1054                         vts.mat.i_c_adt_ssector *DVD_LB_SIZE,
1055                         SEEK_SET );
1056         vts.c_adt = ReadCellInf( p_ifo );
1057     }
1058     if( vts.mat.i_vobu_admap_ssector )
1059     {
1060         p_ifo->i_pos = lseek( p_ifo->i_fd, vts.i_pos +
1061                         vts.mat.i_vobu_admap_ssector *DVD_LB_SIZE,
1062                         SEEK_SET );
1063         vts.vobu_admap = ReadMap( p_ifo );
1064     }
1065
1066     p_ifo->vts = vts;
1067
1068     return 0;
1069 }
1070
1071 /*
1072  * DVD Information Management
1073  */
1074 #if 0
1075 /*****************************************************************************
1076  * IfoRead : Function that fills structure and calls specified functions
1077  * to do it.
1078  *****************************************************************************/
1079 void IfoRead( ifo_t* p_ifo )
1080 {
1081     int     i;
1082     off_t   i_off;
1083
1084     /* Video Title Sets initialization */
1085     p_ifo->p_vts = malloc( p_ifo->vmg.mat.i_tts_nb *sizeof(vts_t) );
1086     if( p_ifo->p_vts == NULL )
1087     {
1088         intf_ErrMsg( "Out of memory" );
1089         p_ifo->b_error = 1;
1090         return;
1091     }
1092
1093     for( i=0 ; i<p_ifo->vmg.mat.i_tts_nb ; i++ )
1094     {
1095
1096         intf_WarnMsg( 2, "ifo: initializing VTS %d", i+1 );
1097
1098         i_off = (off_t)( p_ifo->vmg.ptt_srpt.p_tts[i].i_ssector ) *DVD_LB_SIZE
1099                        + p_ifo->i_off;
1100
1101         p_ifo->i_pos = lseek( p_ifo->i_fd, i_off, SEEK_SET );
1102
1103         /* FIXME : I really don't know why udf find file
1104          * does not give the exact beginning of file */
1105
1106         p_ifo->p_vts[i] = ReadVTS( p_ifo );
1107
1108     }
1109
1110     return; 
1111 }
1112 #endif
1113 /*
1114  * IFO virtual machine : a set of commands that give the
1115  * interactive behaviour of the dvd
1116  */
1117 #if 1
1118
1119 #define OP_VAL_16(i) (ntoh16( com.data.pi_16[i]))
1120 #define OP_VAL_8(i) ((com.data.pi_8[i]))
1121
1122 static char ifo_reg[][80]=
1123 {
1124     "Menu_Language_Code",
1125     "Audio_Stream_#",
1126     "SubPicture_Stream_#",
1127     "Angle_#",
1128     "VTS_#",
1129     "VTS_Title_#",
1130     "PGC_#",
1131     "PTT_#",
1132     "Highlighted_Button_#",
1133     "Nav_Timer",
1134     "TimedPGC",
1135     "Karaoke_audio_mixing_mode",
1136     "Parental_mgmt_country_code",
1137     "Parental_Level",
1138     "Player_Video_Cfg",
1139     "Player_Audio_Cfg",
1140     "Audio_language_code_setting",
1141     "Audio_language_extension_code",
1142     "SPU_language_code_setting",
1143     "SPU_language_extension_code",
1144     "?Player_Regional_Code",
1145     "Reserved_21",
1146     "Reserved_22",
1147     "Reserved_23"
1148 };
1149
1150 static char * IfoMath( char val )
1151 {
1152     static char math_op[][10] =
1153     {
1154         "none",
1155         "=", 
1156         "<->",    // swap
1157         "+=",
1158         "-=",
1159         "*=",
1160         "/=",
1161         "%=",
1162         "rnd",    // rnd
1163         "&=",
1164         "|=",
1165         "^=",
1166         "??",    // invalid
1167         "??",    // invalid
1168         "??",    // invalid
1169         "??"    // invalid
1170     };
1171
1172     return (char *) math_op[val & 0x0f];
1173 }
1174
1175
1176 char ifo_cmp[][10] =
1177 {
1178     "none",
1179     "&&",
1180     "==",
1181     "!=",
1182     ">=",
1183     ">",
1184     "<",
1185     "<="
1186 };
1187
1188 char ifo_parental[][10] =
1189 {
1190     "0",
1191     "G",
1192     "2",
1193     "PG",
1194     "PG-13",
1195     "5",
1196     "R",
1197     "NC-17"
1198 };
1199
1200 char ifo_menu_id[][80] =
1201 {
1202     "-0-",
1203     "-1-",
1204     "Title (VTS menu)",
1205     "Root",
1206     "Sub-Picture",
1207     "Audio",
1208     "Angle",
1209     "Part of Title",
1210 };
1211
1212 char * IfoMenuName( char index )
1213 {
1214     return ifo_menu_id[index&0x07];
1215 }
1216
1217 static void IfoRegister( u16 i_data, u8 i_direct)
1218 {
1219     if( i_direct )
1220     {
1221         if( 0/*isalpha( i_data >> 8 & 0xff )*/ )
1222         {
1223             printf("'%c%c'", i_data>>8&0xff, i_data&0xff);
1224         }
1225         else
1226         {
1227             printf("0x%02x", i_data);
1228         }
1229     }
1230     else
1231     {
1232         if( i_data & 0x80 )
1233         {
1234             i_data &= 0x1f;
1235
1236             if( i_data > 0x17 )
1237             {
1238                 printf("s[ILL]");
1239             }
1240             else
1241             {
1242                 printf("s[%s]", ifo_reg[i_data]);
1243             }
1244         }
1245         else
1246         {
1247             i_data &= 0x1f;
1248
1249             if( i_data > 0xf )
1250             {
1251                 printf("r[ILL]");
1252             }
1253             else
1254             {
1255                 printf("r[0x%02x]", i_data);
1256             }
1257         }
1258     }
1259 }
1260
1261 static void IfoAdvanced( u8 *pi_code )
1262 {
1263     u8      i_cmd = pi_code[0];
1264
1265     printf(" { ");
1266
1267     if( pi_code[1]>>2 )
1268     {
1269         printf( " Highlight button %d; ", pi_code[1]>>2 );
1270     }
1271
1272     if( i_cmd == 0xff )
1273     {
1274         printf( " Illegal " );
1275     }
1276
1277     if( i_cmd == 0x00 )
1278     {
1279         printf( "ReSuME %d", pi_code[7] );
1280     }
1281     else if( ( i_cmd & 0x06) == 0x02 )
1282     {    // XX01Y
1283         printf ("Link to %s cell ", ( i_cmd & 0x01 ) ? "prev" : "next");
1284     }
1285     else
1286     {
1287         printf( "advanced (0x%02x) ", i_cmd );
1288     }
1289     printf(" } ");
1290 }
1291
1292 static void IfoJmp( ifo_command_t com )
1293 {
1294
1295     printf ("jmp ");
1296
1297     switch( com.i_sub_cmd )
1298     {
1299     case 0x01:
1300         printf( "Exit" );
1301         break;
1302     case 0x02:
1303         printf( "VTS 0x%02x", OP_VAL_8(3) );
1304         break;
1305     case 0x03:
1306         printf( "This VTS Title 0x%02x", OP_VAL_8(3) );
1307         break;
1308     case 0x05:
1309         printf( "This VTS Title 0x%02x Part 0x%04x",
1310                             OP_VAL_8(3),
1311                             OP_VAL_8(0)<<8|OP_VAL_8(1));
1312         break;
1313     case 0x06:
1314 #if 0
1315             printf ("in SystemSpace ");
1316             switch (OP_VAL_8(3)>>4) {
1317                 case 0x00:
1318                     printf ("to play first PGC");
1319                     break;
1320                 case 0x01: {
1321                     printf ("to menu \"%s\"", decode_menuname (OP_VAL_8(3)));
1322                 }
1323                     break;
1324                 case 0x02:
1325                     printf ("to VTS 0x%02x and TTN 0x%02x", OP_VAL_8(1), OP_VAL_8(2));
1326                     break;
1327                 case 0x03:
1328                     printf ("to VMGM PGC number 0x%02x", OP_VAL_8(0)<<8 | OP_VAL_8(1));
1329                     break;
1330                 case 0x08:
1331                     printf ("vts 0x%02x lu 0x%02x menu \"%s\"", OP_VAL_8(2), OP_VAL_8(1), decode_menuname (OP_VAL_8(3)));
1332                     break;
1333 #else
1334         switch( OP_VAL_8(3)>>6 )
1335         {
1336         case 0x00:
1337             printf( "to play first PGC" );
1338             break;                
1339         case 0x01:
1340             printf( "to VMG title menu (?)" );
1341             break;
1342         case 0x02:
1343             printf( "vts 0x%02x lu 0x%02x menu \"%s\"",
1344                             OP_VAL_8(2),
1345                             OP_VAL_8(1),
1346                             IfoMenuName( OP_VAL_8(3)&0xF ) );
1347             break;                
1348         case 0x03:
1349             printf( "vmg pgc 0x%04x (?)", ( OP_VAL_8(0)<<8) | OP_VAL_8(1) );
1350             break;
1351 #endif
1352         }
1353         break;
1354     case 0x08:
1355 #if 0
1356             switch(OP_VAL_8(3)>>4) {
1357                 case 0x00:
1358                     printf ("system first pgc");
1359                     break;
1360                 case 0x01:
1361                     printf ("system title menu");
1362                     break;
1363                 case 0x02:
1364                     printf ("system menu \"%s\"", decode_menuname (OP_VAL_8(3)));
1365                     break;
1366                 case 0x03:
1367                     printf ("system vmg pgc %02x ????", OP_VAL_8(0)<<8|OP_VAL_8(1));
1368                     break;
1369                 case 0x08:
1370                     printf ("system lu 0x%02x menu \"%s\"", OP_VAL_8(2), decode_menuname (OP_VAL_8(3)));
1371                     break;
1372                 case 0x0c:
1373                     printf ("system vmg pgc 0x%02x", OP_VAL_8(0)<<8|OP_VAL_8(1));
1374                     break;
1375             }
1376 #else
1377         // OP_VAL_8(2) is number of cell
1378         // it is processed BEFORE switch
1379         // under some conditions, it is ignored
1380         // I don't understand exactly what it means
1381         printf( " ( spec cell 0x%02X ) ", OP_VAL_8(2) ); 
1382
1383         switch( OP_VAL_8(3)>>6 )
1384         {
1385         case 0:
1386             printf( "to FP PGC" );
1387             break;
1388         case 1:
1389             printf( "to VMG root menu (?)" );
1390             break;
1391         case 2:
1392             printf( "to VTS menu \"%s\" (?)",
1393                     IfoMenuName(OP_VAL_8(3)&0xF) );
1394             break; 
1395         case 3:
1396             printf( "vmg pgc 0x%02x (?)", (OP_VAL_8(0)<<8)|OP_VAL_8(1) );
1397             break;
1398         }    
1399 #endif
1400         break;
1401     }
1402 }
1403
1404 static void IfoLnk( ifo_command_t com )
1405 {
1406     u16     i_button=OP_VAL_8(4)>>2;
1407
1408     printf ("lnk to ");
1409
1410     switch( com.i_sub_cmd )
1411     {
1412     case 0x01:
1413         IfoAdvanced( &OP_VAL_8(4) );
1414         break;
1415
1416     case 0x04:
1417         printf( "PGC 0x%02x", OP_VAL_16(2) );
1418         break; 
1419
1420     case 0x05:
1421         printf( "PTT 0x%02x", OP_VAL_16(2) );
1422         break; 
1423
1424     case 0x06:
1425         printf( "Program 0x%02x this PGC", OP_VAL_8(5) );
1426         break;
1427
1428     case 0x07:
1429         printf( "Cell 0x%02x this PGC", OP_VAL_8(5) );
1430         break;
1431     default:
1432         return;
1433     }
1434
1435     if( i_button )
1436     {
1437         printf( ", Highlight 0x%02x", OP_VAL_8(4)>>2 );
1438     }
1439             
1440 }
1441
1442 void IfoSetSystem( ifo_command_t com )
1443 {
1444     switch( com.i_cmd )
1445     {
1446     case 1: {
1447         int i;
1448
1449         for( i=1; i<=3; i++ )
1450         {
1451             if( OP_VAL_8(i)&0x80 )
1452             {
1453                 if( com.i_direct )
1454                 {
1455                     printf ("s[%s] = 0x%02x;", ifo_reg[i], OP_VAL_8(i)&0xf);
1456                 }
1457                 else
1458                 {
1459                     printf ("s[%s] = r[0x%02x];", ifo_reg[i], OP_VAL_8(i)&0xf);
1460                 }
1461             }
1462         }
1463 #if 0
1464                 if(op->direct) {
1465                         if(OP_VAL_8(1]&0x80)
1466                                 printf ("s[%s] = 0x%02x;", reg_name[1], OP_VAL_8(1]&0xf);
1467                         if(OP_VAL_8(2)&0x80)
1468 //DENT: lwhat about 0x7f here ???
1469                                 printf ("s[%s] = 0x%02x;", reg_name[2], OP_VAL_8(2)&0x7f);
1470                         if(OP_VAL_8(3)&0x80)
1471                                 printf ("s[%s] = 0x%02x;", reg_name[3], OP_VAL_8(3)&0xf);
1472                 } else {
1473                         if(OP_VAL_8(1)&0x80)
1474                                 printf ("s[%s] = r[0x%02x];", reg_name[1], OP_VAL_8(1)&0xf);
1475                         if(OP_VAL_8(2)&0x80)
1476                                 printf ("s[%s] = r[0x%02x];", reg_name[2], OP_VAL_8(2)&0xf);
1477                         if(OP_VAL_8(3)&0x80)
1478                                 printf ("s[%s] = r[0x%02x];", reg_name[3], OP_VAL_8(3)&0xf);
1479                 }
1480 #endif
1481         }
1482         break;
1483     case 2:
1484         if( com.i_direct )
1485         {
1486             printf( "s[%s] = 0x%02x", ifo_reg[9], OP_VAL_16(0) );
1487         }
1488         else
1489         {
1490             printf( "s[%s] = r[0x%02x]", ifo_reg[9], OP_VAL_8(1)&0x0f );
1491         }
1492
1493         printf( "s[%s] = (s[%s]&0x7FFF)|0x%02x", 
1494                         ifo_reg[10], ifo_reg[10], OP_VAL_16(1)&0x8000);
1495         break;
1496     case 3:
1497         if( com.i_direct )
1498         {
1499             printf( "r[0x%02x] = 0x%02x", OP_VAL_8(3)&0x0f, OP_VAL_16(0) );
1500         }
1501         else
1502         {
1503             printf ("r[r[0x%02x]] = r[0x%02x]",
1504                                     OP_VAL_8(3)&0x0f, OP_VAL_8(1)&0x0f);
1505         }
1506         break;
1507     case 4:
1508         //actually only bits 00011100 00011100 are set
1509         if( com.i_direct )
1510         {
1511             printf ("s[%s] = 0x%02x", ifo_reg[11], OP_VAL_16(1));
1512         }
1513         else
1514         {
1515             printf ("s[%s] = r[0x%02x]", ifo_reg[11], OP_VAL_8(3)&0x0f );
1516         }
1517         break;
1518     case 6:
1519         //actually,
1520         //s[%s]=(r[%s]&0x3FF) | (0x%02x << 0xA);
1521         //but it is way too ugly
1522         if( com.i_direct )
1523         {
1524             printf( "s[%s] = 0x%02x", ifo_reg[8], OP_VAL_8(2)>>2 );
1525         }
1526         else
1527         {
1528             printf( "s[%s] = r[0x%02x]", ifo_reg[8], OP_VAL_8(3)&0x0f );
1529         }
1530         break;
1531     default:
1532         printf ("unknown");
1533     }
1534 }
1535
1536 static void IfoSet( ifo_command_t com )
1537 {
1538     IfoRegister( OP_VAL_16(0), 0 );
1539     printf( " %s ", IfoMath( com.i_cmd ) );
1540     IfoRegister( OP_VAL_16(1), com.i_direct );
1541 }
1542
1543 /*****************************************************************************
1544  * CommandRead : translates the command strings in ifo into command
1545  * structures.
1546  *****************************************************************************/
1547 void CommandRead( ifo_command_t com )
1548 {
1549     u8*     pi_code = (u8*)(&com);
1550
1551     switch( com.i_type )
1552     {
1553     /* Goto */
1554     case 0:
1555         /* Main command */
1556         if( !pi_code[1] )
1557         {
1558             printf( "NOP\n" );
1559         }
1560         else
1561         {
1562             if( com.i_cmp )
1563             {
1564                 printf ("if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
1565                                              ifo_cmp[com.i_cmp]);
1566                 IfoRegister (OP_VAL_16(1), com.i_dir_cmp);
1567                 printf (") ");
1568             }
1569         
1570             /* Sub command */
1571             switch( com.i_sub_cmd )
1572             {
1573             case 1:
1574                 printf( "goto Line 0x%02x", OP_VAL_16(2) );
1575                 break;
1576         
1577             case 2:
1578                 printf( "stop VM" );
1579                 break;
1580         
1581             case 3:
1582                 printf( "Set Parental Level To %s and goto Line 0x%02x",
1583                                      ifo_parental[OP_VAL_8(4)&0x7],
1584                                      OP_VAL_8(5) );
1585                 break;
1586         
1587             default:
1588                 printf( "Illegal" );
1589                 break;
1590             }
1591         }
1592         break;
1593
1594     /* Lnk */
1595     case 1:
1596         /* Main command */
1597         if( !pi_code[1] )
1598         {
1599             printf( "NOP\n" );
1600         }
1601         else
1602         {
1603             if( com.i_direct )
1604             {
1605                 if( com.i_cmp )
1606                 {
1607                     printf( "if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f,
1608                                                  ifo_cmp[com.i_cmp] );
1609                     IfoRegister( OP_VAL_8(5), 0 );
1610                     printf( ") " );
1611                 }
1612
1613                 /* Sub command */
1614                 IfoJmp( com );
1615             }
1616             else
1617             {    
1618                 if( com.i_cmp )
1619                 {
1620                     printf( "if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
1621                                                  ifo_cmp[com.i_cmp] );
1622                     IfoRegister( OP_VAL_16(1), com.i_dir_cmp );
1623                     printf( ") " );
1624                 }
1625
1626                 /* Sub command */
1627                 IfoLnk( com );
1628             }
1629         }
1630         break;
1631
1632     /* SetSystem */
1633     case 2:
1634         if( !pi_code[1] )
1635         {
1636             IfoSetSystem( com );
1637         }
1638         else if( com.i_cmp && !com.i_sub_cmd )
1639         {
1640             printf ("if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f, ifo_cmp[com.i_cmp]);
1641             IfoRegister( OP_VAL_8(5), 0 );
1642             printf (") ");
1643             IfoSetSystem( com );
1644         }
1645         else if( !com.i_cmp && com.i_sub_cmd )
1646         {
1647             printf( "if (" );
1648             IfoSetSystem( com );
1649             printf( ") " );
1650             IfoLnk( com );
1651         }
1652         else
1653         {
1654             printf("nop");
1655         }
1656         break;
1657
1658     /* Set */
1659     case 3:
1660           if( ! pi_code[1] )
1661         {
1662             IfoSet( com );
1663         }
1664         else if( com.i_cmp && !com.i_sub_cmd )
1665         {
1666             printf ("if (r[0x%02x] %s ", OP_VAL_8(0)&0x0f, ifo_cmp[com.i_cmp]);
1667             IfoRegister( OP_VAL_16(2), com.i_dir_cmp );
1668             printf (") ");
1669             IfoSet( com );
1670         }
1671         else if( !com.i_cmp && com.i_sub_cmd )
1672         {
1673             printf ("if (");
1674             IfoSet( com );
1675             printf (") ");
1676             IfoLnk( com );
1677         }
1678         else
1679         {
1680             printf( "nop" );
1681         }
1682         break;
1683
1684     /* 
1685      * math command on r[opcode[1]] and
1686      * direct?be2me_16(OP_VAL_8(0)):reg[OP_VAL_8(1)] is executed
1687      * ( unless command is swap; then r[opcode[1]] and r[OP_VAL_8(1)]
1688      * are swapped )
1689      * boolean operation cmp on r[opcode[1]] and
1690      * dir_cmp?be2me_16(OP_VAL_8(1)[1]):reg[OP_VAL_8(3)] is executed
1691      * on true result, buttons(c[6], c[7]) is called
1692      * problem is 'what is buttons()'
1693      */
1694     case 4:
1695         printf( "r[0x%X] ", pi_code[1] );
1696         printf( " %s ", IfoMath( com.i_cmd ) );
1697         if( com.i_cmd == 2 )
1698         {
1699             printf( "r[0x%X] ", OP_VAL_8(1) );
1700         }
1701         else
1702         {
1703             IfoRegister( OP_VAL_16(0), com.i_direct );
1704         }
1705         printf("; ");
1706
1707         printf( "if ( r[%d] %s ", pi_code[1], ifo_cmp[com.i_cmp] );
1708         IfoRegister( OP_VAL_8(1), com.i_dir_cmp );
1709         printf( " )  then {" );
1710         IfoAdvanced( &OP_VAL_8(4) );
1711         printf( "}" );
1712         break;
1713
1714     /*
1715      * opposite to case 4: boolean, math and buttons.
1716      */
1717     case 5:
1718     case 6:
1719         printf("if (");
1720
1721         if( !com.i_direct && com.i_dir_cmp )
1722         {
1723             printf( "0x%X", OP_VAL_16(1) );
1724         }
1725         else
1726         {
1727             IfoRegister( OP_VAL_8(3), 0 );
1728             if( OP_VAL_8(3)&0x80 )
1729             {
1730                 printf( "s[%s]", ifo_reg[OP_VAL_8(3)&0x1F] );
1731             }
1732             else
1733             {
1734                 printf( "r[0x%X]", OP_VAL_8(3)&0x1F);
1735                     // 0x1F is either not a mistake,
1736                     // or Microsoft programmer's mistake!!!
1737             }
1738         }
1739
1740         printf( " %s r[0x%X] ", ifo_cmp[com.i_cmp],
1741                                 com.i_direct ? OP_VAL_8(2) : OP_VAL_8(1) );
1742            printf( " )  then {" );
1743         printf( "r[0x%X] ", pi_code[1] & 0xF );
1744         printf( " %s ", IfoMath( com.i_cmd ) );
1745
1746         if( com.i_cmd == 0x02 )    // swap
1747         {
1748             printf("r[0x%X] ", OP_VAL_8(0)&0x1F);
1749         }
1750         else
1751         {
1752             if( com.i_direct )
1753             {
1754                 printf( "0x%X", OP_VAL_16(0) );
1755             }
1756             else
1757             {
1758                 if( OP_VAL_8(0) & 0x80 )
1759                 {
1760                     printf("s[%s]", ifo_reg[OP_VAL_8(0) & 0x1F] );
1761                 }
1762                 else
1763                 {
1764                     printf("r[0x%X]", OP_VAL_8(0) & 0x1F );
1765                 }
1766             }
1767         }
1768
1769         printf("; ");
1770         IfoAdvanced( &OP_VAL_8(4) );
1771         printf("}");
1772
1773         break;
1774
1775     default:
1776         printf( "Unknown Command\n" );
1777         break;
1778     }
1779
1780     return;
1781 }
1782
1783 /*****************************************************************************
1784  * CommandPrint : print in clear text (I hope so !) what a command does
1785  *****************************************************************************/
1786 void CommandPrint( ifo_t ifo )
1787 {
1788     return;
1789 }
1790
1791 #endif