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