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