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