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