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