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