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