]> git.sesse.net Git - vlc/blob - modules/access/dvd/ifo.c
* include/vlc_common.h:
[vlc] / modules / access / dvd / ifo.c
1 /*****************************************************************************
2  * ifo.c: Functions for ifo parsing
3  *****************************************************************************
4  * Copyright (C) 1999-2001 VideoLAN
5  * $Id: ifo.c,v 1.6 2003/10/25 00:49:13 sam Exp $
6  *
7  * Authors: Stéphane Borel <stef@via.ecp.fr>
8  *          German Tischler <tanis@gaspode.franken.de>
9  *
10  * based on:
11  *  - libifo by Thomas Mirlacher <dent@cosy.sbg.ac.at>
12  *  - IFO structure documentation by Thomas Mirlacher, Björn Englund,
13  *  Håkan Hjort
14  *
15  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 2 of the License, or
18  * (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
28  *****************************************************************************/
29
30 /*****************************************************************************
31  * Preamble
32  *****************************************************************************/
33 #include <stdio.h>
34 #include <stdlib.h>
35
36 #include <vlc/vlc.h>
37
38 #ifdef HAVE_UNISTD_H
39 #   include <unistd.h>
40 #endif
41
42 #include <string.h>
43 #include <fcntl.h>
44
45 #ifdef GOD_DAMN_DMCA
46 #   include "dvdcss.h"
47 #else
48 #   include <dvdcss/dvdcss.h>
49 #endif
50
51 #include "dvd.h"
52 #include "ifo.h"
53 #include "udf.h"
54
55 /*****************************************************************************
56  * Local prototypes
57  *****************************************************************************/
58 void            CommandRead     ( command_desc_t );
59 static int      ReadTitle       ( ifo_t * , title_t *, int, int );
60 static int      FreeTitle       ( title_t * );
61 static int      ReadUnitInf     ( ifo_t * , unit_inf_t *, int, int );
62 static int      FreeUnitInf     ( unit_inf_t * );
63 static int      ReadTitleUnit   ( ifo_t * , title_unit_t *, int );
64 static int      FreeTitleUnit   ( title_unit_t * );
65 static int      ReadVobuMap     ( ifo_t * , vobu_map_t *, int );
66 static int      FreeVobuMap     ( vobu_map_t * );
67 static int      ReadCellInf     ( ifo_t * , cell_inf_t *, int );
68 static int      FreeCellInf     ( cell_inf_t * );
69 static int      FreeTitleSet    ( vts_t * );
70
71 static uint8_t* FillBuffer      ( ifo_t *, uint8_t *, int );
72 static uint8_t  ReadByte        ( ifo_t *, uint8_t *, uint8_t ** );
73 static void     ReadBytes       ( ifo_t *, uint8_t *, uint8_t **, uint8_t *, int );
74 static void     DumpBytes       ( ifo_t *, uint8_t *, uint8_t **, int );
75 static uint16_t ReadWord        ( ifo_t *, uint8_t *, uint8_t ** );
76 static uint32_t ReadDouble      ( ifo_t *, uint8_t *, uint8_t ** );
77 static uint64_t ReadQuad        ( ifo_t *, uint8_t *, uint8_t ** );
78
79 /*
80  * IFO Management.
81  */
82
83 /*****************************************************************************
84  * IfoCreate : Creates an ifo structure and prepares for parsing directly
85  *             on DVD device
86  *****************************************************************************/
87 int IfoCreate( thread_dvd_data_t * p_dvd )
88 {
89     p_dvd->p_ifo = malloc( sizeof(ifo_t) );
90     if( p_dvd->p_ifo == NULL )
91     {
92         return -1;
93     }
94     /* memset to 0 to avoid crashing on deallocation later */
95     memset( p_dvd->p_ifo, 0, sizeof(ifo_t) );
96
97     /* if we are here the dvd device has already been opened */
98     p_dvd->p_ifo->dvdhandle = p_dvd->dvdhandle;
99
100     return 0;
101 }
102
103 /*****************************************************************************
104  * IfoInit : Reads information from the management table.
105  *****************************************************************************/
106 int IfoInit( ifo_t * p_ifo )
107 {
108     uint8_t             p_buf[DVD_LB_SIZE];
109     uint8_t *           p_tmp;
110     uint64_t            i_temp;
111     int                 i, j, k;
112     int                 i_start;
113
114     /* find the start sector of video information on the dvd */
115     p_ifo->i_start = DVDUDFFindFile( p_ifo->dvdhandle, "/VIDEO_TS/VIDEO_TS.IFO" );
116     if( !p_ifo->i_start ) return -1;
117
118     p_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_start );
119     /*i_start = p_ifo->i_pos; */
120
121     /*
122      * read the video manager information table
123      */
124 #define MGINF     p_ifo->vmg.manager_inf
125     /*fprintf( stderr, "VMGI\n" ); */
126
127     ReadBytes( p_ifo, p_buf, &p_tmp, MGINF.psz_id, 12 );
128     MGINF.psz_id[12] = '\0';
129     MGINF.i_vmg_end_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
130     DumpBytes( p_ifo, p_buf, &p_tmp, 12 );
131     MGINF.i_vmg_inf_end_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
132     DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
133     MGINF.i_spec_ver = ReadByte( p_ifo, p_buf, &p_tmp );
134     MGINF.i_cat = ReadDouble( p_ifo, p_buf, &p_tmp );
135     MGINF.i_volume_nb = ReadWord( p_ifo, p_buf, &p_tmp );
136     MGINF.i_volume = ReadWord( p_ifo, p_buf, &p_tmp );
137     MGINF.i_disc_side = ReadByte( p_ifo, p_buf, &p_tmp );
138     DumpBytes( p_ifo, p_buf, &p_tmp, 19 );
139     MGINF.i_title_set_nb = ReadWord( p_ifo, p_buf, &p_tmp );
140     ReadBytes( p_ifo, p_buf, &p_tmp, MGINF.ps_provider_id, 32 );
141     MGINF.i_pos_code = ReadQuad( p_ifo, p_buf, &p_tmp );
142     DumpBytes( p_ifo, p_buf, &p_tmp, 24 );
143     MGINF.i_vmg_inf_end_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
144     MGINF.i_first_play_title_start_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
145     DumpBytes( p_ifo, p_buf, &p_tmp, 56 );
146     MGINF.i_vob_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
147     MGINF.i_title_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
148     MGINF.i_title_unit_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
149     MGINF.i_parental_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
150     MGINF.i_vts_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
151     MGINF.i_text_data_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
152     MGINF.i_cell_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
153     MGINF.i_vobu_map_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
154     DumpBytes( p_ifo, p_buf, &p_tmp, 32 );
155     DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
156     DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
157     MGINF.i_audio_nb = ReadByte( p_ifo, p_buf, &p_tmp );
158     /*fprintf( stderr, "vmgi audio nb : %d\n", MGINF.i_audio_nb ); */
159
160     for( i = 0 ; i < 8 ; i++ )
161     {
162         i_temp = ReadQuad( p_ifo, p_buf, &p_tmp );
163     }
164
165     DumpBytes( p_ifo, p_buf, &p_tmp, 17 );
166     MGINF.i_spu_nb = ReadByte( p_ifo, p_buf, &p_tmp );
167     /*fprintf( stderr, "vmgi subpic nb : %d\n", MGINF.i_spu_nb ); */
168
169     for( i = 0 ; i < MGINF.i_spu_nb ; i++ )
170     {
171         ReadBytes( p_ifo, p_buf, &p_tmp, (uint8_t*)(&i_temp), 6 );
172         /* FIXME : take care of endianness */
173     }
174
175     /*
176      * read first play title.
177      */
178     /*fprintf(stderr,"readtitle %i\n", MGINF.i_first_play_title_start_byte & 0x7ff ); */
179     if( ReadTitle( p_ifo, &p_ifo->vmg.title, p_ifo->i_start
180                            + OFF2LB( MGINF.i_first_play_title_start_byte ),
181                    MGINF.i_first_play_title_start_byte & 0x7ff ) < 0 )
182     {
183         return -1;
184     }
185
186     /*
187      * fills the title information structure.
188      */
189 #define TITINF       p_ifo->vmg.title_inf
190     if( MGINF.i_title_inf_start_sector )
191     {
192         p_tmp = FillBuffer( p_ifo, p_buf,
193                         p_ifo->i_start + MGINF.i_title_inf_start_sector );
194         /*fprintf( stderr, "title inf %d\n", p_ifo->i_pos ); */
195
196         TITINF.i_title_nb = ReadWord( p_ifo, p_buf, &p_tmp );
197         /*fprintf( stderr, "title_inf: TTU nb %d\n", TITINF.i_title_nb ); */
198         DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
199         TITINF.i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
200
201         /* parsing of title attributes */
202         TITINF.p_attr = malloc( TITINF.i_title_nb *sizeof(title_attr_t) );
203         if( TITINF.p_attr == NULL )
204         {
205             return -1;
206         }
207
208         for( i = 0 ; i < TITINF.i_title_nb ; i++ )
209         {
210             TITINF.p_attr[i].i_play_type = ReadByte( p_ifo, p_buf, &p_tmp );
211             TITINF.p_attr[i].i_angle_nb = ReadByte( p_ifo, p_buf, &p_tmp );
212             TITINF.p_attr[i].i_chapter_nb = ReadWord( p_ifo, p_buf, &p_tmp );
213             TITINF.p_attr[i].i_parental_id = ReadWord( p_ifo, p_buf, &p_tmp );
214             TITINF.p_attr[i].i_title_set_num = ReadByte( p_ifo, p_buf, &p_tmp );
215             TITINF.p_attr[i].i_title_num = ReadByte( p_ifo, p_buf, &p_tmp );
216             TITINF.p_attr[i].i_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
217             /*fprintf( stderr, "title_inf: %d %d %d\n", TITINF.p_attr[i].i_chapter_nb, TITINF.p_attr[i].i_title_set_num, TITINF.p_attr[i].i_title_num ); */
218         }
219     }
220     else
221     {
222         TITINF.p_attr = NULL;
223     }
224 #undef TITINF
225
226     /*
227      * fills the title unit structure.
228      */
229     if( MGINF.i_title_unit_start_sector )
230     {
231         if( ReadTitleUnit( p_ifo, &p_ifo->vmg.title_unit, p_ifo->i_start
232                             + MGINF.i_title_unit_start_sector ) < 0 )
233         {
234             return -1;
235         }
236     }
237
238     /*
239      * fills the structure about parental information.
240      */
241 #define PARINF        p_ifo->vmg.parental_inf
242     if( MGINF.i_parental_inf_start_sector )
243     {
244         p_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_start +
245                                 MGINF.i_parental_inf_start_sector );
246         i_start = p_ifo->i_pos;
247
248         /*fprintf( stderr, "PTL\n" ); */
249
250         PARINF.i_country_nb = ReadWord( p_ifo, p_buf, &p_tmp );
251         PARINF.i_vts_nb = ReadWord( p_ifo, p_buf, &p_tmp );
252         PARINF.i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
253
254         PARINF.p_parental_desc = malloc( PARINF.i_country_nb
255                                           * sizeof(parental_desc_t) );
256         if( PARINF.p_parental_desc == NULL )
257         {
258             return -1;
259         }
260
261         for( i = 0 ; i < PARINF.i_country_nb ; i++ )
262         {
263             ReadBytes( p_ifo, p_buf, &p_tmp,
264                        PARINF.p_parental_desc[i].ps_country_code, 2 );
265             DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
266             PARINF.p_parental_desc[i].i_parental_mask_start_byte =
267                                             ReadWord( p_ifo, p_buf, &p_tmp );
268             DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
269         }
270
271         PARINF.p_parental_mask = malloc( PARINF.i_country_nb
272                                           * sizeof(parental_mask_t) );
273         if( PARINF.p_parental_mask == NULL )
274         {
275             return -1;
276         }
277
278         for( i = 0 ; i < PARINF.i_country_nb ; i++ )
279         {
280             p_tmp = FillBuffer( p_ifo, p_buf, i_start + OFF2LB(
281                       PARINF.p_parental_desc[i].i_parental_mask_start_byte ) )
282               + (PARINF.p_parental_desc[i].i_parental_mask_start_byte & 0x7ff);
283
284             for( j = 0 ; j < 8 ; j++ )
285             {
286                 PARINF.p_parental_mask[i].ppi_mask[j] =
287                             malloc( ( PARINF.i_vts_nb + 1 ) * sizeof(uint16_t) );
288
289                 if( PARINF.p_parental_mask[i].ppi_mask[j] == NULL )
290                 {
291                     return -1;
292                 }
293
294                 for( k = 0 ; k < PARINF.i_vts_nb + 1 ; k++ )
295                 {
296                     PARINF.p_parental_mask[i].ppi_mask[j][k] =
297                                             ReadWord( p_ifo, p_buf, &p_tmp );
298                 }
299             }
300         }
301     }
302 #undef PARINF
303
304     /*
305      * information and attributes about for each vts.
306      */
307 #define VTSINF     p_ifo->vmg.vts_inf
308     if( MGINF.i_vts_inf_start_sector )
309     {
310         uint64_t i_temp;
311
312         p_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_start +
313                                 MGINF.i_vts_inf_start_sector );
314         i_start = p_ifo->i_pos;
315
316         /*fprintf( stderr, "VTS ATTR\n" ); */
317
318         VTSINF.i_vts_nb = ReadWord( p_ifo, p_buf, &p_tmp );;
319         /*fprintf( stderr, "VTS ATTR Nb: %d\n", VTSINF.i_vts_nb ); */
320         DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
321         VTSINF.i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
322         VTSINF.pi_vts_attr_start_byte =
323                             malloc( VTSINF.i_vts_nb * sizeof(uint32_t) );
324         if( VTSINF.pi_vts_attr_start_byte == NULL )
325         {
326             return -1;
327         }
328
329         for( i = 0 ; i < VTSINF.i_vts_nb ; i++ )
330         {
331             VTSINF.pi_vts_attr_start_byte[i] =
332                                       ReadDouble( p_ifo, p_buf, &p_tmp );
333         }
334
335         VTSINF.p_vts_attr = malloc( VTSINF.i_vts_nb * sizeof(vts_attr_t) );
336         if( VTSINF.p_vts_attr == NULL )
337         {
338             return -1;
339         }
340
341         for( i = 0 ; i < VTSINF.i_vts_nb ; i++ )
342         {
343             p_tmp = FillBuffer( p_ifo, p_buf, i_start +
344                                 OFF2LB( VTSINF.pi_vts_attr_start_byte[i] ) )
345                      + ( VTSINF.pi_vts_attr_start_byte[i] & 0x7ff );
346
347             VTSINF.p_vts_attr[i].i_last_byte =
348                                 ReadDouble( p_ifo, p_buf, &p_tmp );
349             VTSINF.p_vts_attr[i].i_cat_app_type =
350                                 ReadDouble( p_ifo, p_buf, &p_tmp );
351             DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
352             DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
353             VTSINF.p_vts_attr[i].i_vts_menu_audio_nb =
354                                 ReadByte( p_ifo, p_buf, &p_tmp );
355             /*fprintf( stderr, "m audio nb : %d\n", VTSINF.p_vts_attr[i].i_vts_menu_audio_nb ); */
356
357             for( j = 0 ; j < 8 ; j++ )
358             {
359                 i_temp = ReadQuad( p_ifo, p_buf, &p_tmp );
360             }
361
362             DumpBytes( p_ifo, p_buf, &p_tmp, 17 );
363             VTSINF.p_vts_attr[i].i_vts_menu_spu_nb =
364                                 ReadByte( p_ifo, p_buf, &p_tmp );
365             /*fprintf( stderr, "m subp nb : %d\n", VTSINF.p_vts_attr[i].i_vts_menu_spu_nb ); */
366
367             for( j = 0 ; j < 28 ; j++ )
368             {
369                 /* FIXME : Fix endianness issue here */
370                 ReadBytes( p_ifo, p_buf, &p_tmp, (uint8_t*)(&i_temp), 6 );
371             }
372
373             DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
374             DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
375             DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
376             VTSINF.p_vts_attr[i].i_vts_title_audio_nb =
377                                 ReadDouble( p_ifo, p_buf, &p_tmp );
378             /*fprintf( stderr, "tt audio nb : %d\n", VTSINF.p_vts_attr[i].i_vts_title_audio_nb ); */
379
380             for( j = 0 ; j < 8 ; j++ )
381             {
382                 i_temp = ReadQuad( p_ifo, p_buf, &p_tmp );;
383             }
384
385             DumpBytes( p_ifo, p_buf, &p_tmp, 17 );
386             VTSINF.p_vts_attr[i].i_vts_title_spu_nb =
387                                 ReadByte( p_ifo, p_buf, &p_tmp );
388             /*fprintf( stderr, "tt subp nb : %d\n", VTSINF.p_vts_attr[i].i_vts_title_spu_nb ); */
389
390             for( j = 0 ; j < 28 /*VTSINF.p_vts_vts_inf[i].i_vtstt_subpic_nb*/ ; j++ )
391             {
392                 /* FIXME : Fix endianness issue here */
393                 ReadBytes( p_ifo, p_buf, &p_tmp, (uint8_t*)(&i_temp), 6 );
394             }
395         }
396     }
397 #undef VTSINF
398
399     /*
400      * global cell map.
401      */
402     if( MGINF.i_cell_inf_start_sector )
403     {
404         if( ReadCellInf( p_ifo, &p_ifo->vmg.cell_inf, p_ifo->i_start +
405                          MGINF.i_cell_inf_start_sector ) < 0 )
406         {
407             return -1;
408         }
409     }
410
411     /*
412      * global vob unit map.
413      */
414     if( MGINF.i_vobu_map_start_sector )
415     {
416         if( ReadVobuMap( p_ifo, &p_ifo->vmg.vobu_map, p_ifo->i_start +
417                          MGINF.i_vobu_map_start_sector ) < 0 )
418         {
419             return -1;
420         }
421     }
422 #undef MGINF
423
424     p_ifo->vts.b_initialized = 0;
425
426     return 0;
427 }
428
429 /*****************************************************************************
430  * IfoTitleSet: Parse vts*.ifo files to fill the Video Title Set structure.
431  *****************************************************************************/
432 int IfoTitleSet( ifo_t * p_ifo, int i_title )
433 {
434     uint8_t     p_buf[DVD_LB_SIZE];
435     uint8_t *   p_tmp;
436     int         i_off;
437     int         i_start;
438     uint64_t    i_temp;
439     uint16_t    i_short;
440     int         i, j;
441
442     if( p_ifo->vts.b_initialized )
443     {
444         FreeTitleSet( &p_ifo->vts );
445     }
446
447     i_off = p_ifo->vmg.title_inf.p_attr[i_title-1].i_start_sector
448                    + p_ifo->i_start;
449
450     /*fprintf(stderr, "offset: %d\n" , i_off ); */
451
452     p_tmp = FillBuffer( p_ifo, p_buf, i_off );
453     /*i_start = p_ifo->i_pos; */
454     p_ifo->vts.i_pos = p_ifo->i_pos;
455
456 #define MGINF p_ifo->vts.manager_inf
457
458     /*
459      * read manager information
460      */
461     /*fprintf( stderr, "VTSI\n" ); */
462
463     ReadBytes( p_ifo, p_buf, &p_tmp, MGINF.psz_id , 12 );
464     MGINF.psz_id[12] = '\0';
465     MGINF.i_last_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
466     DumpBytes( p_ifo, p_buf, &p_tmp, 12 );
467     MGINF.i_inf_last_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
468     DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
469     MGINF.i_spec_ver = ReadByte( p_ifo, p_buf, &p_tmp );
470     MGINF.i_cat = ReadDouble( p_ifo, p_buf, &p_tmp );
471     DumpBytes( p_ifo, p_buf, &p_tmp, 90 );
472     MGINF.i_inf_end_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
473     DumpBytes( p_ifo, p_buf, &p_tmp, 60 );
474     MGINF.i_menu_vob_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
475     MGINF.i_title_vob_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
476     MGINF.i_title_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
477     MGINF.i_title_unit_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
478     MGINF.i_menu_unit_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
479     MGINF.i_time_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
480     MGINF.i_menu_cell_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
481     MGINF.i_menu_vobu_map_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
482     MGINF.i_cell_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
483     MGINF.i_vobu_map_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
484     DumpBytes( p_ifo, p_buf, &p_tmp, 24 );
485     DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
486     DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
487     MGINF.i_menu_audio_nb = ReadByte( p_ifo, p_buf, &p_tmp );
488
489     for( i = 0 ; i < 8 ; i++ )
490     {
491         i_temp = ReadQuad( p_ifo, p_buf, &p_tmp );
492     }
493
494     DumpBytes( p_ifo, p_buf, &p_tmp, 17 );
495     MGINF.i_menu_spu_nb = ReadByte( p_ifo, p_buf, &p_tmp );
496
497     for( i = 0 ; i < 28 ; i++ )
498     {
499         /* FIXME : take care of endianness */
500         ReadBytes( p_ifo, p_buf, &p_tmp, (uint8_t*)(&i_temp), 6 );
501     }
502
503     DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
504
505     i_short = ReadWord( p_ifo, p_buf, &p_tmp );
506     i_short >>= 2;
507     MGINF.video_attr.i_mode = i_short & 0x1;
508     i_short >>= 1;
509     MGINF.video_attr.i_letterboxed = i_short & 0x1;
510     i_short >>= 1;
511     MGINF.video_attr.i_source_res = i_short & 0x3;
512     i_short >>= 2;
513     MGINF.video_attr.i_line21_2 = i_short & 0x1;
514     i_short >>= 1;
515     MGINF.video_attr.i_line21_1 = i_short & 0x1;
516     i_short >>= 1;
517     MGINF.video_attr.i_perm_displ = i_short & 0x3;
518     i_short >>= 2;
519     MGINF.video_attr.i_ratio = i_short & 0x3;
520     i_short >>= 2;
521     MGINF.video_attr.i_system = i_short & 0x3;
522     i_short >>= 2;
523     MGINF.video_attr.i_compression = i_short & 0x3;
524
525     DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
526     MGINF.i_audio_nb = ReadByte( p_ifo, p_buf, &p_tmp );
527     /*fprintf( stderr, "vtsi audio nb : %d\n", MGINF.i_audio_nb ); */
528
529     for( i = 0 ; i < 8 ; i++ )
530     {
531         i_temp = ReadQuad( p_ifo, p_buf, &p_tmp );
532         /*fprintf( stderr, "Audio %d: "I64Fx"\n", i, i_temp ); */
533         i_temp >>= 8;
534         MGINF.p_audio_attr[i].i_bar = i_temp & 0xff;
535         i_temp >>= 8;
536         MGINF.p_audio_attr[i].i_caption = i_temp & 0xff;
537         i_temp >>= 8;
538         MGINF.p_audio_attr[i].i_foo = i_temp & 0xff;
539         i_temp >>= 8;
540         MGINF.p_audio_attr[i].i_lang_code = i_temp & 0xffff;
541         i_temp >>= 16;
542         MGINF.p_audio_attr[i].i_num_channels = i_temp & 0x7;
543         i_temp >>= 3;
544         MGINF.p_audio_attr[i].i_test = i_temp & 0x1;
545         i_temp >>= 1;
546         MGINF.p_audio_attr[i].i_sample_freq = i_temp & 0x3;
547         i_temp >>= 2;
548         MGINF.p_audio_attr[i].i_quantization = i_temp & 0x3;
549         i_temp >>= 2;
550         MGINF.p_audio_attr[i].i_appl_mode = i_temp & 0x3;
551         i_temp >>= 2;
552         MGINF.p_audio_attr[i].i_type = i_temp & 0x3;
553         i_temp >>= 2;
554         MGINF.p_audio_attr[i].i_multichannel_extension = i_temp & 0x1;
555         i_temp >>= 1;
556         MGINF.p_audio_attr[i].i_coding_mode = i_temp & 0x7;
557     }
558
559     DumpBytes( p_ifo, p_buf, &p_tmp, 17 );
560     MGINF.i_spu_nb = ReadByte( p_ifo, p_buf, &p_tmp );
561     /*fprintf( stderr, "vtsi subpic nb : %d\n", MGINF.i_spu_nb ); */
562
563     for( i=0 ; i<MGINF.i_spu_nb ; i++ )
564     {
565         ReadBytes( p_ifo, p_buf, &p_tmp, (uint8_t*)(&i_temp), 6 );
566         i_temp = hton64( i_temp ) >> 16;
567         /*fprintf( stderr, "Subpic %d: "I64Fx"\n", i, i_temp ); */
568         MGINF.p_spu_attr[i].i_caption = i_temp & 0xff;
569         i_temp >>= 8;
570         MGINF.p_spu_attr[i].i_foo = i_temp & 0xff;
571         i_temp >>= 8;
572         MGINF.p_spu_attr[i].i_lang_code = i_temp & 0xffff;
573         i_temp >>= 16;
574         MGINF.p_spu_attr[i].i_prefix = i_temp & 0xffff;
575     }
576
577     /*
578      * read title information: set of pointers to title
579      */
580 #define TITINF p_ifo->vts.title_inf
581     if( MGINF.i_title_inf_start_sector )
582     {
583         p_tmp = FillBuffer( p_ifo, p_buf, p_ifo->vts.i_pos +
584                                           MGINF.i_title_inf_start_sector );
585
586         i_start = p_ifo->i_pos;
587
588         /*fprintf( stderr, "VTS PTR\n" ); */
589
590         TITINF.i_title_nb = ReadWord( p_ifo, p_buf, &p_tmp );
591         /*fprintf( stderr, "VTS title_inf nb: %d\n", TITINF.i_title_nb ); */
592         DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
593         TITINF.i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
594
595         TITINF.pi_start_byte = malloc( TITINF.i_title_nb * sizeof(uint32_t) );
596         if( TITINF.pi_start_byte == NULL )
597         {
598             return -1;
599         }
600
601         for( i = 0 ; i < TITINF.i_title_nb ; i++ )
602         {
603             TITINF.pi_start_byte[i] = ReadDouble( p_ifo, p_buf, &p_tmp );
604         }
605
606         /* Parsing of tts */
607         TITINF.p_title_start = malloc( TITINF.i_title_nb
608                                          * sizeof(title_start_t) );
609         if( TITINF.p_title_start == NULL )
610         {
611             return -1;
612         }
613
614         for( i = 0 ; i < TITINF.i_title_nb ; i++ )
615         {
616             p_tmp = FillBuffer( p_ifo, p_buf, i_start +
617                                 OFF2LB( TITINF.pi_start_byte[i] ) )
618                      + (TITINF.pi_start_byte[i] & 0x7ff);
619
620             TITINF.p_title_start[i].i_title_id =
621                                    ReadWord( p_ifo, p_buf, &p_tmp );
622             TITINF.p_title_start[i].i_chapter =
623                                    ReadWord( p_ifo, p_buf, &p_tmp );
624         }
625     }
626 #undef TITINF
627
628     /*
629      * menu unit information
630      */
631     if( MGINF.i_menu_unit_start_sector )
632     {
633         if( ReadTitleUnit( p_ifo, &p_ifo->vts.menu_unit, p_ifo->vts.i_pos +
634                      MGINF.i_menu_unit_start_sector ) < 0 )
635         {
636             return -1;
637         }
638     }
639
640     /*
641      * title unit information
642      */
643     if( MGINF.i_title_unit_start_sector )
644     {
645         if( ReadUnitInf( p_ifo, &p_ifo->vts.title_unit, p_ifo->vts.i_pos +
646                          MGINF.i_title_unit_start_sector, 0  ) < 0 )
647         {
648             return -1;
649         }
650     }
651
652     /*
653      * time map information
654      */
655 #define TIMINF p_ifo->vts.time_inf
656     if( MGINF.i_time_inf_start_sector )
657     {
658         uint8_t p_buf[DVD_LB_SIZE];
659
660         p_tmp = FillBuffer( p_ifo, p_buf, p_ifo->vts.i_pos +
661                                           MGINF.i_time_inf_start_sector );
662
663         /*fprintf( stderr, "TMAP\n" ); */
664
665         TIMINF.i_nb = ReadWord( p_ifo, p_buf, &p_tmp );;
666         DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
667         TIMINF.i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
668
669         TIMINF.pi_start_byte = malloc( TIMINF.i_nb * sizeof(uint32_t) );
670         if( TIMINF.pi_start_byte == NULL )
671         {
672             return -1;
673         }
674
675         for( i = 0 ; i < TIMINF.i_nb ; i++ )
676         {
677             TIMINF.pi_start_byte[i] = ReadDouble( p_ifo, p_buf, &p_tmp );
678         }
679
680         TIMINF.p_time_map = malloc( TIMINF.i_nb * sizeof(time_map_t) );
681         if( TIMINF.p_time_map == NULL )
682         {
683             return -1;
684         }
685
686         for( i = 0 ; i < TIMINF.i_nb ; i++ )
687         {
688             TIMINF.p_time_map[i].i_time_unit = ReadByte( p_ifo, p_buf, &p_tmp );
689             DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
690             TIMINF.p_time_map[i].i_entry_nb = ReadWord( p_ifo, p_buf, &p_tmp );
691
692             if( TIMINF.p_time_map[i].i_entry_nb )
693             {
694                 TIMINF.p_time_map[i].pi_sector =
695                      malloc( TIMINF.p_time_map[i].i_entry_nb * sizeof(uint32_t) );
696                 if( TIMINF.p_time_map[i].pi_sector == NULL )
697                 {
698                     return -1;
699                 }
700
701                 for( j = 0 ; j < TIMINF.p_time_map[i].i_entry_nb ; j++ )
702                 {
703                     TIMINF.p_time_map[i].pi_sector[j] =
704                                         ReadDouble( p_ifo, p_buf, &p_tmp );
705                 }
706             }
707         }
708     }
709 #undef TIMINF
710
711     if( MGINF.i_menu_cell_inf_start_sector
712          && ReadCellInf( p_ifo, &p_ifo->vts.menu_cell_inf, p_ifo->vts.i_pos +
713                          MGINF.i_menu_cell_inf_start_sector ) < 0 )
714     {
715         return -1;
716     }
717
718     if( MGINF.i_menu_vobu_map_start_sector
719          && ReadVobuMap( p_ifo, &p_ifo->vts.menu_vobu_map, p_ifo->vts.i_pos +
720                          MGINF.i_menu_vobu_map_start_sector ) < 0 )
721     {
722         return -1;
723     }
724
725     if( MGINF.i_cell_inf_start_sector
726          && ReadCellInf( p_ifo, &p_ifo->vts.cell_inf, p_ifo->vts.i_pos +
727                          MGINF.i_cell_inf_start_sector ) )
728     {
729         return -1;
730     }
731
732     if( MGINF.i_vobu_map_start_sector
733          && ReadVobuMap( p_ifo, &p_ifo->vts.vobu_map, p_ifo->vts.i_pos +
734                          MGINF.i_vobu_map_start_sector ) )
735     {
736         return -1;
737     }
738 #undef MGINF
739
740 #if 0
741     intf_Warn( p_input, 4, "vts %d initialized",
742                p_ifo->vmg.title_inf.p_attr[i_title-1].i_title_set_num );
743 #endif
744
745     p_ifo->vts.b_initialized = 1;
746
747     return 0;
748 }
749
750 /*****************************************************************************
751  * FreeTitleSet : free all structures allocated by IfoTitleSet
752  *****************************************************************************/
753 static int FreeTitleSet( vts_t * p_vts )
754 {
755     int     i;
756
757     if( p_vts->manager_inf.i_vobu_map_start_sector )
758     {
759         FreeVobuMap( &p_vts->vobu_map );
760     }
761
762     if( p_vts->manager_inf.i_cell_inf_start_sector )
763     {
764         FreeCellInf( &p_vts->cell_inf );
765     }
766
767     if( p_vts->manager_inf.i_menu_vobu_map_start_sector )
768     {
769         FreeVobuMap( &p_vts->menu_vobu_map );
770     }
771
772     if( p_vts->manager_inf.i_menu_cell_inf_start_sector )
773     {
774         FreeCellInf( &p_vts->menu_cell_inf );
775     }
776
777     if( p_vts->manager_inf.i_time_inf_start_sector )
778     {
779         for( i = 0 ; i < p_vts->time_inf.i_nb ; i++ )
780         {
781             if( p_vts->time_inf.p_time_map[i].i_entry_nb )
782             {
783                 free( p_vts->time_inf.p_time_map[i].pi_sector );
784             }
785         }
786
787         free( p_vts->time_inf.p_time_map );
788         free( p_vts->time_inf.pi_start_byte );
789     }
790
791     if( p_vts->manager_inf.i_title_unit_start_sector )
792     {
793         FreeUnitInf( &p_vts->title_unit );
794     }
795
796     if( p_vts->manager_inf.i_menu_unit_start_sector )
797     {
798         FreeTitleUnit( &p_vts->menu_unit );
799     }
800
801     if( p_vts->manager_inf.i_title_inf_start_sector )
802     {
803         free( p_vts->title_inf.pi_start_byte );
804         free( p_vts->title_inf.p_title_start );
805     }
806
807     p_vts->b_initialized = 0;
808
809     return 0;
810 }
811
812 /*****************************************************************************
813  * IfoDestroy : Frees all the memory allocated to ifo structures
814  *****************************************************************************/
815 void IfoDestroy( ifo_t * p_ifo )
816 {
817     int     i, j;
818
819     FreeTitleSet( &p_ifo->vts );
820
821     if( p_ifo->vmg.manager_inf.i_vobu_map_start_sector )
822     {
823         FreeVobuMap( &p_ifo->vmg.vobu_map );
824     }
825
826     if( p_ifo->vmg.manager_inf.i_cell_inf_start_sector )
827     {
828         FreeCellInf( &p_ifo->vmg.cell_inf );
829     }
830
831     if( p_ifo->vmg.manager_inf.i_vts_inf_start_sector )
832     {
833         free( p_ifo->vmg.vts_inf.p_vts_attr );
834         free( p_ifo->vmg.vts_inf.pi_vts_attr_start_byte );
835     }
836
837     /* free parental information structures */
838     if( p_ifo->vmg.manager_inf.i_parental_inf_start_sector )
839     {
840         for( i = 0 ; i < p_ifo->vmg.parental_inf.i_country_nb ; i++ )
841         {
842             for( j = 0 ; j < 8 ; j++ )
843             {
844                 if ( p_ifo->vmg.parental_inf.p_parental_mask[i].ppi_mask[j] != NULL )
845                     free( p_ifo->vmg.parental_inf.p_parental_mask[i].ppi_mask[j] );
846             }
847         }
848
849         if ( p_ifo->vmg.parental_inf.p_parental_mask != NULL )
850             free( p_ifo->vmg.parental_inf.p_parental_mask );
851         if ( p_ifo->vmg.parental_inf.p_parental_desc != NULL )
852             free( p_ifo->vmg.parental_inf.p_parental_desc );
853     }
854
855     if( p_ifo->vmg.manager_inf.i_title_unit_start_sector )
856     {
857         FreeTitleUnit( &p_ifo->vmg.title_unit );
858     }
859
860     if( p_ifo->vmg.manager_inf.i_title_inf_start_sector )
861     {
862         free( p_ifo->vmg.title_inf.p_attr );
863     }
864
865     FreeTitle( &p_ifo->vmg.title );
866
867     free( p_ifo );
868
869     return;
870 }
871
872 /*
873  * Function common to Video Manager and Video Title set Processing
874  */
875
876 /*****************************************************************************
877  * ReadTitle : Fills the title structure.
878  *****************************************************************************
879  * Titles are logical stream units that correspond to a whole inside the dvd.
880  * Several title can point to the same part of the physical DVD, and give
881  * map to different anglesfor instance.
882  *****************************************************************************/
883 static int ReadTitle( ifo_t * p_ifo, title_t * p_title, int i_block, int i_bytes )
884 {
885     uint8_t     p_buf[DVD_LB_SIZE];
886     uint8_t *   p_tmp;
887     int         i_start;
888     uint16_t    i_audio;
889     uint32_t    i_spu;
890     int         i;
891
892     p_tmp = FillBuffer( p_ifo, p_buf, i_block ) + i_bytes;
893
894     i_start = p_ifo->i_pos;
895
896     /*fprintf( stderr, "PGC @ %d + %d\n", p_ifo->i_pos, i_bytes ); */
897
898     DumpBytes( p_ifo, p_buf, &p_tmp, 2);
899     p_title->i_chapter_nb = ReadByte( p_ifo, p_buf, &p_tmp );
900     p_title->i_cell_nb = ReadByte( p_ifo, p_buf, &p_tmp );
901     /*fprintf( stderr, "title: Prg: %d Cell: %d\n",p_title->i_chapter_nb,p_title->i_cell_nb  ); */
902     p_title->i_play_time = ReadDouble( p_ifo, p_buf, &p_tmp );
903     p_title->i_prohibited_user_op = ReadDouble( p_ifo, p_buf, &p_tmp );
904
905     for( i = 0 ; i < 8 ; i++ )
906     {
907         i_audio = ReadWord( p_ifo, p_buf, &p_tmp );
908         p_title->pi_audio_status[i].i_foo = i_audio & 0xff;
909         i_audio >>= 8;
910         p_title->pi_audio_status[i].i_position = i_audio & 0x07;
911         i_audio >>= 7;
912         p_title->pi_audio_status[i].i_available = i_audio;
913     }
914
915     for( i = 0 ; i < 32 ; i++ )
916     {
917         i_spu = ReadDouble( p_ifo, p_buf, &p_tmp );
918         p_title->pi_spu_status[i].i_position_pan = i_spu & 0x1f;
919         i_spu >>= 8;
920         p_title->pi_spu_status[i].i_position_letter = i_spu & 0x1f;
921         i_spu >>= 8;
922         p_title->pi_spu_status[i].i_position_wide = i_spu & 0x1f;
923         i_spu >>= 8;
924         p_title->pi_spu_status[i].i_position_43 = i_spu & 0x1f;
925         i_spu >>= 7;
926         p_title->pi_spu_status[i].i_available = i_spu;
927     }
928
929     p_title->i_next_title_num = ReadWord( p_ifo, p_buf, &p_tmp );
930     p_title->i_prev_title_num = ReadWord( p_ifo, p_buf, &p_tmp );
931     p_title->i_go_up_title_num = ReadWord( p_ifo, p_buf, &p_tmp );
932     p_title->i_still_time = ReadByte( p_ifo, p_buf, &p_tmp );
933     p_title->i_play_mode = ReadByte( p_ifo, p_buf, &p_tmp );
934
935     for( i = 0 ; i < 16 ; i++ )
936     {
937         /* FIXME : We have to erase the extra bit */
938         p_title->pi_yuv_color[i] = ReadDouble( p_ifo, p_buf, &p_tmp );
939     }
940
941     p_title->i_command_start_byte = ReadWord( p_ifo, p_buf, &p_tmp );
942     p_title->i_chapter_map_start_byte = ReadWord( p_ifo, p_buf, &p_tmp );
943     p_title->i_cell_play_start_byte = ReadWord( p_ifo, p_buf, &p_tmp );
944     p_title->i_cell_pos_start_byte = ReadWord( p_ifo, p_buf, &p_tmp );
945
946     /* parsing of command_t */
947     if( p_title->i_command_start_byte )
948     {
949         p_tmp = FillBuffer( p_ifo, p_buf, i_start +
950                             OFF2LB( p_title->i_command_start_byte + i_bytes ) )
951                  + ( (p_title->i_command_start_byte + i_bytes) & 0x7ff );
952
953         /* header */
954         p_title->command.i_pre_command_nb = ReadWord( p_ifo, p_buf, &p_tmp );
955         p_title->command.i_post_command_nb = ReadWord( p_ifo, p_buf, &p_tmp );
956         p_title->command.i_cell_command_nb = ReadWord( p_ifo, p_buf, &p_tmp );
957         DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
958
959         /* pre-title commands */
960         if( p_title->command.i_pre_command_nb )
961         {
962             p_title->command.p_pre_command =
963                            malloc( p_title->command.i_pre_command_nb
964                                     * sizeof(command_desc_t) );
965
966             if( p_title->command.p_pre_command == NULL )
967             {
968                 return -1;
969             }
970
971             for( i = 0 ; i < p_title->command.i_pre_command_nb ; i++ )
972             {
973                 p_title->command.p_pre_command[i] =
974                                         ReadQuad( p_ifo, p_buf, &p_tmp );
975             }
976         }
977         else
978         {
979             p_title->command.p_pre_command = NULL;
980         }
981
982         /* post-title commands */
983         if( p_title->command.i_post_command_nb )
984         {
985             p_title->command.p_post_command =
986                         malloc( p_title->command.i_post_command_nb
987                                  * sizeof(command_desc_t) );
988
989             if( p_title->command.p_post_command == NULL )
990             {
991                 return -1;
992             }
993
994             for( i = 0 ; i < p_title->command.i_post_command_nb ; i++ )
995             {
996                 p_title->command.p_post_command[i] =
997                                         ReadQuad( p_ifo, p_buf, &p_tmp );
998             }
999         }
1000         else
1001         {
1002             p_title->command.p_post_command = NULL;
1003         }
1004
1005         /* cell commands */
1006         if( p_title->command.i_cell_command_nb )
1007         {
1008             p_title->command.p_cell_command =
1009                         malloc( p_title->command.i_cell_command_nb
1010                                  * sizeof(command_desc_t) );
1011
1012             if( p_title->command.p_cell_command == NULL )
1013             {
1014                 return -1;
1015             }
1016
1017             for( i = 0 ; i < p_title->command.i_cell_command_nb ; i++ )
1018             {
1019                 p_title->command.p_cell_command[i] =
1020                                         ReadQuad( p_ifo, p_buf, &p_tmp );
1021             }
1022         }
1023         else
1024         {
1025             p_title->command.p_cell_command = NULL;
1026         }
1027     }
1028
1029     /* parsing of chapter_map_t: it gives the entry cell for each chapter */
1030     if( p_title->i_chapter_map_start_byte )
1031     {
1032         p_ifo->i_pos = dvdcss_seek( p_ifo->dvdhandle,
1033                OFF2LB( i_start + p_title->i_chapter_map_start_byte ),
1034                DVDCSS_NOFLAGS );
1035
1036         p_title->chapter_map.pi_start_cell =
1037                     malloc( p_title->i_chapter_nb * sizeof(chapter_map_t) );
1038
1039         if( p_title->chapter_map.pi_start_cell == NULL )
1040         {
1041             return -1;
1042         }
1043
1044         ReadBytes( p_ifo, p_buf, &p_tmp, p_title->chapter_map.pi_start_cell,
1045                    p_title->i_chapter_nb );
1046     }
1047     else
1048     {
1049         p_title->chapter_map.pi_start_cell = NULL;
1050     }
1051
1052     /* parsing of cell_play_t */
1053     if( p_title->i_cell_play_start_byte )
1054     {
1055         p_tmp = FillBuffer( p_ifo, p_buf, i_start +
1056                             OFF2LB( p_title->i_cell_play_start_byte+i_bytes ) )
1057                  + ( (p_title->i_cell_play_start_byte+i_bytes) & 0x7ff );
1058
1059         p_title->p_cell_play = malloc( p_title->i_cell_nb
1060                                         * sizeof(cell_play_t) );
1061
1062         if( p_title->p_cell_play == NULL )
1063         {
1064             return -1;
1065         }
1066
1067         for( i = 0 ; i < p_title->i_cell_nb ; i++ )
1068         {
1069 #define PLAY p_title->p_cell_play[i]
1070             PLAY.i_category = ReadWord( p_ifo, p_buf, &p_tmp );
1071             PLAY.i_still_time = ReadByte( p_ifo, p_buf, &p_tmp );
1072             PLAY.i_command_nb = ReadByte( p_ifo, p_buf, &p_tmp );
1073             PLAY.i_play_time = ReadDouble( p_ifo, p_buf, &p_tmp );
1074             PLAY.i_first_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
1075             PLAY.i_first_ilvu_vobu_esector = ReadDouble( p_ifo, p_buf, &p_tmp );
1076             PLAY.i_last_vobu_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
1077             PLAY.i_last_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
1078 #undef PLAY
1079         }
1080     }
1081
1082     /* Parsing of cell_pos_t */
1083     if( p_title->i_cell_pos_start_byte )
1084     {
1085         p_tmp = FillBuffer( p_ifo, p_buf, i_start +
1086                             OFF2LB( p_title->i_cell_pos_start_byte + i_bytes ) )
1087                  + ( (p_title->i_cell_pos_start_byte + i_bytes) & 0x7ff );
1088
1089         p_title->p_cell_pos = malloc( p_title->i_cell_nb
1090                                        * sizeof(cell_pos_t) );
1091
1092         if( p_title->p_cell_pos == NULL )
1093         {
1094             return -1;
1095         }
1096
1097         for( i = 0 ; i < p_title->i_cell_nb ; i++ )
1098         {
1099             p_title->p_cell_pos[i].i_vob_id = ReadWord( p_ifo, p_buf, &p_tmp );
1100             DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
1101             p_title->p_cell_pos[i].i_cell_id = ReadByte( p_ifo, p_buf, &p_tmp );
1102         }
1103     }
1104
1105     return 0;
1106 }
1107
1108 /*****************************************************************************
1109  * FreeTitle: frees alla structure allocated by a call to ReadTitle
1110  *****************************************************************************/
1111 static int FreeTitle( title_t * p_title )
1112 {
1113     if( p_title->i_command_start_byte )
1114     {
1115         if( p_title->command.i_pre_command_nb )
1116         {
1117             free( p_title->command.p_pre_command );
1118         }
1119
1120         if( p_title->command.i_post_command_nb )
1121         {
1122             free( p_title->command.p_post_command );
1123         }
1124
1125         if( p_title->command.i_cell_command_nb )
1126         {
1127             free( p_title->command.p_cell_command );
1128         }
1129     }
1130
1131     if( p_title->i_chapter_map_start_byte )
1132     {
1133         free( p_title->chapter_map.pi_start_cell );
1134     }
1135
1136     if( p_title->i_cell_play_start_byte )
1137     {
1138         free( p_title->p_cell_play );
1139     }
1140
1141     if( p_title->i_cell_pos_start_byte )
1142     {
1143         free( p_title->p_cell_pos );
1144     }
1145
1146     return 0;
1147 }
1148
1149 /*****************************************************************************
1150  * ReadUnitInf : Fills Menu Language Unit Table/ PGC Info Table
1151  *****************************************************************************/
1152 static int ReadUnitInf( ifo_t * p_ifo, unit_inf_t * p_unit_inf,
1153                         int i_block, int i_bytes )
1154 {
1155     uint8_t         p_buf[DVD_LB_SIZE];
1156     uint8_t *       p_tmp;
1157     int             i_start;
1158     int             i;
1159
1160     p_tmp = FillBuffer( p_ifo, p_buf, i_block ) + i_bytes;
1161
1162     i_start = p_ifo->i_pos;
1163     /*fprintf( stderr, "Unit\n" ); */
1164
1165     p_unit_inf->i_title_nb = ReadWord( p_ifo, p_buf, &p_tmp );
1166     /*fprintf( stderr, "Unit nb: %d\n", p_unit_inf->i_title_nb ); */
1167     DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
1168     p_unit_inf->i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
1169
1170     p_unit_inf->p_title =
1171             malloc( p_unit_inf->i_title_nb * sizeof(unit_title_t) );
1172     if( p_unit_inf->p_title == NULL )
1173     {
1174         return -1;
1175     }
1176
1177     for( i = 0 ; i < p_unit_inf->i_title_nb ; i++ )
1178     {
1179 #define TITLE p_unit_inf->p_title[i]
1180         TITLE.i_category_mask = ReadByte( p_ifo, p_buf, &p_tmp );
1181         TITLE.i_category = ReadByte( p_ifo, p_buf, &p_tmp );
1182         /*fprintf( stderr, "cat mask %d: %x cat %x\n", i, TITLE.i_category_mask, TITLE.i_category ); */
1183         TITLE.i_parental_mask = ReadWord( p_ifo, p_buf, &p_tmp );
1184         TITLE.i_title_start_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
1185 #undef TITLE
1186     }
1187
1188     for( i = 0 ; i < p_unit_inf->i_title_nb ; i++ )
1189     {
1190         /*fprintf( stderr, "Unit: PGC %d @ %d\n", i, p_ifo->i_pos ); */
1191         ReadTitle( p_ifo, &p_unit_inf->p_title[i].title, i_start +
1192             OFF2LB( p_unit_inf->p_title[i].i_title_start_byte + i_bytes ),
1193           (p_unit_inf->p_title[i].i_title_start_byte+i_bytes) & 0x7ff );
1194     }
1195
1196     return 0;
1197 }
1198
1199 /*****************************************************************************
1200  * FreeUnitInf : frees a structure allocated by ReadUnit
1201  *****************************************************************************/
1202 static int FreeUnitInf( unit_inf_t * p_unit_inf )
1203 {
1204     int i;
1205
1206     if( p_unit_inf->p_title != NULL )
1207     {
1208         for( i = 0 ; i < p_unit_inf->i_title_nb ; i++ )
1209         {
1210             FreeTitle( &p_unit_inf->p_title[i].title );
1211         }
1212
1213         free( p_unit_inf->p_title );
1214     }
1215
1216     return 0;
1217 }
1218
1219
1220 /*****************************************************************************
1221  * ReadTitleUnit: Fills the Title Unit structure.
1222  *****************************************************************************/
1223 static int ReadTitleUnit( ifo_t * p_ifo, title_unit_t * p_title_unit,
1224                           int i_block )
1225 {
1226     uint8_t         p_buf[DVD_LB_SIZE];
1227     uint8_t *       p_tmp;
1228     int             i;
1229     int             i_start;
1230
1231     p_tmp = FillBuffer( p_ifo, p_buf, i_block );
1232     i_start = p_ifo->i_pos;
1233     /*fprintf( stderr, "Unit Table\n" ); */
1234
1235     p_title_unit->i_unit_nb = ReadWord( p_ifo, p_buf, &p_tmp );
1236     DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
1237     p_title_unit->i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
1238
1239     /*fprintf(stderr, "Unit: nb %d last %d\n", p_title_unit->i_unit_nb, p_title_unit->i_last_byte ); */
1240
1241     p_title_unit->p_unit = malloc( p_title_unit->i_unit_nb * sizeof(unit_t) );
1242     if( p_title_unit->p_unit == NULL )
1243     {
1244         return -1;
1245     }
1246
1247     for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ )
1248     {
1249         /*ReadBytes( p_ifo, p_buf, &p_tmp, p_title_unit->p_unit[i].ps_lang_code, 2 ); */
1250         p_title_unit->p_unit[i].i_lang_code = ReadWord( p_ifo, p_buf, &p_tmp );
1251         /*fprintf( stderr, "lang %d %x\n", i,p_title_unit->p_unit[i].i_lang_code ); */
1252         DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
1253         p_title_unit->p_unit[i].i_existence_mask =
1254                                            ReadByte( p_ifo, p_buf, &p_tmp );
1255         p_title_unit->p_unit[i].i_unit_inf_start_byte =
1256                                            ReadDouble( p_ifo, p_buf, &p_tmp );
1257     }
1258
1259     p_title_unit->p_unit_inf =
1260                 malloc( p_title_unit->i_unit_nb * sizeof(unit_inf_t) );
1261     if( p_title_unit->p_unit_inf == NULL )
1262     {
1263         return -1;
1264     }
1265
1266     for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ )
1267     {
1268         ReadUnitInf( p_ifo, &p_title_unit->p_unit_inf[i], i_start +
1269                       OFF2LB( p_title_unit->p_unit[i].i_unit_inf_start_byte ),
1270                      p_title_unit->p_unit[i].i_unit_inf_start_byte & 0x7ff );
1271     }
1272
1273     return 0;
1274 }
1275
1276 /*****************************************************************************
1277  * FreeTitleUnit: frees a structure allocateed by ReadTitleUnit
1278  *****************************************************************************/
1279 static int FreeTitleUnit( title_unit_t * p_title_unit )
1280 {
1281     int     i;
1282
1283     if( p_title_unit->p_unit_inf != NULL )
1284     {
1285         for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ )
1286         {
1287             FreeUnitInf( &p_title_unit->p_unit_inf[i] );
1288         }
1289
1290         free( p_title_unit->p_unit_inf );
1291     }
1292
1293     return 0;
1294 }
1295
1296 /*****************************************************************************
1297  * ReadCellInf : Fills the Cell Information structure.
1298  *****************************************************************************/
1299 static int ReadCellInf( ifo_t * p_ifo, cell_inf_t * p_cell_inf, int i_block )
1300 {
1301     uint8_t         p_buf[DVD_LB_SIZE];
1302     uint8_t *       p_tmp;
1303     int             i_start;
1304     int             i;
1305
1306     p_tmp = FillBuffer( p_ifo, p_buf, i_block );
1307     i_start = p_ifo->i_pos;
1308 /*    fprintf( stderr, "CELL ADD\n" ); */
1309
1310     p_cell_inf->i_vob_nb = ReadWord( p_ifo, p_buf, &p_tmp );
1311     DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
1312     p_cell_inf->i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
1313
1314     p_cell_inf->i_cell_nb = (p_cell_inf->i_last_byte + 1/* - 7*/) / sizeof(cell_map_t);
1315
1316 /*    fprintf( stderr, "Cell inf: vob %d, %d cells, last byte %d\n", p_cell_inf->i_vob_nb, p_cell_inf->i_cell_nb, p_cell_inf->i_last_byte );
1317 */
1318     p_cell_inf->p_cell_map =
1319                 malloc( p_cell_inf->i_cell_nb *sizeof(cell_map_t) );
1320     if( p_cell_inf->p_cell_map == NULL )
1321     {
1322         return -1;
1323     }
1324
1325     for( i = 0 ; i < p_cell_inf->i_cell_nb ; i++ )
1326     {
1327 #define MAP p_cell_inf->p_cell_map[i]
1328         MAP.i_vob_id = ReadWord( p_ifo, p_buf, &p_tmp );
1329         MAP.i_cell_id = ReadByte( p_ifo, p_buf, &p_tmp );
1330         DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
1331         MAP.i_first_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
1332 /*        fprintf(stderr, "sector[%d] %d (%d)\n", i,ntohl(*(uint32_t*)(p_tmp)), p_ifo->i_pos);*/
1333         MAP.i_last_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
1334 #undef MAP
1335     }
1336
1337     return 0;
1338 }
1339
1340 /*****************************************************************************
1341  * FreeCellInf : frees structures allocated by ReadCellInf
1342  *****************************************************************************/
1343 static int FreeCellInf( cell_inf_t * p_cell_inf )
1344 {
1345     free( p_cell_inf->p_cell_map );
1346
1347     return 0;
1348 }
1349
1350 /*****************************************************************************
1351  * ReadVobuMap : Fills the VOBU Map structure.
1352  *****************************************************************************/
1353 static int ReadVobuMap( ifo_t * p_ifo, vobu_map_t * p_vobu_map, int i_block )
1354 {
1355     uint8_t             p_buf[DVD_LB_SIZE];
1356     uint8_t *           p_tmp;
1357     int                 i_start;
1358     int                 i, i_max;
1359
1360     p_tmp = FillBuffer( p_ifo, p_buf, i_block );
1361     i_start = p_ifo->i_pos;
1362     /*fprintf( stderr, "VOBU ADMAP\n" ); */
1363
1364     p_vobu_map->i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
1365     i_max = ( i_start + p_vobu_map->i_last_byte + 1 - p_ifo->i_pos )
1366              / sizeof(uint32_t);
1367
1368     p_vobu_map->pi_vobu_start_sector = malloc( i_max * sizeof(uint32_t) );
1369     if( p_vobu_map->pi_vobu_start_sector == NULL )
1370     {
1371         return -1;
1372     }
1373
1374     for( i = 0 ; i < i_max ; i++ )
1375     {
1376         p_vobu_map->pi_vobu_start_sector[i] = ReadDouble( p_ifo, p_buf, &p_tmp );
1377     }
1378
1379     return 0;
1380 }
1381
1382 /*****************************************************************************
1383  * FreeVobuMap: frees structures allocated by ReadVobuMap
1384  *****************************************************************************/
1385 static int FreeVobuMap( vobu_map_t * p_vobu_map )
1386 {
1387     free( p_vobu_map->pi_vobu_start_sector );
1388
1389     return 0;
1390 }
1391
1392 /*
1393  * IFO virtual machine : a set of commands that give the
1394  * interactive behaviour of the dvd
1395  */
1396 #if 0
1397
1398 #define OP_VAL_16(i) (ntoh16( com.data.pi_16[i]))
1399 #define OP_VAL_8(i) ((com.data.pi_8[i]))
1400
1401 static char ifo_reg[][80]=
1402 {
1403     "Menu_Language_Code",
1404     "Audio_Stream_#",
1405     "SubPicture_Stream_#",
1406     "Angle_#",
1407     "VTS_#",
1408     "VTS_Title_#",
1409     "PGC_#",
1410     "PTT_#",
1411     "Highlighted_Button_#",
1412     "Nav_Timer",
1413     "TimedPGC",
1414     "Karaoke_audio_mixing_mode",
1415     "Parental_mgmt_country_code",
1416     "Parental_Level",
1417     "Player_Video_Cfg",
1418     "Player_Audio_Cfg",
1419     "Audio_language_code_setting",
1420     "Audio_language_extension_code",
1421     "SPU_language_code_setting",
1422     "SPU_language_extension_code",
1423     "?Player_Regional_Code",
1424     "Reserved_21",
1425     "Reserved_22",
1426     "Reserved_23"
1427 };
1428
1429 static char * IfoMath( char val )
1430 {
1431     static char math_op[][10] =
1432     {
1433         "none",
1434         "=",
1435         "<->",    /* swap */
1436         "+=",
1437         "-=",
1438         "*=",
1439         "/=",
1440         "%=",
1441         "rnd",    /* rnd */
1442         "&=",
1443         "|=",
1444         "^=",
1445         "??",    /* invalid */
1446         "??",    /* invalid */
1447         "??",    /* invalid */
1448         "??"    /* invalid */
1449     };
1450
1451     return (char *) math_op[val & 0x0f];
1452 }
1453
1454
1455 char ifo_cmp[][10] =
1456 {
1457     "none",
1458     "&&",
1459     "==",
1460     "!=",
1461     ">=",
1462     ">",
1463     "<",
1464     "<="
1465 };
1466
1467 char ifo_parental[][10] =
1468 {
1469     "0",
1470     "G",
1471     "2",
1472     "PG",
1473     "PG-13",
1474     "5",
1475     "R",
1476     "NC-17"
1477 };
1478
1479 char ifo_menu_id[][80] =
1480 {
1481     "-0-",
1482     "-1-",
1483     "Title (VTS menu)",
1484     "Root",
1485     "Sub-Picture",
1486     "Audio",
1487     "Angle",
1488     "Part of Title",
1489 };
1490
1491 char * IfoMenuName( char index )
1492 {
1493     return ifo_menu_id[index&0x07];
1494 }
1495
1496 static void IfoRegister( uint16_t i_data, uint8_t i_direct)
1497 {
1498     if( i_direct )
1499     {
1500         if( 0/*isalpha( i_data >> 8 & 0xff )*/ )
1501         {
1502             printf("'%c%c'", i_data>>8&0xff, i_data&0xff);
1503         }
1504         else
1505         {
1506             printf("0x%02x", i_data);
1507         }
1508     }
1509     else
1510     {
1511         if( i_data & 0x80 )
1512         {
1513             i_data &= 0x1f;
1514
1515             if( i_data > 0x17 )
1516             {
1517                 printf("s[ILL]");
1518             }
1519             else
1520             {
1521                 printf("s[%s]", ifo_reg[i_data]);
1522             }
1523         }
1524         else
1525         {
1526             i_data &= 0x1f;
1527
1528             if( i_data > 0xf )
1529             {
1530                 printf("r[ILL]");
1531             }
1532             else
1533             {
1534                 printf("r[0x%02x]", i_data);
1535             }
1536         }
1537     }
1538 }
1539
1540 static void IfoAdvanced( uint8_t *pi_code ){
1541     uint8_t i_cmd = pi_code[0];
1542
1543     printf(" { ");
1544
1545     if( pi_code[1]>>2 )
1546     {
1547         printf( " Highlight button %d; ", pi_code[1]>>2 );
1548     }
1549
1550     if( i_cmd == 0xff )
1551     {
1552         printf( " Illegal " );
1553     }
1554
1555     if( i_cmd == 0x00 )
1556     {
1557         printf( "ReSuME %d", pi_code[7] );
1558     }
1559     else if( ( i_cmd & 0x06) == 0x02 )
1560     {    /* XX01Y */
1561         printf ("Link to %s cell ", ( i_cmd & 0x01 ) ? "prev" : "next");
1562     }
1563     else
1564     {
1565         printf( "advanced (0x%02x) ", i_cmd );
1566     }
1567     printf(" } ");
1568 }
1569
1570 static void IfoJmp( ifo_command_t com )
1571 {
1572
1573     printf ("jmp ");
1574
1575     switch( com.i_sub_cmd )
1576     {
1577     case 0x01:
1578         printf( "Exit" );
1579         break;
1580     case 0x02:
1581         printf( "VTS 0x%02x", OP_VAL_8(3) );
1582         break;
1583     case 0x03:
1584         printf( "This VTS Title 0x%02x", OP_VAL_8(3) );
1585         break;
1586     case 0x05:
1587         printf( "This VTS Title 0x%02x Part 0x%04x",
1588                             OP_VAL_8(3),
1589                             OP_VAL_8(0)<<8|OP_VAL_8(1));
1590         break;
1591     case 0x06:
1592 #if 0
1593             printf ("in SystemSpace ");
1594             switch (OP_VAL_8(3)>>4) {
1595                 case 0x00:
1596                     printf ("to play first PGC");
1597                     break;
1598                 case 0x01: {
1599                     printf ("to menu \"%s\"", decode_menuname (OP_VAL_8(3)));
1600                 }
1601                     break;
1602                 case 0x02:
1603                     printf ("to VTS 0x%02x and TTN 0x%02x", OP_VAL_8(1), OP_VAL_8(2));
1604                     break;
1605                 case 0x03:
1606                     printf ("to VMGM PGC number 0x%02x", OP_VAL_8(0)<<8 | OP_VAL_8(1));
1607                     break;
1608                 case 0x08:
1609                     printf ("vts 0x%02x lu 0x%02x menu \"%s\"", OP_VAL_8(2), OP_VAL_8(1), decode_menuname (OP_VAL_8(3)));
1610                     break;
1611 #else
1612         switch( OP_VAL_8(3)>>6 )
1613         {
1614         case 0x00:
1615             printf( "to play first PGC" );
1616             break;
1617         case 0x01:
1618             printf( "to VMG title menu (?)" );
1619             break;
1620         case 0x02:
1621             printf( "vts 0x%02x lu 0x%02x menu \"%s\"",
1622                             OP_VAL_8(2),
1623                             OP_VAL_8(1),
1624                             IfoMenuName( OP_VAL_8(3)&0xF ) );
1625             break;
1626         case 0x03:
1627             printf( "vmg pgc 0x%04x (?)", ( OP_VAL_8(0)<<8) | OP_VAL_8(1) );
1628             break;
1629 #endif
1630         }
1631         break;
1632     case 0x08:
1633 #if 0
1634             switch(OP_VAL_8(3)>>4) {
1635                 case 0x00:
1636                     printf ("system first pgc");
1637                     break;
1638                 case 0x01:
1639                     printf ("system title menu");
1640                     break;
1641                 case 0x02:
1642                     printf ("system menu \"%s\"", decode_menuname (OP_VAL_8(3)));
1643                     break;
1644                 case 0x03:
1645                     printf ("system vmg pgc %02x ????", OP_VAL_8(0)<<8|OP_VAL_8(1));
1646                     break;
1647                 case 0x08:
1648                     printf ("system lu 0x%02x menu \"%s\"", OP_VAL_8(2), decode_menuname (OP_VAL_8(3)));
1649                     break;
1650                 case 0x0c:
1651                     printf ("system vmg pgc 0x%02x", OP_VAL_8(0)<<8|OP_VAL_8(1));
1652                     break;
1653             }
1654 #else
1655         /* OP_VAL_8(2) is number of cell */
1656         /* it is processed BEFORE switch */
1657         /* under some conditions, it is ignored */
1658         /* I don't understand exactly what it means */
1659         printf( " ( spec cell 0x%02X ) ", OP_VAL_8(2) );
1660
1661         switch( OP_VAL_8(3)>>6 )
1662         {
1663         case 0:
1664             printf( "to FP PGC" );
1665             break;
1666         case 1:
1667             printf( "to VMG root menu (?)" );
1668             break;
1669         case 2:
1670             printf( "to VTS menu \"%s\" (?)",
1671                     IfoMenuName(OP_VAL_8(3)&0xF) );
1672             break;
1673         case 3:
1674             printf( "vmg pgc 0x%02x (?)", (OP_VAL_8(0)<<8)|OP_VAL_8(1) );
1675             break;
1676         }
1677 #endif
1678         break;
1679     }
1680 }
1681
1682 static void IfoLnk( ifo_command_t com )
1683 {
1684     uint16_t i_button = OP_VAL_8(4)>>2;
1685
1686     printf ("lnk to ");
1687
1688     switch( com.i_sub_cmd )
1689     {
1690     case 0x01:
1691         IfoAdvanced( &OP_VAL_8(4) );
1692         break;
1693
1694     case 0x04:
1695         printf( "PGC 0x%02x", OP_VAL_16(2) );
1696         break;
1697
1698     case 0x05:
1699         printf( "PTT 0x%02x", OP_VAL_16(2) );
1700         break;
1701
1702     case 0x06:
1703         printf( "Program 0x%02x this PGC", OP_VAL_8(5) );
1704         break;
1705
1706     case 0x07:
1707         printf( "Cell 0x%02x this PGC", OP_VAL_8(5) );
1708         break;
1709     default:
1710         return;
1711     }
1712
1713     if( i_button )
1714     {
1715         printf( ", Highlight 0x%02x", OP_VAL_8(4)>>2 );
1716     }
1717
1718 }
1719
1720 void IfoSetSystem( ifo_command_t com )
1721 {
1722     switch( com.i_cmd )
1723     {
1724     case 1: {
1725         int i;
1726
1727         for( i=1; i<=3; i++ )
1728         {
1729             if( OP_VAL_8(i)&0x80 )
1730             {
1731                 if( com.i_direct )
1732                 {
1733                     printf ("s[%s] = 0x%02x;", ifo_reg[i], OP_VAL_8(i)&0xf);
1734                 }
1735                 else
1736                 {
1737                     printf ("s[%s] = r[0x%02x];", ifo_reg[i], OP_VAL_8(i)&0xf);
1738                 }
1739             }
1740         }
1741 #if 0
1742                 if(op->direct) {
1743                         if(OP_VAL_8(1]&0x80)
1744                                 printf ("s[%s] = 0x%02x;", reg_name[1], OP_VAL_8(1]&0xf);
1745                         if(OP_VAL_8(2)&0x80)
1746 /*DENT: lwhat about 0x7f here ??? */
1747                                 printf ("s[%s] = 0x%02x;", reg_name[2], OP_VAL_8(2)&0x7f);
1748                         if(OP_VAL_8(3)&0x80)
1749                                 printf ("s[%s] = 0x%02x;", reg_name[3], OP_VAL_8(3)&0xf);
1750                 } else {
1751                         if(OP_VAL_8(1)&0x80)
1752                                 printf ("s[%s] = r[0x%02x];", reg_name[1], OP_VAL_8(1)&0xf);
1753                         if(OP_VAL_8(2)&0x80)
1754                                 printf ("s[%s] = r[0x%02x];", reg_name[2], OP_VAL_8(2)&0xf);
1755                         if(OP_VAL_8(3)&0x80)
1756                                 printf ("s[%s] = r[0x%02x];", reg_name[3], OP_VAL_8(3)&0xf);
1757                 }
1758 #endif
1759         }
1760         break;
1761     case 2:
1762         if( com.i_direct )
1763         {
1764             printf( "s[%s] = 0x%02x", ifo_reg[9], OP_VAL_16(0) );
1765         }
1766         else
1767         {
1768             printf( "s[%s] = r[0x%02x]", ifo_reg[9], OP_VAL_8(1)&0x0f );
1769         }
1770
1771         printf( "s[%s] = (s[%s]&0x7FFF)|0x%02x",
1772                         ifo_reg[10], ifo_reg[10], OP_VAL_16(1)&0x8000);
1773         break;
1774     case 3:
1775         if( com.i_direct )
1776         {
1777             printf( "r[0x%02x] = 0x%02x", OP_VAL_8(3)&0x0f, OP_VAL_16(0) );
1778         }
1779         else
1780         {
1781             printf ("r[r[0x%02x]] = r[0x%02x]",
1782                                     OP_VAL_8(3)&0x0f, OP_VAL_8(1)&0x0f);
1783         }
1784         break;
1785     case 4:
1786         /*actually only bits 00011100 00011100 are set */
1787         if( com.i_direct )
1788         {
1789             printf ("s[%s] = 0x%02x", ifo_reg[11], OP_VAL_16(1));
1790         }
1791         else
1792         {
1793             printf ("s[%s] = r[0x%02x]", ifo_reg[11], OP_VAL_8(3)&0x0f );
1794         }
1795         break;
1796     case 6:
1797         /*actually, */
1798         /*s[%s]=(r[%s]&0x3FF) | (0x%02x << 0xA); */
1799         /*but it is way too ugly */
1800         if( com.i_direct )
1801         {
1802             printf( "s[%s] = 0x%02x", ifo_reg[8], OP_VAL_8(2)>>2 );
1803         }
1804         else
1805         {
1806             printf( "s[%s] = r[0x%02x]", ifo_reg[8], OP_VAL_8(3)&0x0f );
1807         }
1808         break;
1809     default:
1810         printf ("unknown");
1811     }
1812 }
1813
1814 static void IfoSet( ifo_command_t com )
1815 {
1816     IfoRegister( OP_VAL_16(0), 0 );
1817     printf( " %s ", IfoMath( com.i_cmd ) );
1818     IfoRegister( OP_VAL_16(1), com.i_direct );
1819 }
1820
1821 /*****************************************************************************
1822  * CommandRead : translates the command strings in ifo into command
1823  * structures.
1824  *****************************************************************************/
1825 void CommandRead( ifo_command_t com )
1826 {
1827     uint8_t * pi_code = (uint8_t*)(&com);
1828
1829     switch( com.i_type )
1830     {
1831     /* Goto */
1832     case 0:
1833         /* Main command */
1834         if( !pi_code[1] )
1835         {
1836             printf( "NOP\n" );
1837         }
1838         else
1839         {
1840             if( com.i_cmp )
1841             {
1842                 printf ("if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
1843                                              ifo_cmp[com.i_cmp]);
1844                 IfoRegister (OP_VAL_16(1), com.i_dir_cmp);
1845                 printf (") ");
1846             }
1847
1848             /* Sub command */
1849             switch( com.i_sub_cmd )
1850             {
1851             case 1:
1852                 printf( "goto Line 0x%02x", OP_VAL_16(2) );
1853                 break;
1854
1855             case 2:
1856                 printf( "stop VM" );
1857                 break;
1858
1859             case 3:
1860                 printf( "Set Parental Level To %s and goto Line 0x%02x",
1861                                      ifo_parental[OP_VAL_8(4)&0x7],
1862                                      OP_VAL_8(5) );
1863                 break;
1864
1865             default:
1866                 printf( "Illegal" );
1867                 break;
1868             }
1869         }
1870         break;
1871
1872     /* Lnk */
1873     case 1:
1874         /* Main command */
1875         if( !pi_code[1] )
1876         {
1877             printf( "NOP\n" );
1878         }
1879         else
1880         {
1881             if( com.i_direct )
1882             {
1883                 if( com.i_cmp )
1884                 {
1885                     printf( "if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f,
1886                                                  ifo_cmp[com.i_cmp] );
1887                     IfoRegister( OP_VAL_8(5), 0 );
1888                     printf( ") " );
1889                 }
1890
1891                 /* Sub command */
1892                 IfoJmp( com );
1893             }
1894             else
1895             {
1896                 if( com.i_cmp )
1897                 {
1898                     printf( "if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
1899                                                  ifo_cmp[com.i_cmp] );
1900                     IfoRegister( OP_VAL_16(1), com.i_dir_cmp );
1901                     printf( ") " );
1902                 }
1903
1904                 /* Sub command */
1905                 IfoLnk( com );
1906             }
1907         }
1908         break;
1909
1910     /* SetSystem */
1911     case 2:
1912         if( !pi_code[1] )
1913         {
1914             IfoSetSystem( com );
1915         }
1916         else if( com.i_cmp && !com.i_sub_cmd )
1917         {
1918             printf ("if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f, ifo_cmp[com.i_cmp]);
1919             IfoRegister( OP_VAL_8(5), 0 );
1920             printf (") ");
1921             IfoSetSystem( com );
1922         }
1923         else if( !com.i_cmp && com.i_sub_cmd )
1924         {
1925             printf( "if (" );
1926             IfoSetSystem( com );
1927             printf( ") " );
1928             IfoLnk( com );
1929         }
1930         else
1931         {
1932             printf("nop");
1933         }
1934         break;
1935
1936     /* Set */
1937     case 3:
1938           if( ! pi_code[1] )
1939         {
1940             IfoSet( com );
1941         }
1942         else if( com.i_cmp && !com.i_sub_cmd )
1943         {
1944             printf ("if (r[0x%02x] %s ", OP_VAL_8(0)&0x0f, ifo_cmp[com.i_cmp]);
1945             IfoRegister( OP_VAL_16(2), com.i_dir_cmp );
1946             printf (") ");
1947             IfoSet( com );
1948         }
1949         else if( !com.i_cmp && com.i_sub_cmd )
1950         {
1951             printf ("if (");
1952             IfoSet( com );
1953             printf (") ");
1954             IfoLnk( com );
1955         }
1956         else
1957         {
1958             printf( "nop" );
1959         }
1960         break;
1961
1962     /*
1963      * math command on r[opcode[1]] and
1964      * direct?be2me_16(OP_VAL_8(0)):reg[OP_VAL_8(1)] is executed
1965      * ( unless command is swap; then r[opcode[1]] and r[OP_VAL_8(1)]
1966      * are swapped )
1967      * boolean operation cmp on r[opcode[1]] and
1968      * dir_cmp?be2me_16(OP_VAL_8(1)[1]):reg[OP_VAL_8(3)] is executed
1969      * on true result, buttons(c[6], c[7]) is called
1970      * problem is 'what is buttons()'
1971      */
1972     case 4:
1973         printf( "r[0x%X] ", pi_code[1] );
1974         printf( " %s ", IfoMath( com.i_cmd ) );
1975         if( com.i_cmd == 2 )
1976         {
1977             printf( "r[0x%X] ", OP_VAL_8(1) );
1978         }
1979         else
1980         {
1981             IfoRegister( OP_VAL_16(0), com.i_direct );
1982         }
1983         printf("; ");
1984
1985         printf( "if ( r[%d] %s ", pi_code[1], ifo_cmp[com.i_cmp] );
1986         IfoRegister( OP_VAL_8(1), com.i_dir_cmp );
1987         printf( " )  then {" );
1988         IfoAdvanced( &OP_VAL_8(4) );
1989         printf( "}" );
1990         break;
1991
1992     /*
1993      * opposite to case 4: boolean, math and buttons.
1994      */
1995     case 5:
1996     case 6:
1997         printf("if (");
1998
1999         if( !com.i_direct && com.i_dir_cmp )
2000         {
2001             printf( "0x%X", OP_VAL_16(1) );
2002         }
2003         else
2004         {
2005             IfoRegister( OP_VAL_8(3), 0 );
2006             if( OP_VAL_8(3)&0x80 )
2007             {
2008                 printf( "s[%s]", ifo_reg[OP_VAL_8(3)&0x1F] );
2009             }
2010             else
2011             {
2012                 printf( "r[0x%X]", OP_VAL_8(3)&0x1F);
2013                     /* 0x1F is either not a mistake, */
2014                     /* or Microsoft programmer's mistake!!! */
2015             }
2016         }
2017
2018         printf( " %s r[0x%X] ", ifo_cmp[com.i_cmp],
2019                                 com.i_direct ? OP_VAL_8(2) : OP_VAL_8(1) );
2020            printf( " )  then {" );
2021         printf( "r[0x%X] ", pi_code[1] & 0xF );
2022         printf( " %s ", IfoMath( com.i_cmd ) );
2023
2024         if( com.i_cmd == 0x02 )    /* swap */
2025         {
2026             printf("r[0x%X] ", OP_VAL_8(0)&0x1F);
2027         }
2028         else
2029         {
2030             if( com.i_direct )
2031             {
2032                 printf( "0x%X", OP_VAL_16(0) );
2033             }
2034             else
2035             {
2036                 if( OP_VAL_8(0) & 0x80 )
2037                 {
2038                     printf("s[%s]", ifo_reg[OP_VAL_8(0) & 0x1F] );
2039                 }
2040                 else
2041                 {
2042                     printf("r[0x%X]", OP_VAL_8(0) & 0x1F );
2043                 }
2044             }
2045         }
2046
2047         printf("; ");
2048         IfoAdvanced( &OP_VAL_8(4) );
2049         printf("}");
2050
2051         break;
2052
2053     default:
2054         printf( "Unknown Command\n" );
2055         break;
2056     }
2057
2058     return;
2059 }
2060
2061 /*****************************************************************************
2062  * CommandPrint : print in clear text (I hope so !) what a command does
2063  *****************************************************************************/
2064 void CommandPrint( ifo_t ifo )
2065 {
2066     return;
2067 }
2068
2069 #endif
2070
2071 /*****************************************************************************
2072  * ReadByte and so
2073  *****************************************************************************/
2074 static uint8_t* FillBuffer( ifo_t* p_ifo, uint8_t* p_buf, int i_pos )
2075 {
2076     p_ifo->i_pos = dvdcss_seek( p_ifo->dvdhandle, i_pos, DVDCSS_NOFLAGS );
2077     dvdcss_read( p_ifo->dvdhandle, p_buf, 1, DVDCSS_NOFLAGS );
2078
2079     return p_buf;
2080 }
2081
2082 static void ReadBytes( ifo_t* p_ifo, uint8_t* p_buf, uint8_t** pp_tmp,
2083                                      uint8_t* pi_dest, int i_nb )
2084 {
2085     if( i_nb > DVD_LB_SIZE )
2086     {
2087 #if 0
2088         intf_Err( p_input, "excessive ReadBytes call (%i)", i_nb );
2089 #endif
2090     }
2091
2092     if( *pp_tmp + i_nb >= p_buf + DVD_LB_SIZE )
2093     {
2094         int i_spare = (int)( (p_buf + DVD_LB_SIZE) - *pp_tmp );
2095
2096         /* Copy the bytes remaining in the current buffer */
2097         memcpy( pi_dest, *pp_tmp, i_spare );
2098         pi_dest += i_spare;
2099         i_nb -= i_spare;
2100
2101         /* Load the next buffer */
2102         *pp_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_pos + 1 );
2103     }
2104
2105     memcpy( pi_dest, *pp_tmp, i_nb );
2106     *pp_tmp += i_nb;
2107
2108     return;
2109 }
2110
2111 static void DumpBytes( ifo_t* p_ifo, uint8_t* p_buf, uint8_t** pp_tmp, int i_nb )
2112 {
2113     if( i_nb > DVD_LB_SIZE )
2114     {
2115 #if 0
2116         intf_Err( p_input, "excessive DumpBytes call (%i)", i_nb );
2117 #endif
2118     }
2119
2120     *pp_tmp += i_nb;
2121
2122     if( *pp_tmp >= p_buf + DVD_LB_SIZE )
2123     {
2124         /* If we went too far, load the next buffer */
2125         *pp_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_pos + 1 )
2126                    + (int)( (*pp_tmp) - (p_buf + DVD_LB_SIZE) );
2127     }
2128
2129     return;
2130 }
2131
2132 #define ADDBYTE \
2133     if( *pp_tmp >= p_buf + DVD_LB_SIZE ) \
2134     { \
2135         *pp_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_pos + 1 ); \
2136     } \
2137     i_ret <<= 8; i_ret |= **pp_tmp; (*pp_tmp)++;
2138
2139 static uint8_t ReadByte( ifo_t * p_ifo, uint8_t* p_buf, uint8_t** pp_tmp )
2140 {
2141     uint8_t i_ret = 0;
2142     ADDBYTE;
2143     return i_ret;
2144 }
2145
2146 static uint16_t ReadWord( ifo_t * p_ifo, uint8_t* p_buf, uint8_t** pp_tmp )
2147 {
2148     uint16_t i_ret = 0;
2149     ADDBYTE; ADDBYTE;
2150     return i_ret;
2151 }
2152
2153 static uint32_t ReadDouble( ifo_t * p_ifo, uint8_t* p_buf, uint8_t** pp_tmp )
2154 {
2155     uint32_t i_ret = 0;
2156     ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE;
2157     return i_ret;
2158 }
2159
2160 static uint64_t ReadQuad( ifo_t * p_ifo, uint8_t* p_buf, uint8_t** pp_tmp )
2161 {
2162     uint64_t i_ret = 0;
2163     ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE;
2164     return i_ret;
2165 }
2166