]> git.sesse.net Git - vlc/blob - plugins/dvd/dvd_ifo.c
* Portability : changed off64_t to off_t and activated appropriate
[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.3 2001/02/08 17:44:12 massiot Exp $
6  *
7  * Author: Stéphane Borel <stef@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <fcntl.h>
31
32 #include "common.h"
33
34 #include "intf_msg.h"
35 #include "dvd_ifo.h"
36 #include "input_dvd.h"
37
38 /*
39  * IFO Management.
40  */
41
42 /*****************************************************************************
43  * IfoFindVMG : When reading directly on a device, finds the offset to the
44  * beginning of video_ts.ifo.
45  *****************************************************************************/
46 static int IfoFindVMG( ifo_t* p_ifo )
47 {
48     char    psz_ifo_start[12] = "DVDVIDEO-VMG";
49     char    psz_test[12];
50
51     read( p_ifo->i_fd, psz_test, 12 );
52
53     while( strncmp( psz_test, psz_ifo_start, 12 ) != 0 )
54     {
55         /* The start of ifo file is on a sector boundary */
56         p_ifo->i_pos = lseek( p_ifo->i_fd,
57                               p_ifo->i_pos + DVD_LB_SIZE,
58                               SEEK_SET );
59         read( p_ifo->i_fd, psz_test, 12 );
60     }
61     p_ifo->i_off = p_ifo->i_pos;
62
63 //fprintf( stderr, "VMG Off : %lld\n", (long long)(p_ifo->i_off) );
64
65     return 0;
66 }
67
68 /*****************************************************************************
69  * IfoFindVTS : beginning of vts_*.ifo.
70  *****************************************************************************/
71 static int IfoFindVTS( ifo_t* p_ifo )
72 {
73     char    psz_ifo_start[12] = "DVDVIDEO-VTS";
74     char    psz_test[12];
75
76     read( p_ifo->i_fd, psz_test, 12 );
77
78     while( strncmp( psz_test, psz_ifo_start, 12 ) != 0 )
79     {
80         /* The start of ifo file is on a sector boundary */
81         p_ifo->i_pos = lseek( p_ifo->i_fd,
82                               p_ifo->i_pos + DVD_LB_SIZE,
83                               SEEK_SET );
84         read( p_ifo->i_fd, psz_test, 12 );
85     }
86     p_ifo->i_off = p_ifo->i_pos;
87
88 //fprintf( stderr, "VTS Off : %lld\n", (long long)(p_ifo->i_off) );
89
90     return 0;
91 }
92
93 /*****************************************************************************
94  * IfoInit : Creates an ifo structure and prepares for parsing directly
95  * on DVD device.
96  *****************************************************************************/
97 ifo_t IfoInit( int i_fd )
98 {
99     ifo_t       ifo;
100     
101     /* If we are here the dvd device has already been opened */
102     ifo.i_fd = i_fd;
103     /* No data at the beginning of the disk
104      * 512000 bytes is just another value :) */
105     ifo.i_pos = lseek( ifo.i_fd, 250 *DVD_LB_SIZE, SEEK_SET );
106     /* FIXME : use udf filesystem to find the beginning of the file */
107     IfoFindVMG( &ifo );
108     
109     return ifo;
110 }
111
112 /*****************************************************************************
113  * IfoEnd : Frees all the memory allocated to ifo structures
114  *****************************************************************************/
115 void IfoEnd( ifo_t* p_ifo )
116 {
117     int     i,j;
118
119     /* Free structures from video title sets */
120     for( j=0 ; j<p_ifo->vmg.mat.i_tts_nb ; j++ )
121     {
122         free( p_ifo->p_vts[j].vobu_admap.pi_vobu_ssector );
123         free( p_ifo->p_vts[j].c_adt.p_cell_inf );
124         free( p_ifo->p_vts[j].m_vobu_admap.pi_vobu_ssector );
125         free( p_ifo->p_vts[j].m_c_adt.p_cell_inf );
126         for( i=0 ; i<p_ifo->p_vts[j].tmap_ti.i_nb ; i++ )
127         {
128             free( p_ifo->p_vts[j].tmap_ti.p_tmap[i].pi_sector );
129         }
130         free( p_ifo->p_vts[j].tmap_ti.pi_sbyte );
131         free( p_ifo->p_vts[j].tmap_ti.p_tmap );
132         free( p_ifo->p_vts[j].pgci_ti.p_srp );
133         for( i=0 ; i<p_ifo->p_vts[j].pgci_ut.i_lu_nb ; i++ )
134         {
135             free( p_ifo->p_vts[j].pgci_ut.p_pgci_inf[i].p_srp );
136         }
137         free( p_ifo->p_vts[j].pgci_ut.p_pgci_inf );
138         free( p_ifo->p_vts[j].pgci_ut.p_lu );
139     }
140
141     free( p_ifo->p_vts );
142
143     /* Free structures from video manager */
144     free( p_ifo->vmg.vobu_admap.pi_vobu_ssector );
145     free( p_ifo->vmg.c_adt.p_cell_inf );
146     for( i=0 ; i<p_ifo->vmg.pgci_ut.i_lu_nb ; i++ )
147     {
148         free( p_ifo->vmg.pgci_ut.p_pgci_inf[i].p_srp );
149     }
150     free( p_ifo->vmg.pgci_ut.p_pgci_inf );
151     free( p_ifo->vmg.pgci_ut.p_lu );
152     for( i=1 ; i<=8 ; i++ )
153     {
154         free( p_ifo->vmg.ptl_mait.p_ptl_mask->ppi_ptl_mask[i] );
155     }
156     free( p_ifo->vmg.ptl_mait.p_ptl_desc );
157     free( p_ifo->vmg.ptl_mait.p_ptl_mask );
158     free( p_ifo->vmg.vts_atrt.pi_vts_atrt_sbyte );
159     free( p_ifo->vmg.vts_atrt.p_vts_atrt );
160     free( p_ifo->vmg.pgc.p_cell_pos_inf );
161     free( p_ifo->vmg.pgc.p_cell_play_inf );
162     free( p_ifo->vmg.pgc.prg_map.pi_entry_cell );
163     free( p_ifo->vmg.pgc.com_tab.p_cell_com );
164     free( p_ifo->vmg.pgc.com_tab.p_post_com );
165     free( p_ifo->vmg.pgc.com_tab.p_pre_com );
166
167     return;
168 }
169
170 /*
171  * Macros to process ifo files
172  */
173  
174 #define GET( p_field , i_len )                                              \
175     {                                                                       \
176         read( p_ifo->i_fd , (p_field) , (i_len) );                          \
177 /*fprintf(stderr, "Pos : %lld Val : %llx\n",                                  \
178                                 (long long)(p_ifo->i_pos - i_start),        \
179                                 (long long)*(p_field) );    */                \
180         p_ifo->i_pos += i_len;                                              \
181     }
182
183 #define GETC( p_field )                                                     \
184     {                                                                       \
185         read( p_ifo->i_fd , (p_field) , 1 );                                \
186 /*fprintf(stderr, "Pos : %lld Value : %d\n",                                  \
187                                 (long long)(p_ifo->i_pos - i_start),        \
188                                           *(p_field) );*/                     \
189         p_ifo->i_pos += 1;                                                  \
190     }
191
192 #define GETS( p_field )                                                     \
193     {                                                                       \
194         read( p_ifo->i_fd , (p_field) , 2 );                                \
195         *(p_field) = ntohs( *(p_field) );                                   \
196 /*fprintf(stderr, "Pos : %lld Value : %d\n",                                  \
197                                 (long long)(p_ifo->i_pos - i_start),        \
198                                           *(p_field) );*/                     \
199         p_ifo->i_pos += 2;                                                  \
200     }
201
202 #define GETL( p_field )                                                     \
203     {                                                                       \
204         read( p_ifo->i_fd , (p_field) , 4 );                                \
205         *(p_field) = ntohl( *(p_field) );                                   \
206 /*fprintf(stderr, "Pos : %lld Value : %d\n",                                  \
207                                 (long long)(p_ifo->i_pos - i_start),        \
208                                           *(p_field) );*/                     \
209         p_ifo->i_pos += 4;                                                  \
210     }
211
212 #define GETLL( p_field )                                                    \
213     {                                                                       \
214         read( p_ifo->i_fd , (p_field) , 8 );                                \
215         *(p_field) = ntoh64( *(p_field) );                                  \
216 /*fprintf(stderr, "Pos : %lld Value : %lld\n",                                \
217                                 (long long)(p_ifo->i_pos - i_start),        \
218                                             *(p_field) );*/                   \
219         p_ifo->i_pos += 8;                                                  \
220     }
221
222 #define FLUSH( i_len )                                                      \
223     {                                                                       \
224 /*fprintf(stderr, "Pos : %lld\n", (long long)(p_ifo->i_pos - i_start));*/       \
225         p_ifo->i_pos = lseek( p_ifo->i_fd ,                               \
226                               p_ifo->i_pos + (i_len), SEEK_SET );           \
227     }
228
229 /*
230  * Function common to Video Manager and Video Title set Processing
231  */
232
233 /*****************************************************************************
234  * ReadPGC : Fills the Program Chain structure.
235  *****************************************************************************/
236 #define GETCOMMAND( p_com )                                                 \
237     {                                                                       \
238         read( p_ifo->i_fd , (p_com) , 8 );                                  \
239 /*fprintf(stderr, "Pos : %lld Type : %d direct : %d cmd : %d dircmp : %d cmp : %d subcmd : %d v0 : %d v2 : %d v4 : %d\n",                                  \
240                                 (long long)(p_ifo->i_pos - i_start),        \
241                                 (int)((p_com)->i_type),                     \
242                                 (int)((p_com)->i_direct),                   \
243                                 (int)((p_com)->i_cmd),                      \
244                                 (int)((p_com)->i_dir_cmp),                  \
245                                 (int)((p_com)->i_cmp),                      \
246                                 (int)((p_com)->i_sub_cmd),                  \
247                                 (int)((p_com)->i_v0),                       \
248                                 (int)((p_com)->i_v2),                       \
249                                 (int)((p_com)->i_v4) );           */          \
250         p_ifo->i_pos += 8;                                                  \
251     }
252
253 static pgc_t ReadPGC( ifo_t* p_ifo )
254 {
255     pgc_t   pgc;
256     int     i;
257     off_t   i_start = p_ifo->i_pos;
258
259 //fprintf( stderr, "PGC\n" );
260
261     FLUSH(2);
262     GETC( &pgc.i_prg_nb );
263     GETC( &pgc.i_cell_nb );
264     GETL( &pgc.i_play_time );
265     GETL( &pgc.i_prohibited_user_op );
266     for( i=0 ; i<8 ; i++ )
267     {
268         GETS( &pgc.pi_audio_status[i] );
269     }
270     for( i=0 ; i<32 ; i++ )
271     {
272         GETL( &pgc.pi_subpic_status[i] );
273     }
274     GETS( &pgc.i_next_pgc_nb );
275     GETS( &pgc.i_prev_pgc_nb );
276     GETS( &pgc.i_goup_pgc_nb );
277     GETC( &pgc.i_still_time );
278     GETC( &pgc.i_play_mode );
279     for( i=0 ; i<16 ; i++ )
280     {
281         GETL( &pgc.pi_yuv_color[i] );
282         /* FIXME : We have to erase the extra bit */
283     }
284     GETS( &pgc.i_com_tab_sbyte );
285     GETS( &pgc.i_prg_map_sbyte );
286     GETS( &pgc.i_cell_play_inf_sbyte );
287     GETS( &pgc.i_cell_pos_inf_sbyte );
288
289     /* Parsing of pgc_com_tab_t */
290     if( pgc.i_com_tab_sbyte )
291     {
292         p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
293                             + pgc.i_com_tab_sbyte, SEEK_SET );
294         GETS( &pgc.com_tab.i_pre_com_nb );
295         GETS( &pgc.com_tab.i_post_com_nb );
296         GETS( &pgc.com_tab.i_cell_com_nb );
297         FLUSH( 2 );
298         if( pgc.com_tab.i_pre_com_nb )
299         {
300             pgc.com_tab.p_pre_com =
301                       malloc(pgc.com_tab.i_pre_com_nb *sizeof(ifo_command_t));
302             if( pgc.com_tab.p_pre_com == NULL )
303             {
304                 intf_ErrMsg( "Out of memory" );
305                 p_ifo->b_error = 1;
306                 return pgc;
307             }
308             for( i=0 ; i<pgc.com_tab.i_pre_com_nb ; i++ )
309             {
310                 GETCOMMAND( &pgc.com_tab.p_pre_com[i] );
311             }
312         }
313         if( pgc.com_tab.i_post_com_nb )
314         {
315             pgc.com_tab.p_post_com =
316                       malloc(pgc.com_tab.i_post_com_nb *sizeof(ifo_command_t));
317             if( pgc.com_tab.p_post_com == NULL )
318             {
319                 intf_ErrMsg( "Out of memory" );
320                 p_ifo->b_error = 1;
321                 return pgc;
322             }
323             for( i=0 ; i<pgc.com_tab.i_post_com_nb ; i++ )
324             {
325                 GETCOMMAND( &pgc.com_tab.p_post_com[i] );
326             }
327         }
328         if( pgc.com_tab.i_cell_com_nb )
329         {
330             pgc.com_tab.p_cell_com =
331                       malloc(pgc.com_tab.i_cell_com_nb *sizeof(ifo_command_t));
332             if( pgc.com_tab.p_cell_com == NULL )
333             {
334                 intf_ErrMsg( "Out of memory" );
335                 p_ifo->b_error = 1;
336                 return pgc;
337             }
338             for( i=0 ; i<pgc.com_tab.i_cell_com_nb ; i++ )
339             {
340                 GETCOMMAND( &pgc.com_tab.p_cell_com[i] );
341             }
342         }
343     }
344     /* Parsing of pgc_prg_map_t */
345     if( pgc.i_prg_map_sbyte )
346     {
347         p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
348                             + pgc.i_prg_map_sbyte, SEEK_SET );
349         pgc.prg_map.pi_entry_cell = malloc( pgc.i_prg_nb *sizeof(u8) );
350         if( pgc.prg_map.pi_entry_cell == NULL )
351         {
352             intf_ErrMsg( "Out of memory" );
353             p_ifo->b_error = 1;
354             return pgc;
355         }
356         GET( pgc.prg_map.pi_entry_cell, pgc.i_prg_nb );
357         /* FIXME : check endianness here */
358     }
359     /* Parsing of cell_play_inf_t */
360     if( pgc.i_cell_play_inf_sbyte )
361     {
362         p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
363                             + pgc.i_cell_play_inf_sbyte, SEEK_SET );
364         pgc.p_cell_play_inf = malloc( pgc.i_cell_nb *sizeof(cell_play_inf_t) );
365         if( pgc.p_cell_play_inf == NULL )
366         {
367             intf_ErrMsg( "Out of memory" );
368             p_ifo->b_error = 1;
369             return pgc;
370         }
371         for( i=0 ; i<pgc.i_cell_nb ; i++ )
372         {
373             GETS( &pgc.p_cell_play_inf[i].i_cat );
374             GETC( &pgc.p_cell_play_inf[i].i_still_time );
375             GETC( &pgc.p_cell_play_inf[i].i_com_nb );
376             GETL( &pgc.p_cell_play_inf[i].i_play_time );
377             GETL( &pgc.p_cell_play_inf[i].i_entry_sector );
378             GETL( &pgc.p_cell_play_inf[i].i_first_ilvu_vobu_esector );
379             GETL( &pgc.p_cell_play_inf[i].i_lvobu_ssector );
380             GETL( &pgc.p_cell_play_inf[i].i_lsector );
381         }
382     }
383     /* Parsing of cell_pos_inf_map */
384     if( pgc.i_cell_pos_inf_sbyte )
385     {
386         p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
387                             + pgc.i_cell_pos_inf_sbyte, SEEK_SET );
388         pgc.p_cell_pos_inf = malloc( pgc.i_cell_nb *sizeof(cell_pos_inf_t) );
389         if( pgc.p_cell_play_inf == NULL )
390         {
391             intf_ErrMsg( "Out of memory" );
392             p_ifo->b_error = 1;
393             return pgc;
394         }
395         for( i=0 ; i<pgc.i_cell_nb ; i++ )
396         {
397             GETS( &pgc.p_cell_pos_inf[i].i_vob_id );
398             FLUSH( 1 );
399             GETC( &pgc.p_cell_pos_inf[i].i_cell_id );
400         }
401     } 
402
403     return pgc;
404 }
405
406 /*****************************************************************************
407  * ReadUnit : Fills Menu Language Unit Table/ PGC Info Table
408  *****************************************************************************/
409 static pgci_inf_t ReadUnit( ifo_t* p_ifo )
410 {
411     pgci_inf_t      inf;
412     int             i;
413     off_t           i_start = p_ifo->i_pos;
414
415 //fprintf( stderr, "Unit\n" );
416
417     GETS( &inf.i_srp_nb );
418     FLUSH( 2 );
419     GETL( &inf.i_lu_ebyte );
420     inf.p_srp = malloc( inf.i_srp_nb *sizeof(pgci_srp_t) );
421     if( inf.p_srp == NULL )
422     {
423         intf_ErrMsg( "Out of memory" );
424         p_ifo->b_error = 1;
425         return inf;
426     }
427     for( i=0 ; i<inf.i_srp_nb ; i++ )
428     {
429         GETC( &inf.p_srp[i].i_pgc_cat_mask );
430         GETC( &inf.p_srp[i].i_pgc_cat );
431         GETS( &inf.p_srp[i].i_par_mask );
432         GETL( &inf.p_srp[i].i_pgci_sbyte );
433     }
434     for( i=0 ; i<inf.i_srp_nb ; i++ )
435     {
436         p_ifo->i_pos = lseek( p_ifo->i_fd,
437                          i_start + inf.p_srp[i].i_pgci_sbyte,
438                          SEEK_SET );
439         inf.p_srp[i].pgc = ReadPGC( p_ifo );
440     }
441
442     return inf;
443 }
444
445 /*****************************************************************************
446  * ReadUnitTable : Fills the PGCI Unit structure.
447  *****************************************************************************/
448 static pgci_ut_t ReadUnitTable( ifo_t* p_ifo )
449 {
450     pgci_ut_t       pgci;
451     int             i;
452     off_t           i_start = p_ifo->i_pos;
453
454 //fprintf( stderr, "Unit Table\n" );
455
456     GETS( &pgci.i_lu_nb );
457     FLUSH( 2 );
458     GETL( &pgci.i_ebyte );
459     pgci.p_lu = malloc( pgci.i_lu_nb *sizeof(pgci_lu_t) );
460     if( pgci.p_lu == NULL )
461     {
462         intf_ErrMsg( "Out of memory" );
463         p_ifo->b_error = 1;
464         return pgci;
465     }
466     for( i=0 ; i<pgci.i_lu_nb ; i++ )
467     {
468         GET( pgci.p_lu[i].ps_lang_code, 2 );
469         FLUSH( 1 );
470         GETC( &pgci.p_lu[i].i_existence_mask );
471         GETL( &pgci.p_lu[i].i_lu_sbyte );
472     }
473     pgci.p_pgci_inf = malloc( pgci.i_lu_nb *sizeof(pgci_inf_t) );
474     if( pgci.p_pgci_inf == NULL )
475     {
476         intf_ErrMsg( "Out of memory" );
477         p_ifo->b_error = 1;
478         return pgci;
479     }
480     for( i=0 ; i<pgci.i_lu_nb ; i++ )
481     {
482         p_ifo->i_pos = lseek( p_ifo->i_fd, i_start +
483                                 pgci.p_lu[i].i_lu_sbyte,
484                                 SEEK_SET );
485         pgci.p_pgci_inf[i] = ReadUnit( p_ifo );
486     }
487
488     return pgci;
489 }
490
491 /*****************************************************************************
492  * ReadCellInf : Fills the Cell Information structure.
493  *****************************************************************************/
494 static c_adt_t ReadCellInf( ifo_t* p_ifo )
495 {
496     c_adt_t         c_adt;
497     int             i, i_max;
498     off_t           i_start = p_ifo->i_pos;
499
500 //fprintf( stderr, "CELL ADD\n" );
501
502     GETS( &c_adt.i_vob_nb );
503     FLUSH( 2 );
504     GETL( &c_adt.i_ebyte );
505     i_max = ( i_start + c_adt.i_ebyte + 1 - p_ifo->i_pos ) / sizeof(cell_inf_t);
506     c_adt.p_cell_inf = malloc( i_max *sizeof(cell_inf_t) );
507     if( c_adt.p_cell_inf == NULL )
508     {
509         intf_ErrMsg( "Out of memory" );
510         p_ifo->b_error = 1;
511         return c_adt;
512     }
513     for( i=0 ; i<i_max ; i++ )
514     {
515         GETS( &c_adt.p_cell_inf[i].i_vob_id );
516         GETC( &c_adt.p_cell_inf[i].i_cell_id );
517         FLUSH( 1 );
518         GETL( &c_adt.p_cell_inf[i].i_ssector );
519         GETL( &c_adt.p_cell_inf[i].i_esector );
520     }
521     
522     return c_adt;
523 }
524
525 /*****************************************************************************
526  * ReadMap : Fills the VOBU Map structure.
527  *****************************************************************************/
528 static vobu_admap_t ReadMap( ifo_t* p_ifo )
529 {
530     vobu_admap_t        map;
531     int                 i, i_max;
532     off_t               i_start = p_ifo->i_pos;
533     
534 //fprintf( stderr, "VOBU ADMAP\n" );
535
536     GETL( &map.i_ebyte );
537     i_max = ( i_start + map.i_ebyte + 1 - p_ifo->i_pos ) / sizeof(u32);
538     map.pi_vobu_ssector = malloc( i_max *sizeof(u32) );
539     for( i=0 ; i<i_max ; i++ )
540     {
541         GETL( &map.pi_vobu_ssector[i] );
542     }
543
544     return map;
545 }
546  
547 /*
548  * Video Manager Information Processing.
549  * This is what is contained in video_ts.ifo.
550  */
551
552 /*****************************************************************************
553  * ReadVMGInfMat : Fills the Management Information structure.
554  *****************************************************************************/
555 static vmgi_mat_t ReadVMGInfMat( ifo_t* p_ifo )
556 {
557     vmgi_mat_t  mat;
558     int         i;
559 //    off_t     i_start = p_ifo->i_pos;
560
561 //fprintf( stderr, "VMGI\n" );
562
563     GET( mat.psz_id , 12 );
564     mat.psz_id[12] = '\0';
565     GETL( &mat.i_lsector );
566     FLUSH( 12 );
567     GETL( &mat.i_i_lsector );
568     FLUSH( 1 );
569     GETC( &mat.i_spec_ver );
570     GETL( &mat.i_cat );
571     GETS( &mat.i_vol_nb );
572     GETS( &mat.i_vol );
573     GETC( &mat.i_disc_side );
574     FLUSH( 19 );
575     GETS( &mat.i_tts_nb );
576     GET( mat.ps_provider_id, 32 );
577     GETLL( &mat.i_pos_code );
578     FLUSH( 24 );
579     GETL( &mat.i_i_mat_ebyte );
580     GETL( &mat.i_fp_pgc_sbyte );
581     FLUSH( 56 );
582     GETL( &mat.i_vobs_ssector );
583     GETL( &mat.i_ptt_srpt_ssector );
584     GETL( &mat.i_pgci_ut_ssector );
585     GETL( &mat.i_ptl_mait_ssector );
586     GETL( &mat.i_vts_atrt_ssector );
587     GETL( &mat.i_txtdt_mg_ssector );
588     GETL( &mat.i_c_adt_ssector );
589     GETL( &mat.i_vobu_admap_ssector );
590     FLUSH( 32 );
591     GETS( &mat.i_video_atrt );
592     FLUSH( 1 );
593     GETC( &mat.i_audio_nb );
594 //fprintf( stderr, "vmgi audio nb : %d\n", mat.i_audio_nb );
595     for( i=0 ; i < 8 ; i++ )
596     {
597         GETLL( &mat.pi_audio_atrt[i] );
598     }
599     FLUSH( 17 );
600     GETC( &mat.i_subpic_nb );
601 //fprintf( stderr, "vmgi subpic nb : %d\n", mat.i_subpic_nb );
602     for( i=0 ; i < mat.i_subpic_nb ; i++ )
603     {
604         GET( &mat.pi_subpic_atrt[i], 6 );
605         /* FIXME : take care of endianness */
606     }
607
608     return mat;
609 }
610
611 /*****************************************************************************
612  * ReadVMGTitlePointer : Fills the Part Of Title Search Pointer structure.
613  *****************************************************************************/
614 static vmg_ptt_srpt_t ReadVMGTitlePointer( ifo_t* p_ifo )
615 {
616     vmg_ptt_srpt_t  ptr;
617     int             i;
618 //    off_t           i_start = p_ifo->i_pos;
619
620 //fprintf( stderr, "PTR\n" );
621
622     GETS( &ptr.i_ttu_nb );
623     FLUSH( 2 );
624     GETL( &ptr.i_ebyte );
625     /* Parsing of tts */
626     ptr.p_tts = malloc( ptr.i_ttu_nb *sizeof(tts_t) );
627     if( ptr.p_tts == NULL )
628     {
629         intf_ErrMsg( "Out of memory" );
630         p_ifo->b_error = 1;
631         return ptr;
632     }
633     for( i=0 ; i<ptr.i_ttu_nb ; i++ )
634     {
635         GETC( &ptr.p_tts[i].i_play_type );
636         GETC( &ptr.p_tts[i].i_angle_nb );
637         GETS( &ptr.p_tts[i].i_ptt_nb );
638         GETS( &ptr.p_tts[i].i_parental_id );
639         GETC( &ptr.p_tts[i].i_tts_nb );
640         GETC( &ptr.p_tts[i].i_vts_ttn );
641         GETL( &ptr.p_tts[i].i_ssector );
642     }
643
644     return ptr;
645 }
646
647 /*****************************************************************************
648  * ReadParentalInf : Fills the Parental Management structure.
649  *****************************************************************************/
650 static vmg_ptl_mait_t ReadParentalInf( ifo_t* p_ifo )
651 {
652     vmg_ptl_mait_t  par;
653     int             i, j, k;
654     off_t           i_start = p_ifo->i_pos;
655
656 //fprintf( stderr, "PTL\n" );
657
658     GETS( &par.i_country_nb );
659     GETS( &par.i_vts_nb );
660     GETL( &par.i_ebyte );
661     par.p_ptl_desc = malloc( par.i_country_nb *sizeof(vmg_ptl_mai_desc_t) );
662     if( par.p_ptl_desc == NULL )
663     {
664         intf_ErrMsg( "Out of memory" );
665         p_ifo->b_error = 1;
666         return par;
667     }
668     for( i=0 ; i<par.i_country_nb ; i++ )
669     {
670         GET( par.p_ptl_desc[i].ps_country_code, 2 );
671         FLUSH( 2 );
672         GETS( &par.p_ptl_desc[i].i_ptl_mai_sbyte );
673         FLUSH( 2 );
674     }
675     par.p_ptl_mask = malloc( par.i_country_nb *sizeof(vmg_ptl_mask_t) );
676     if( par.p_ptl_mask == NULL )
677     {
678         intf_ErrMsg( "Out of memory" );
679         p_ifo->b_error = 1;
680         return par;
681     }
682     for( i=0 ; i<par.i_country_nb ; i++ )
683     {
684         p_ifo->i_pos = lseek( p_ifo->i_fd, i_start +
685                          par.p_ptl_desc[i].i_ptl_mai_sbyte, SEEK_SET );
686         for( j=1 ; j<=8 ; j++ )
687         {
688             par.p_ptl_mask[i].ppi_ptl_mask[j] =
689                                     malloc( par.i_vts_nb *sizeof(u16) );
690             if( par.p_ptl_mask[i].ppi_ptl_mask[j] == NULL )
691             {
692                 intf_ErrMsg( "Out of memory" );
693                 p_ifo->b_error = 1;
694                 return par;
695             }        
696             for( k=0 ; k<par.i_vts_nb ; k++ )
697             {
698                 GETS( &par.p_ptl_mask[i].ppi_ptl_mask[j][k] );
699             }
700         }
701     }
702
703     return par;
704 }
705
706 /*****************************************************************************
707  * ReadVTSAttr : Fills the structure about VTS attributes.
708  *****************************************************************************/
709 static vmg_vts_atrt_t ReadVTSAttr( ifo_t* p_ifo )
710 {
711     vmg_vts_atrt_t  atrt;
712     int             i, j;
713     off_t           i_start = p_ifo->i_pos;
714
715 //fprintf( stderr, "VTS ATTR\n" );
716
717     GETS( &atrt.i_vts_nb );
718     FLUSH( 2 );
719     GETL( &atrt.i_ebyte );
720     atrt.pi_vts_atrt_sbyte = malloc( atrt.i_vts_nb *sizeof(u32) );
721     if( atrt.pi_vts_atrt_sbyte == NULL )
722     {
723         intf_ErrMsg( "Out of memory" );
724         p_ifo->b_error = 1;
725         return atrt;
726     }
727     for( i=0 ; i<atrt.i_vts_nb ; i++ )
728     {
729         GETL( &atrt.pi_vts_atrt_sbyte[i] );
730     }
731     atrt.p_vts_atrt = malloc( atrt.i_vts_nb *sizeof(vts_atrt_t) );
732     if( atrt.p_vts_atrt == NULL )
733     {
734         intf_ErrMsg( "Out of memory" );
735         p_ifo->b_error = 1;
736         return atrt;
737     }
738     for( i=0 ; i<atrt.i_vts_nb ; i++ )
739     {
740         p_ifo->i_pos = lseek( p_ifo->i_fd, i_start +
741                                 atrt.pi_vts_atrt_sbyte[i],
742                                 SEEK_SET );
743         GETL( &atrt.p_vts_atrt[i].i_ebyte );
744         GETL( &atrt.p_vts_atrt[i].i_cat_app_type );
745         GETS( &atrt.p_vts_atrt[i].i_vtsm_video_atrt );
746         FLUSH( 1 );
747         GETC( &atrt.p_vts_atrt[i].i_vtsm_audio_nb );
748 //fprintf( stderr, "m audio nb : %d\n", atrt.p_vts_atrt[i].i_vtsm_audio_nb );
749         for( j=0 ; j<8 ; j++ )
750         {
751             GETLL( &atrt.p_vts_atrt[i].pi_vtsm_audio_atrt[j] );
752         }
753         FLUSH( 17 );
754         GETC( &atrt.p_vts_atrt[i].i_vtsm_subpic_nb );
755 //fprintf( stderr, "m subp nb : %d\n", atrt.p_vts_atrt[i].i_vtsm_subpic_nb );
756         for( j=0 ; j<28 ; j++ )
757         {
758             GET( &atrt.p_vts_atrt[i].pi_vtsm_subpic_atrt[j], 6 );
759             /* FIXME : Fix endianness issue here */
760         }
761         FLUSH( 2 );
762         GETS( &atrt.p_vts_atrt[i].i_vtstt_video_atrt );
763         FLUSH( 1 );
764         GETL( &atrt.p_vts_atrt[i].i_vtstt_audio_nb );
765 //fprintf( stderr, "tt audio nb : %d\n", atrt.p_vts_atrt[i].i_vtstt_audio_nb );
766         for( j=0 ; j<8 ; j++ )
767         {
768             GETLL( &atrt.p_vts_atrt[i].pi_vtstt_audio_atrt[j] );
769         }
770         FLUSH( 17 );
771         GETC( &atrt.p_vts_atrt[i].i_vtstt_subpic_nb );
772 //fprintf( stderr, "tt subp nb : %d\n", atrt.p_vts_atrt[i].i_vtstt_subpic_nb );
773         for( j=0 ; j<28/*atrt.p_vts_atrt[i].i_vtstt_subpic_nb*/ ; j++ )
774         {
775             GET( &atrt.p_vts_atrt[i].pi_vtstt_subpic_atrt[j], 6 );
776             /* FIXME : Fix endianness issue here */
777         }
778     }
779
780     return atrt;
781 }
782                            
783 /*****************************************************************************
784  * ReadVMG : Parse video_ts.ifo file to fill the Video Manager structure.
785  *****************************************************************************/
786 static vmg_t ReadVMG( ifo_t* p_ifo )
787 {
788     vmg_t       vmg;
789
790     p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off, SEEK_SET);
791     vmg.mat = ReadVMGInfMat( p_ifo );
792     p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off + 
793                               vmg.mat.i_fp_pgc_sbyte, SEEK_SET );
794     vmg.pgc = ReadPGC( p_ifo );
795     if( vmg.mat.i_ptt_srpt_ssector )
796     {
797         p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
798                         vmg.mat.i_ptt_srpt_ssector *DVD_LB_SIZE,
799                         SEEK_SET );
800         vmg.ptt_srpt = ReadVMGTitlePointer( p_ifo );
801     }
802     if( vmg.mat.i_pgci_ut_ssector )
803     {
804         p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
805                         vmg.mat.i_pgci_ut_ssector *DVD_LB_SIZE,
806                         SEEK_SET );
807         vmg.pgci_ut = ReadUnitTable( p_ifo );
808     }
809     if( vmg.mat.i_ptl_mait_ssector )
810     {
811         p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
812                         vmg.mat.i_ptl_mait_ssector *DVD_LB_SIZE,
813                         SEEK_SET );
814         vmg.ptl_mait = ReadParentalInf( p_ifo );
815     }
816     if( vmg.mat.i_vts_atrt_ssector )
817     {
818         p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
819                         vmg.mat.i_vts_atrt_ssector *DVD_LB_SIZE,
820                         SEEK_SET );
821         vmg.vts_atrt = ReadVTSAttr( p_ifo );
822     }
823     if( vmg.mat.i_c_adt_ssector )
824     {
825         p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
826                         vmg.mat.i_c_adt_ssector *DVD_LB_SIZE,
827                         SEEK_SET );
828         vmg.c_adt = ReadCellInf( p_ifo );
829     }
830     if( vmg.mat.i_vobu_admap_ssector )
831     {
832         p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
833                         vmg.mat.i_vobu_admap_ssector *DVD_LB_SIZE,
834                         SEEK_SET );
835         vmg.vobu_admap = ReadMap( p_ifo );
836     }
837     return vmg;
838 }
839
840 /*
841  * Video Title Set Information Processing.
842  * This is what is contained in vts_*.ifo.
843  */
844
845 /*****************************************************************************
846  * ReadVTSInfMat : Fills the Title Set Information structure.
847  *****************************************************************************/
848 static vtsi_mat_t ReadVTSInfMat( ifo_t* p_ifo )
849 {
850     vtsi_mat_t  mat;
851     int         i;
852 //    off_t       i_start = p_ifo->i_pos;
853
854 //fprintf( stderr, "VTSI\n" );
855
856     GET( mat.psz_id , 12 );
857     mat.psz_id[12] = '\0';
858     GETL( &mat.i_lsector );
859     FLUSH( 12 );
860     GETL( &mat.i_i_lsector );
861     FLUSH( 1 );
862     GETC( &mat.i_spec_ver );
863     GETL( &mat.i_cat );
864     FLUSH( 90 );
865     GETL( &mat.i_mat_ebyte );
866     FLUSH( 60 );
867     GETL( &mat.i_m_vobs_ssector );
868     GETL( &mat.i_tt_vobs_ssector );
869     GETL( &mat.i_ptt_srpt_ssector );
870     GETL( &mat.i_pgcit_ssector );
871     GETL( &mat.i_m_pgci_ut_ssector );
872     GETL( &mat.i_tmap_ti_ssector );
873     GETL( &mat.i_m_c_adt_ssector );
874     GETL( &mat.i_m_vobu_admap_ssector );
875     GETL( &mat.i_c_adt_ssector );
876     GETL( &mat.i_vobu_admap_ssector );
877     FLUSH( 24 );
878     GETS( &mat.i_m_video_atrt );
879     FLUSH( 1 );
880     GETC( &mat.i_m_audio_nb );
881     for( i=0 ; i<8 ; i++ )
882     {
883         GETLL( &mat.pi_m_audio_atrt[i] );
884     }
885     FLUSH( 17 );
886     GETC( &mat.i_m_subpic_nb );
887     for( i=0 ; i<28 ; i++ )
888     {
889         GET( &mat.pi_m_subpic_atrt[i], 6 );
890         /* FIXME : take care of endianness */
891     }
892     FLUSH( 2 );
893     GETS( &mat.i_video_atrt );
894     FLUSH( 1 );
895     GETC( &mat.i_audio_nb );
896 //fprintf( stderr, "vtsi audio nb : %d\n", mat.i_audio_nb );
897     for( i=0 ; i<8 ; i++ )
898     {
899         GETLL( &mat.pi_audio_atrt[i] );
900     }
901     FLUSH( 17 );
902     GETC( &mat.i_subpic_nb );
903 //fprintf( stderr, "vtsi subpic nb : %d\n", mat.i_subpic_nb );
904     for( i=0 ; i<mat.i_subpic_nb ; i++ )
905     {
906         GET( &mat.pi_subpic_atrt[i], 6 );
907         /* FIXME : take care of endianness */
908     }
909
910     return mat;
911 }
912
913 /*****************************************************************************
914  * ReadVTSTitlePointer : Fills the Part Of Title Search Pointer structure.
915  *****************************************************************************/
916 static vts_ptt_srpt_t ReadVTSTitlePointer( ifo_t* p_ifo )
917 {
918     vts_ptt_srpt_t  ptr;
919     int             i;
920     off_t           i_start = p_ifo->i_pos;
921
922 //fprintf( stderr, "PTR\n" );
923
924     GETS( &ptr.i_ttu_nb );
925     FLUSH( 2 );
926     GETL( &ptr.i_ebyte );
927     ptr.pi_ttu_sbyte = malloc( ptr.i_ttu_nb *sizeof(u32) );
928     if( ptr.pi_ttu_sbyte == NULL )
929     {
930         intf_ErrMsg( "Out of memory" );
931         p_ifo->b_error = 1;
932         return ptr;
933     }
934     for( i=0 ; i<ptr.i_ttu_nb ; i++ )
935     {
936         GETL( &ptr.pi_ttu_sbyte[i] );
937     }
938     /* Parsing of tts */
939     ptr.p_ttu = malloc( ptr.i_ttu_nb *sizeof(ttu_t) );
940     if( ptr.p_ttu == 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         p_ifo->i_pos = lseek( p_ifo->i_fd, i_start +
949                         ptr.pi_ttu_sbyte[i], SEEK_SET );
950         GETS( &ptr.p_ttu[i].i_pgc_nb );
951         GETS( &ptr.p_ttu[i].i_prg_nb );
952     }
953
954     return ptr;
955 }
956
957 /*****************************************************************************
958  * ReadVTSTimeMap : Fills the time map table
959  *****************************************************************************/
960 static vts_tmap_ti_t ReadVTSTimeMap( ifo_t* p_ifo )
961 {
962     vts_tmap_ti_t   tmap;
963     int             i,j;
964 //    off_t           i_start = p_ifo->i_pos;
965
966 //fprintf( stderr, "TMAP\n" );
967
968     GETS( &tmap.i_nb );
969     FLUSH( 2 );
970     GETL( &tmap.i_ebyte );
971     tmap.pi_sbyte = malloc( tmap.i_nb *sizeof(u32) );
972     if( tmap.pi_sbyte == NULL )
973     {
974         intf_ErrMsg( "Out of memory" );
975         p_ifo->b_error = 1;
976         return tmap;
977     }
978     for( i=0 ; i<tmap.i_nb ; i++ )
979     {    
980         GETL( &tmap.pi_sbyte[i] );
981     }
982     tmap.p_tmap = malloc( tmap.i_nb *sizeof(tmap_t) );
983     if( tmap.p_tmap == NULL )
984     {
985         intf_ErrMsg( "Out of memory" );
986         p_ifo->b_error = 1;
987         return tmap;
988     }
989     for( i=0 ; i<tmap.i_nb ; i++ )
990     {    
991         GETC( &tmap.p_tmap[i].i_time_unit );
992         FLUSH( 1 );
993         GETS( &tmap.p_tmap[i].i_entry_nb );
994         tmap.p_tmap[i].pi_sector =
995                     malloc( tmap.p_tmap[i].i_entry_nb *sizeof(u32) );
996         if( tmap.p_tmap[i].pi_sector == NULL )
997         {
998             intf_ErrMsg( "Out of memory" );
999             p_ifo->b_error = 1;
1000             return tmap;
1001         }
1002         for( j=0 ; j<tmap.p_tmap[i].i_entry_nb ; j++ )
1003         {
1004             GETL( &tmap.p_tmap[i].pi_sector[j] );
1005         }
1006     }
1007
1008     return tmap;
1009 }
1010     
1011
1012 /*****************************************************************************
1013  * ReadVTS : Parse vts*.ifo files to fill the Video Title Set structure.
1014  *****************************************************************************/
1015 static vts_t ReadVTS( ifo_t* p_ifo )
1016 {
1017     vts_t       vts;
1018
1019     vts.i_pos = p_ifo->i_pos;
1020
1021     vts.mat = ReadVTSInfMat( p_ifo );
1022     if( vts.mat.i_ptt_srpt_ssector )
1023     {
1024         p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
1025                         vts.mat.i_ptt_srpt_ssector *DVD_LB_SIZE,
1026                         SEEK_SET );
1027         vts.ptt_srpt = ReadVTSTitlePointer( p_ifo );
1028     }
1029     if( vts.mat.i_m_pgci_ut_ssector )
1030     {
1031         p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
1032                         vts.mat.i_m_pgci_ut_ssector *DVD_LB_SIZE,
1033                         SEEK_SET );
1034         vts.pgci_ut = ReadUnitTable( p_ifo );
1035     }
1036     if( vts.mat.i_pgcit_ssector )
1037     {
1038         p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
1039                         vts.mat.i_pgcit_ssector *DVD_LB_SIZE,
1040                         SEEK_SET );
1041         vts.pgci_ti = ReadUnit( p_ifo );
1042     }
1043     if( vts.mat.i_tmap_ti_ssector )
1044     {
1045         p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
1046                         vts.mat.i_tmap_ti_ssector *DVD_LB_SIZE,
1047                         SEEK_SET );
1048         vts.tmap_ti = ReadVTSTimeMap( p_ifo );
1049     }
1050     if( vts.mat.i_m_c_adt_ssector )
1051     {
1052         p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
1053                         vts.mat.i_m_c_adt_ssector *DVD_LB_SIZE,
1054                         SEEK_SET );
1055         vts.m_c_adt = ReadCellInf( p_ifo );
1056     }
1057     if( vts.mat.i_m_vobu_admap_ssector )
1058     {
1059         p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
1060                         vts.mat.i_m_vobu_admap_ssector *DVD_LB_SIZE,
1061                         SEEK_SET );
1062         vts.m_vobu_admap = ReadMap( p_ifo );
1063     }
1064     if( vts.mat.i_c_adt_ssector )
1065     {
1066         p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
1067                         vts.mat.i_c_adt_ssector *DVD_LB_SIZE,
1068                         SEEK_SET );
1069         vts.c_adt = ReadCellInf( p_ifo );
1070     }
1071     if( vts.mat.i_vobu_admap_ssector )
1072     {
1073         p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
1074                         vts.mat.i_vobu_admap_ssector *DVD_LB_SIZE,
1075                         SEEK_SET );
1076         vts.vobu_admap = ReadMap( p_ifo );
1077     }
1078
1079     return vts;
1080 }
1081
1082 /*
1083  * DVD Information Management
1084  */
1085
1086 /*****************************************************************************
1087  * IfoRead : Function that fills structure and calls specified functions
1088  * to do it.
1089  *****************************************************************************/
1090 void IfoRead( ifo_t* p_ifo )
1091 {
1092     int     i;
1093     off_t   i_off;
1094
1095     p_ifo->vmg = ReadVMG( p_ifo );
1096     p_ifo->p_vts = malloc( p_ifo->vmg.mat.i_tts_nb *sizeof(vts_t) );
1097     if( p_ifo->p_vts == NULL )
1098     {
1099         intf_ErrMsg( "Out of memory" );
1100         p_ifo->b_error = 1;
1101         return;
1102     }
1103     for( i=0 ; i<1/*p_ifo->vmg.mat.i_tts_nb*/ ; i++ )
1104     {
1105
1106         intf_WarnMsg( 3, "######### VTS %d #############\n", i+1 );
1107
1108         i_off = p_ifo->vmg.ptt_srpt.p_tts[i].i_ssector *DVD_LB_SIZE;
1109         p_ifo->i_pos = lseek( p_ifo->i_fd, i_off, SEEK_SET );
1110         /* FIXME : use udf filesystem to avoid this */
1111         IfoFindVTS( p_ifo );
1112         p_ifo->p_vts[i] = ReadVTS( p_ifo );
1113     }
1114     return; 
1115 }
1116
1117 /*
1118  * IFO virtual machine : a set of commands that give the behaviour of the dvd
1119  */
1120 #if 0
1121 /*****************************************************************************
1122  * CommandRead : translates the command strings in ifo into command
1123  * structures.
1124  *****************************************************************************/
1125 void CommandRead( ifo_command_t com )
1126 {
1127     u8*     pi_code = (u8*)(&com);
1128
1129     switch( com.i_type )
1130     {
1131         case 0:                                     /* Goto */
1132             if( !pi_code[1] )
1133             {
1134                 fprintf( stderr, "NOP\n" );
1135             }
1136             else if( cmd.i_cmp )
1137             {
1138                 
1139             }
1140             break;
1141         case 1:                                     /* Lnk */
1142             break;
1143         case 2:                                     /* SetSystem */
1144             break;
1145         case 3:                                     /* Set */
1146             break;
1147         case 4:                                     /* */
1148             break;
1149         case 5:                                     /* */
1150             break;
1151         case 6:                                     /* */
1152             break;
1153         default:
1154             fprintf( stderr, "Unknown Command\n" );
1155             break;
1156     }
1157
1158     return;
1159 }
1160
1161 /*****************************************************************************
1162  * IfoGoto
1163  *****************************************************************************/
1164 static void IfoGoto( ifo_command_t cmd )
1165 {
1166     
1167
1168     return;
1169 }
1170
1171 /*****************************************************************************
1172  * IfoLnk
1173  *****************************************************************************/
1174 static void IfoLnk( ifo_t* p_ifo )
1175 {
1176     return;
1177 }
1178
1179 /*****************************************************************************
1180  * IfoJmp
1181  *****************************************************************************/
1182 static void IfoJmp( ifo_t* p_ifo )
1183 {
1184     return;
1185 }
1186 #endif