* ./modules/audio_output/oss.c: compilation fixes.
[vlc.git] / 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.2 2002/08/08 00:35:10 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 #elif defined( _MSC_VER ) && defined( _WIN32 )
41 #   include <io.h>
42 #endif
43
44 #include <string.h>
45 #include <fcntl.h>
46
47 #ifdef GOD_DAMN_DMCA
48 #   include "dvdcss.h"
49 #else
50 #   include <dvdcss/dvdcss.h>
51 #endif
52
53 #include "dvd.h"
54 #include "ifo.h"
55 #include "udf.h"
56
57 /*****************************************************************************
58  * Local prototypes
59  *****************************************************************************/
60 void            CommandRead     ( command_desc_t );
61 static int      ReadTitle       ( ifo_t * , title_t *, int, int );
62 static int      FreeTitle       ( title_t * );
63 static int      ReadUnitInf     ( ifo_t * , unit_inf_t *, int, int );
64 static int      FreeUnitInf     ( unit_inf_t * );
65 static int      ReadTitleUnit   ( ifo_t * , title_unit_t *, int );
66 static int      FreeTitleUnit   ( title_unit_t * );
67 static int      ReadVobuMap     ( ifo_t * , vobu_map_t *, int );
68 static int      FreeVobuMap     ( vobu_map_t * );
69 static int      ReadCellInf     ( ifo_t * , cell_inf_t *, int );
70 static int      FreeCellInf     ( cell_inf_t * );
71 static int      FreeTitleSet    ( vts_t * );
72
73 static u8*      FillBuffer      ( ifo_t *, u8 *, int );
74 static u8       ReadByte        ( ifo_t *, u8 *, u8 ** );
75 static void     ReadBytes       ( ifo_t *, u8 *, u8 **, u8 *, int );
76 static void     DumpBytes       ( ifo_t *, u8 *, u8 **, int );
77 static u16      ReadWord        ( ifo_t *, u8 *, u8 ** );
78 static u32      ReadDouble      ( ifo_t *, u8 *, u8 ** );
79 static u64      ReadQuad        ( ifo_t *, u8 *, u8 ** );
80
81 /*
82  * IFO Management.
83  */
84
85 /*****************************************************************************
86  * IfoCreate : Creates an ifo structure and prepares for parsing directly
87  *             on DVD device
88  *****************************************************************************/
89 int IfoCreate( thread_dvd_data_t * p_dvd )
90 {
91     p_dvd->p_ifo = malloc( sizeof(ifo_t) );
92     if( p_dvd->p_ifo == NULL )
93     {
94         return -1;
95     }
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     u8                  p_buf[DVD_LB_SIZE];
109     u8*                 p_tmp;
110     u64                 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, (u8*)(&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(u16) );
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         u64             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(u32) );
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, (u8*)(&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, (u8*)(&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     u8          p_buf[DVD_LB_SIZE];
435     u8 *        p_tmp;
436     int         i_off;
437     int         i_start;
438     u64         i_temp;
439     u16         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, (u8*)(&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: %llx\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, (u8*)(&i_temp), 6 );
566         i_temp = hton64( i_temp ) >> 16;
567         /*fprintf( stderr, "Subpic %d: %llx\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(u32) );
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         u8      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(u32) );
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(u32) );
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                 free( p_ifo->vmg.parental_inf.p_parental_mask[i].ppi_mask[j] );
845             }
846         }
847
848         free( p_ifo->vmg.parental_inf.p_parental_mask );
849         free( p_ifo->vmg.parental_inf.p_parental_desc );
850     }
851
852     if( p_ifo->vmg.manager_inf.i_title_unit_start_sector )
853     {
854         FreeTitleUnit( &p_ifo->vmg.title_unit );
855     }
856
857     if( p_ifo->vmg.manager_inf.i_title_inf_start_sector )
858     {
859         free( p_ifo->vmg.title_inf.p_attr );
860     }
861
862     FreeTitle( &p_ifo->vmg.title );
863
864     free( p_ifo );
865
866     return;
867 }
868
869 /*
870  * Function common to Video Manager and Video Title set Processing
871  */
872
873 /*****************************************************************************
874  * ReadTitle : Fills the title structure.
875  *****************************************************************************
876  * Titles are logical stream units that correspond to a whole inside the dvd.
877  * Several title can point to the same part of the physical DVD, and give
878  * map to different anglesfor instance.
879  *****************************************************************************/
880 static int ReadTitle( ifo_t * p_ifo, title_t * p_title, int i_block, int i_bytes )
881 {
882     u8          p_buf[DVD_LB_SIZE];
883     u8 *        p_tmp;
884     int         i_start;
885     u16         i_audio;
886     u32         i_spu;
887     int         i;
888
889     p_tmp = FillBuffer( p_ifo, p_buf, i_block ) + i_bytes;
890
891     i_start = p_ifo->i_pos;
892
893     /*fprintf( stderr, "PGC @ %d + %d\n", p_ifo->i_pos, i_bytes ); */
894
895     DumpBytes( p_ifo, p_buf, &p_tmp, 2);
896     p_title->i_chapter_nb = ReadByte( p_ifo, p_buf, &p_tmp );
897     p_title->i_cell_nb = ReadByte( p_ifo, p_buf, &p_tmp );
898     /*fprintf( stderr, "title: Prg: %d Cell: %d\n",p_title->i_chapter_nb,p_title->i_cell_nb  ); */
899     p_title->i_play_time = ReadDouble( p_ifo, p_buf, &p_tmp );
900     p_title->i_prohibited_user_op = ReadDouble( p_ifo, p_buf, &p_tmp );
901
902     for( i = 0 ; i < 8 ; i++ )
903     {
904         i_audio = ReadWord( p_ifo, p_buf, &p_tmp );
905         p_title->pi_audio_status[i].i_foo = i_audio & 0xff;
906         i_audio >>= 8;
907         p_title->pi_audio_status[i].i_position = i_audio & 0x07;
908         i_audio >>= 7;
909         p_title->pi_audio_status[i].i_available = i_audio;
910     }
911
912     for( i = 0 ; i < 32 ; i++ )
913     {
914         i_spu = ReadDouble( p_ifo, p_buf, &p_tmp );
915         p_title->pi_spu_status[i].i_position_pan = i_spu & 0x1f;
916         i_spu >>= 8;
917         p_title->pi_spu_status[i].i_position_letter = i_spu & 0x1f;
918         i_spu >>= 8;
919         p_title->pi_spu_status[i].i_position_wide = i_spu & 0x1f;
920         i_spu >>= 8;
921         p_title->pi_spu_status[i].i_position_43 = i_spu & 0x1f;
922         i_spu >>= 7;
923         p_title->pi_spu_status[i].i_available = i_spu;
924     }
925
926     p_title->i_next_title_num = ReadWord( p_ifo, p_buf, &p_tmp );
927     p_title->i_prev_title_num = ReadWord( p_ifo, p_buf, &p_tmp );
928     p_title->i_go_up_title_num = ReadWord( p_ifo, p_buf, &p_tmp );
929     p_title->i_still_time = ReadByte( p_ifo, p_buf, &p_tmp );
930     p_title->i_play_mode = ReadByte( p_ifo, p_buf, &p_tmp );
931
932     for( i = 0 ; i < 16 ; i++ )
933     {
934         /* FIXME : We have to erase the extra bit */
935         p_title->pi_yuv_color[i] = ReadDouble( p_ifo, p_buf, &p_tmp );
936     }
937
938     p_title->i_command_start_byte = ReadWord( p_ifo, p_buf, &p_tmp );
939     p_title->i_chapter_map_start_byte = ReadWord( p_ifo, p_buf, &p_tmp );
940     p_title->i_cell_play_start_byte = ReadWord( p_ifo, p_buf, &p_tmp );
941     p_title->i_cell_pos_start_byte = ReadWord( p_ifo, p_buf, &p_tmp );
942
943     /* parsing of command_t */
944     if( p_title->i_command_start_byte )
945     {
946         p_tmp = FillBuffer( p_ifo, p_buf, i_start +
947                             OFF2LB( p_title->i_command_start_byte + i_bytes ) )
948                  + ( (p_title->i_command_start_byte + i_bytes) & 0x7ff );
949
950         /* header */
951         p_title->command.i_pre_command_nb = ReadWord( p_ifo, p_buf, &p_tmp );
952         p_title->command.i_post_command_nb = ReadWord( p_ifo, p_buf, &p_tmp );
953         p_title->command.i_cell_command_nb = ReadWord( p_ifo, p_buf, &p_tmp );
954         DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
955
956         /* pre-title commands */
957         if( p_title->command.i_pre_command_nb )
958         {
959             p_title->command.p_pre_command =
960                            malloc( p_title->command.i_pre_command_nb
961                                     * sizeof(command_desc_t) );
962
963             if( p_title->command.p_pre_command == NULL )
964             {
965                 return -1;
966             }
967
968             for( i = 0 ; i < p_title->command.i_pre_command_nb ; i++ )
969             {
970                 p_title->command.p_pre_command[i] =
971                                         ReadQuad( p_ifo, p_buf, &p_tmp );
972             }
973         }
974         else
975         {
976             p_title->command.p_pre_command = NULL;
977         }
978
979         /* post-title commands */
980         if( p_title->command.i_post_command_nb )
981         {
982             p_title->command.p_post_command =
983                         malloc( p_title->command.i_post_command_nb
984                                  * sizeof(command_desc_t) );
985
986             if( p_title->command.p_post_command == NULL )
987             {
988                 return -1;
989             }
990
991             for( i = 0 ; i < p_title->command.i_post_command_nb ; i++ )
992             {
993                 p_title->command.p_post_command[i] =
994                                         ReadQuad( p_ifo, p_buf, &p_tmp );
995             }
996         }
997         else
998         {
999             p_title->command.p_post_command = NULL;
1000         }
1001
1002         /* cell commands */
1003         if( p_title->command.i_cell_command_nb )
1004         {
1005             p_title->command.p_cell_command =
1006                         malloc( p_title->command.i_cell_command_nb
1007                                  * sizeof(command_desc_t) );
1008
1009             if( p_title->command.p_cell_command == NULL )
1010             {
1011                 return -1;
1012             }
1013
1014             for( i = 0 ; i < p_title->command.i_cell_command_nb ; i++ )
1015             {
1016                 p_title->command.p_cell_command[i] =
1017                                         ReadQuad( p_ifo, p_buf, &p_tmp );
1018             }
1019         }
1020         else
1021         {
1022             p_title->command.p_cell_command = NULL;
1023         }
1024     }
1025
1026     /* parsing of chapter_map_t: it gives the entry cell for each chapter */
1027     if( p_title->i_chapter_map_start_byte )
1028     {
1029         p_ifo->i_pos = dvdcss_seek( p_ifo->dvdhandle,
1030                OFF2LB( i_start + p_title->i_chapter_map_start_byte ),
1031                DVDCSS_NOFLAGS );
1032         
1033         p_title->chapter_map.pi_start_cell =
1034                     malloc( p_title->i_chapter_nb * sizeof(chapter_map_t) );
1035         
1036         if( p_title->chapter_map.pi_start_cell == NULL )
1037         {
1038             return -1;
1039         }
1040
1041         ReadBytes( p_ifo, p_buf, &p_tmp, p_title->chapter_map.pi_start_cell,
1042                    p_title->i_chapter_nb );
1043     }
1044     else
1045     {
1046         p_title->chapter_map.pi_start_cell = NULL; 
1047     }
1048
1049     /* parsing of cell_play_t */
1050     if( p_title->i_cell_play_start_byte )
1051     {
1052         p_tmp = FillBuffer( p_ifo, p_buf, i_start +
1053                             OFF2LB( p_title->i_cell_play_start_byte+i_bytes ) )
1054                  + ( (p_title->i_cell_play_start_byte+i_bytes) & 0x7ff );
1055
1056         p_title->p_cell_play = malloc( p_title->i_cell_nb
1057                                         * sizeof(cell_play_t) );
1058     
1059         if( p_title->p_cell_play == NULL )
1060         {
1061             return -1;
1062         }
1063
1064         for( i = 0 ; i < p_title->i_cell_nb ; i++ )
1065         {
1066 #define PLAY p_title->p_cell_play[i]
1067             PLAY.i_category = ReadWord( p_ifo, p_buf, &p_tmp );
1068             PLAY.i_still_time = ReadByte( p_ifo, p_buf, &p_tmp );
1069             PLAY.i_command_nb = ReadByte( p_ifo, p_buf, &p_tmp );
1070             PLAY.i_play_time = ReadDouble( p_ifo, p_buf, &p_tmp );
1071             PLAY.i_first_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
1072             PLAY.i_first_ilvu_vobu_esector = ReadDouble( p_ifo, p_buf, &p_tmp );
1073             PLAY.i_last_vobu_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
1074             PLAY.i_last_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
1075 #undef PLAY
1076         }
1077     }
1078
1079     /* Parsing of cell_pos_t */
1080     if( p_title->i_cell_pos_start_byte )
1081     {
1082         p_tmp = FillBuffer( p_ifo, p_buf, i_start +
1083                             OFF2LB( p_title->i_cell_pos_start_byte + i_bytes ) )
1084                  + ( (p_title->i_cell_pos_start_byte + i_bytes) & 0x7ff );
1085
1086         p_title->p_cell_pos = malloc( p_title->i_cell_nb
1087                                        * sizeof(cell_pos_t) );
1088
1089         if( p_title->p_cell_pos == NULL )
1090         {
1091             return -1;
1092         }
1093
1094         for( i = 0 ; i < p_title->i_cell_nb ; i++ )
1095         {
1096             p_title->p_cell_pos[i].i_vob_id = ReadWord( p_ifo, p_buf, &p_tmp );
1097             DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
1098             p_title->p_cell_pos[i].i_cell_id = ReadByte( p_ifo, p_buf, &p_tmp );
1099         }
1100     } 
1101
1102     return 0;
1103 }
1104
1105 /*****************************************************************************
1106  * FreeTitle: frees alla structure allocated by a call to ReadTitle
1107  *****************************************************************************/
1108 static int FreeTitle( title_t * p_title )
1109 {
1110     if( p_title->i_command_start_byte )
1111     {
1112         if( p_title->command.i_pre_command_nb )
1113         {
1114             free( p_title->command.p_pre_command );
1115         }
1116
1117         if( p_title->command.i_post_command_nb )
1118         {
1119             free( p_title->command.p_post_command );
1120         }
1121
1122         if( p_title->command.i_cell_command_nb )
1123         {
1124             free( p_title->command.p_cell_command );
1125         }
1126     }
1127
1128     if( p_title->i_chapter_map_start_byte )
1129     {
1130         free( p_title->chapter_map.pi_start_cell );
1131     }
1132
1133     if( p_title->i_cell_play_start_byte )
1134     {
1135         free( p_title->p_cell_play );
1136     }
1137
1138     if( p_title->i_cell_pos_start_byte )
1139     {
1140         free( p_title->p_cell_pos );
1141     }
1142
1143     return 0;
1144 }
1145
1146 /*****************************************************************************
1147  * ReadUnitInf : Fills Menu Language Unit Table/ PGC Info Table
1148  *****************************************************************************/
1149 static int ReadUnitInf( ifo_t * p_ifo, unit_inf_t * p_unit_inf,
1150                         int i_block, int i_bytes )
1151 {
1152     u8              p_buf[DVD_LB_SIZE];
1153     u8 *            p_tmp;
1154     int             i_start;
1155     int             i;
1156
1157     p_tmp = FillBuffer( p_ifo, p_buf, i_block ) + i_bytes;
1158
1159     i_start = p_ifo->i_pos;
1160     /*fprintf( stderr, "Unit\n" ); */
1161
1162     p_unit_inf->i_title_nb = ReadWord( p_ifo, p_buf, &p_tmp );
1163     /*fprintf( stderr, "Unit nb: %d\n", p_unit_inf->i_title_nb ); */
1164     DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
1165     p_unit_inf->i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
1166
1167     p_unit_inf->p_title =
1168             malloc( p_unit_inf->i_title_nb * sizeof(unit_title_t) );
1169     if( p_unit_inf->p_title == NULL )
1170     {
1171         return -1;
1172     }
1173
1174     for( i = 0 ; i < p_unit_inf->i_title_nb ; i++ )
1175     {
1176 #define TITLE p_unit_inf->p_title[i]
1177         TITLE.i_category_mask = ReadByte( p_ifo, p_buf, &p_tmp );
1178         TITLE.i_category = ReadByte( p_ifo, p_buf, &p_tmp );
1179         /*fprintf( stderr, "cat mask %d: %x cat %x\n", i, TITLE.i_category_mask, TITLE.i_category ); */
1180         TITLE.i_parental_mask = ReadWord( p_ifo, p_buf, &p_tmp );
1181         TITLE.i_title_start_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
1182 #undef TITLE
1183     }
1184
1185     for( i = 0 ; i < p_unit_inf->i_title_nb ; i++ )
1186     {
1187         /*fprintf( stderr, "Unit: PGC %d @ %d\n", i, p_ifo->i_pos ); */
1188         ReadTitle( p_ifo, &p_unit_inf->p_title[i].title, i_start +
1189             OFF2LB( p_unit_inf->p_title[i].i_title_start_byte + i_bytes ),
1190           (p_unit_inf->p_title[i].i_title_start_byte+i_bytes) & 0x7ff );
1191     }
1192
1193     return 0;
1194 }
1195
1196 /*****************************************************************************
1197  * FreeUnitInf : frees a structure allocated by ReadUnit
1198  *****************************************************************************/ 
1199 static int FreeUnitInf( unit_inf_t * p_unit_inf )
1200 {
1201     int i;
1202     
1203     if( p_unit_inf->p_title != NULL )
1204     {
1205         for( i = 0 ; i < p_unit_inf->i_title_nb ; i++ )
1206         {
1207             FreeTitle( &p_unit_inf->p_title[i].title );
1208         }
1209             
1210         free( p_unit_inf->p_title );
1211     }
1212
1213     return 0;
1214 }
1215
1216
1217 /*****************************************************************************
1218  * ReadTitleUnit: Fills the Title Unit structure.
1219  *****************************************************************************/
1220 static int ReadTitleUnit( ifo_t * p_ifo, title_unit_t * p_title_unit,
1221                           int i_block )
1222 {
1223     u8              p_buf[DVD_LB_SIZE];
1224     u8 *            p_tmp;
1225     int             i;
1226     int             i_start;
1227
1228     p_tmp = FillBuffer( p_ifo, p_buf, i_block );
1229     i_start = p_ifo->i_pos;
1230     /*fprintf( stderr, "Unit Table\n" ); */
1231
1232     p_title_unit->i_unit_nb = ReadWord( p_ifo, p_buf, &p_tmp );
1233     DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
1234     p_title_unit->i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
1235
1236     /*fprintf(stderr, "Unit: nb %d last %d\n", p_title_unit->i_unit_nb, p_title_unit->i_last_byte ); */
1237
1238     p_title_unit->p_unit = malloc( p_title_unit->i_unit_nb * sizeof(unit_t) );
1239     if( p_title_unit->p_unit == NULL )
1240     {
1241         return -1;
1242     }
1243
1244     for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ )
1245     {
1246         /*ReadBytes( p_ifo, p_buf, &p_tmp, p_title_unit->p_unit[i].ps_lang_code, 2 ); */
1247         p_title_unit->p_unit[i].i_lang_code = ReadWord( p_ifo, p_buf, &p_tmp );
1248         /*fprintf( stderr, "lang %d %x\n", i,p_title_unit->p_unit[i].i_lang_code ); */
1249         DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
1250         p_title_unit->p_unit[i].i_existence_mask =
1251                                            ReadByte( p_ifo, p_buf, &p_tmp );
1252         p_title_unit->p_unit[i].i_unit_inf_start_byte =
1253                                            ReadDouble( p_ifo, p_buf, &p_tmp );
1254     }
1255
1256     p_title_unit->p_unit_inf =
1257                 malloc( p_title_unit->i_unit_nb * sizeof(unit_inf_t) );
1258     if( p_title_unit->p_unit_inf == NULL )
1259     {
1260         return -1;
1261     }
1262
1263     for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ )
1264     {
1265         ReadUnitInf( p_ifo, &p_title_unit->p_unit_inf[i], i_start +
1266                       OFF2LB( p_title_unit->p_unit[i].i_unit_inf_start_byte ),
1267                      p_title_unit->p_unit[i].i_unit_inf_start_byte & 0x7ff );
1268     }
1269
1270     return 0;
1271 }
1272
1273 /*****************************************************************************
1274  * FreeTitleUnit: frees a structure allocateed by ReadTitleUnit
1275  *****************************************************************************/
1276 static int FreeTitleUnit( title_unit_t * p_title_unit )
1277 {
1278     int     i;
1279
1280     if( p_title_unit->p_unit_inf != NULL )
1281     {
1282         for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ )
1283         {
1284             FreeUnitInf( &p_title_unit->p_unit_inf[i] );
1285         }
1286
1287         free( p_title_unit->p_unit_inf );
1288     }
1289
1290     return 0;
1291 }
1292
1293 /*****************************************************************************
1294  * ReadCellInf : Fills the Cell Information structure.
1295  *****************************************************************************/
1296 static int ReadCellInf( ifo_t * p_ifo, cell_inf_t * p_cell_inf, int i_block )
1297 {
1298     u8              p_buf[DVD_LB_SIZE];
1299     u8 *            p_tmp;
1300     int             i_start;
1301     int             i;
1302
1303     p_tmp = FillBuffer( p_ifo, p_buf, i_block );
1304     i_start = p_ifo->i_pos;
1305 /*    fprintf( stderr, "CELL ADD\n" ); */
1306
1307     p_cell_inf->i_vob_nb = ReadWord( p_ifo, p_buf, &p_tmp );
1308     DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
1309     p_cell_inf->i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
1310
1311     p_cell_inf->i_cell_nb = (p_cell_inf->i_last_byte + 1/* - 7*/) / sizeof(cell_map_t);
1312
1313 /*    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 );
1314 */
1315     p_cell_inf->p_cell_map =
1316                 malloc( p_cell_inf->i_cell_nb *sizeof(cell_map_t) );
1317     if( p_cell_inf->p_cell_map == NULL )
1318     {
1319         return -1;
1320     }
1321
1322     for( i = 0 ; i < p_cell_inf->i_cell_nb ; i++ )
1323     {
1324 #define MAP p_cell_inf->p_cell_map[i]
1325         MAP.i_vob_id = ReadWord( p_ifo, p_buf, &p_tmp );
1326         MAP.i_cell_id = ReadByte( p_ifo, p_buf, &p_tmp );
1327         DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
1328         MAP.i_first_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
1329 /*        fprintf(stderr, "sector[%d] %d (%d)\n", i,ntohl(*(u32*)(p_tmp)), p_ifo->i_pos);*/
1330         MAP.i_last_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
1331 #undef MAP
1332     }
1333     
1334     return 0;
1335 }
1336
1337 /*****************************************************************************
1338  * FreeCellInf : frees structures allocated by ReadCellInf
1339  *****************************************************************************/
1340 static int FreeCellInf( cell_inf_t * p_cell_inf )
1341 {
1342     free( p_cell_inf->p_cell_map );
1343
1344     return 0;
1345 }
1346
1347 /*****************************************************************************
1348  * ReadVobuMap : Fills the VOBU Map structure.
1349  *****************************************************************************/
1350 static int ReadVobuMap( ifo_t * p_ifo, vobu_map_t * p_vobu_map, int i_block )
1351 {
1352     u8                  p_buf[DVD_LB_SIZE];
1353     u8 *                p_tmp;
1354     int                 i_start;
1355     int                 i, i_max;
1356     
1357     p_tmp = FillBuffer( p_ifo, p_buf, i_block );
1358     i_start = p_ifo->i_pos;
1359     /*fprintf( stderr, "VOBU ADMAP\n" ); */
1360
1361     p_vobu_map->i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
1362     i_max = ( i_start + p_vobu_map->i_last_byte + 1 - p_ifo->i_pos )
1363              / sizeof(u32);
1364
1365     p_vobu_map->pi_vobu_start_sector = malloc( i_max * sizeof(u32) );
1366     if( p_vobu_map->pi_vobu_start_sector == NULL )
1367     {
1368         return -1;
1369     }
1370
1371     for( i = 0 ; i < i_max ; i++ )
1372     {
1373         p_vobu_map->pi_vobu_start_sector[i] = ReadDouble( p_ifo, p_buf, &p_tmp );
1374     }
1375
1376     return 0;
1377 }
1378
1379 /*****************************************************************************
1380  * FreeVobuMap: frees structures allocated by ReadVobuMap
1381  *****************************************************************************/
1382 static int FreeVobuMap( vobu_map_t * p_vobu_map )
1383 {
1384     free( p_vobu_map->pi_vobu_start_sector );
1385
1386     return 0;
1387 }
1388
1389 /*
1390  * IFO virtual machine : a set of commands that give the
1391  * interactive behaviour of the dvd
1392  */
1393 #if 0
1394
1395 #define OP_VAL_16(i) (ntoh16( com.data.pi_16[i]))
1396 #define OP_VAL_8(i) ((com.data.pi_8[i]))
1397
1398 static char ifo_reg[][80]=
1399 {
1400     "Menu_Language_Code",
1401     "Audio_Stream_#",
1402     "SubPicture_Stream_#",
1403     "Angle_#",
1404     "VTS_#",
1405     "VTS_Title_#",
1406     "PGC_#",
1407     "PTT_#",
1408     "Highlighted_Button_#",
1409     "Nav_Timer",
1410     "TimedPGC",
1411     "Karaoke_audio_mixing_mode",
1412     "Parental_mgmt_country_code",
1413     "Parental_Level",
1414     "Player_Video_Cfg",
1415     "Player_Audio_Cfg",
1416     "Audio_language_code_setting",
1417     "Audio_language_extension_code",
1418     "SPU_language_code_setting",
1419     "SPU_language_extension_code",
1420     "?Player_Regional_Code",
1421     "Reserved_21",
1422     "Reserved_22",
1423     "Reserved_23"
1424 };
1425
1426 static char * IfoMath( char val )
1427 {
1428     static char math_op[][10] =
1429     {
1430         "none",
1431         "=", 
1432         "<->",    /* swap */
1433         "+=",
1434         "-=",
1435         "*=",
1436         "/=",
1437         "%=",
1438         "rnd",    /* rnd */
1439         "&=",
1440         "|=",
1441         "^=",
1442         "??",    /* invalid */
1443         "??",    /* invalid */
1444         "??",    /* invalid */
1445         "??"    /* invalid */
1446     };
1447
1448     return (char *) math_op[val & 0x0f];
1449 }
1450
1451
1452 char ifo_cmp[][10] =
1453 {
1454     "none",
1455     "&&",
1456     "==",
1457     "!=",
1458     ">=",
1459     ">",
1460     "<",
1461     "<="
1462 };
1463
1464 char ifo_parental[][10] =
1465 {
1466     "0",
1467     "G",
1468     "2",
1469     "PG",
1470     "PG-13",
1471     "5",
1472     "R",
1473     "NC-17"
1474 };
1475
1476 char ifo_menu_id[][80] =
1477 {
1478     "-0-",
1479     "-1-",
1480     "Title (VTS menu)",
1481     "Root",
1482     "Sub-Picture",
1483     "Audio",
1484     "Angle",
1485     "Part of Title",
1486 };
1487
1488 char * IfoMenuName( char index )
1489 {
1490     return ifo_menu_id[index&0x07];
1491 }
1492
1493 static void IfoRegister( u16 i_data, u8 i_direct)
1494 {
1495     if( i_direct )
1496     {
1497         if( 0/*isalpha( i_data >> 8 & 0xff )*/ )
1498         {
1499             printf("'%c%c'", i_data>>8&0xff, i_data&0xff);
1500         }
1501         else
1502         {
1503             printf("0x%02x", i_data);
1504         }
1505     }
1506     else
1507     {
1508         if( i_data & 0x80 )
1509         {
1510             i_data &= 0x1f;
1511
1512             if( i_data > 0x17 )
1513             {
1514                 printf("s[ILL]");
1515             }
1516             else
1517             {
1518                 printf("s[%s]", ifo_reg[i_data]);
1519             }
1520         }
1521         else
1522         {
1523             i_data &= 0x1f;
1524
1525             if( i_data > 0xf )
1526             {
1527                 printf("r[ILL]");
1528             }
1529             else
1530             {
1531                 printf("r[0x%02x]", i_data);
1532             }
1533         }
1534     }
1535 }
1536
1537 static void IfoAdvanced( u8 *pi_code )
1538 {
1539     u8      i_cmd = pi_code[0];
1540
1541     printf(" { ");
1542
1543     if( pi_code[1]>>2 )
1544     {
1545         printf( " Highlight button %d; ", pi_code[1]>>2 );
1546     }
1547
1548     if( i_cmd == 0xff )
1549     {
1550         printf( " Illegal " );
1551     }
1552
1553     if( i_cmd == 0x00 )
1554     {
1555         printf( "ReSuME %d", pi_code[7] );
1556     }
1557     else if( ( i_cmd & 0x06) == 0x02 )
1558     {    /* XX01Y */
1559         printf ("Link to %s cell ", ( i_cmd & 0x01 ) ? "prev" : "next");
1560     }
1561     else
1562     {
1563         printf( "advanced (0x%02x) ", i_cmd );
1564     }
1565     printf(" } ");
1566 }
1567
1568 static void IfoJmp( ifo_command_t com )
1569 {
1570
1571     printf ("jmp ");
1572
1573     switch( com.i_sub_cmd )
1574     {
1575     case 0x01:
1576         printf( "Exit" );
1577         break;
1578     case 0x02:
1579         printf( "VTS 0x%02x", OP_VAL_8(3) );
1580         break;
1581     case 0x03:
1582         printf( "This VTS Title 0x%02x", OP_VAL_8(3) );
1583         break;
1584     case 0x05:
1585         printf( "This VTS Title 0x%02x Part 0x%04x",
1586                             OP_VAL_8(3),
1587                             OP_VAL_8(0)<<8|OP_VAL_8(1));
1588         break;
1589     case 0x06:
1590 #if 0
1591             printf ("in SystemSpace ");
1592             switch (OP_VAL_8(3)>>4) {
1593                 case 0x00:
1594                     printf ("to play first PGC");
1595                     break;
1596                 case 0x01: {
1597                     printf ("to menu \"%s\"", decode_menuname (OP_VAL_8(3)));
1598                 }
1599                     break;
1600                 case 0x02:
1601                     printf ("to VTS 0x%02x and TTN 0x%02x", OP_VAL_8(1), OP_VAL_8(2));
1602                     break;
1603                 case 0x03:
1604                     printf ("to VMGM PGC number 0x%02x", OP_VAL_8(0)<<8 | OP_VAL_8(1));
1605                     break;
1606                 case 0x08:
1607                     printf ("vts 0x%02x lu 0x%02x menu \"%s\"", OP_VAL_8(2), OP_VAL_8(1), decode_menuname (OP_VAL_8(3)));
1608                     break;
1609 #else
1610         switch( OP_VAL_8(3)>>6 )
1611         {
1612         case 0x00:
1613             printf( "to play first PGC" );
1614             break;                
1615         case 0x01:
1616             printf( "to VMG title menu (?)" );
1617             break;
1618         case 0x02:
1619             printf( "vts 0x%02x lu 0x%02x menu \"%s\"",
1620                             OP_VAL_8(2),
1621                             OP_VAL_8(1),
1622                             IfoMenuName( OP_VAL_8(3)&0xF ) );
1623             break;                
1624         case 0x03:
1625             printf( "vmg pgc 0x%04x (?)", ( OP_VAL_8(0)<<8) | OP_VAL_8(1) );
1626             break;
1627 #endif
1628         }
1629         break;
1630     case 0x08:
1631 #if 0
1632             switch(OP_VAL_8(3)>>4) {
1633                 case 0x00:
1634                     printf ("system first pgc");
1635                     break;
1636                 case 0x01:
1637                     printf ("system title menu");
1638                     break;
1639                 case 0x02:
1640                     printf ("system menu \"%s\"", decode_menuname (OP_VAL_8(3)));
1641                     break;
1642                 case 0x03:
1643                     printf ("system vmg pgc %02x ????", OP_VAL_8(0)<<8|OP_VAL_8(1));
1644                     break;
1645                 case 0x08:
1646                     printf ("system lu 0x%02x menu \"%s\"", OP_VAL_8(2), decode_menuname (OP_VAL_8(3)));
1647                     break;
1648                 case 0x0c:
1649                     printf ("system vmg pgc 0x%02x", OP_VAL_8(0)<<8|OP_VAL_8(1));
1650                     break;
1651             }
1652 #else
1653         /* OP_VAL_8(2) is number of cell */
1654         /* it is processed BEFORE switch */
1655         /* under some conditions, it is ignored */
1656         /* I don't understand exactly what it means */
1657         printf( " ( spec cell 0x%02X ) ", OP_VAL_8(2) ); 
1658
1659         switch( OP_VAL_8(3)>>6 )
1660         {
1661         case 0:
1662             printf( "to FP PGC" );
1663             break;
1664         case 1:
1665             printf( "to VMG root menu (?)" );
1666             break;
1667         case 2:
1668             printf( "to VTS menu \"%s\" (?)",
1669                     IfoMenuName(OP_VAL_8(3)&0xF) );
1670             break; 
1671         case 3:
1672             printf( "vmg pgc 0x%02x (?)", (OP_VAL_8(0)<<8)|OP_VAL_8(1) );
1673             break;
1674         }    
1675 #endif
1676         break;
1677     }
1678 }
1679
1680 static void IfoLnk( ifo_command_t com )
1681 {
1682     u16     i_button=OP_VAL_8(4)>>2;
1683
1684     printf ("lnk to ");
1685
1686     switch( com.i_sub_cmd )
1687     {
1688     case 0x01:
1689         IfoAdvanced( &OP_VAL_8(4) );
1690         break;
1691
1692     case 0x04:
1693         printf( "PGC 0x%02x", OP_VAL_16(2) );
1694         break; 
1695
1696     case 0x05:
1697         printf( "PTT 0x%02x", OP_VAL_16(2) );
1698         break; 
1699
1700     case 0x06:
1701         printf( "Program 0x%02x this PGC", OP_VAL_8(5) );
1702         break;
1703
1704     case 0x07:
1705         printf( "Cell 0x%02x this PGC", OP_VAL_8(5) );
1706         break;
1707     default:
1708         return;
1709     }
1710
1711     if( i_button )
1712     {
1713         printf( ", Highlight 0x%02x", OP_VAL_8(4)>>2 );
1714     }
1715             
1716 }
1717
1718 void IfoSetSystem( ifo_command_t com )
1719 {
1720     switch( com.i_cmd )
1721     {
1722     case 1: {
1723         int i;
1724
1725         for( i=1; i<=3; i++ )
1726         {
1727             if( OP_VAL_8(i)&0x80 )
1728             {
1729                 if( com.i_direct )
1730                 {
1731                     printf ("s[%s] = 0x%02x;", ifo_reg[i], OP_VAL_8(i)&0xf);
1732                 }
1733                 else
1734                 {
1735                     printf ("s[%s] = r[0x%02x];", ifo_reg[i], OP_VAL_8(i)&0xf);
1736                 }
1737             }
1738         }
1739 #if 0
1740                 if(op->direct) {
1741                         if(OP_VAL_8(1]&0x80)
1742                                 printf ("s[%s] = 0x%02x;", reg_name[1], OP_VAL_8(1]&0xf);
1743                         if(OP_VAL_8(2)&0x80)
1744 /*DENT: lwhat about 0x7f here ??? */
1745                                 printf ("s[%s] = 0x%02x;", reg_name[2], OP_VAL_8(2)&0x7f);
1746                         if(OP_VAL_8(3)&0x80)
1747                                 printf ("s[%s] = 0x%02x;", reg_name[3], OP_VAL_8(3)&0xf);
1748                 } else {
1749                         if(OP_VAL_8(1)&0x80)
1750                                 printf ("s[%s] = r[0x%02x];", reg_name[1], OP_VAL_8(1)&0xf);
1751                         if(OP_VAL_8(2)&0x80)
1752                                 printf ("s[%s] = r[0x%02x];", reg_name[2], OP_VAL_8(2)&0xf);
1753                         if(OP_VAL_8(3)&0x80)
1754                                 printf ("s[%s] = r[0x%02x];", reg_name[3], OP_VAL_8(3)&0xf);
1755                 }
1756 #endif
1757         }
1758         break;
1759     case 2:
1760         if( com.i_direct )
1761         {
1762             printf( "s[%s] = 0x%02x", ifo_reg[9], OP_VAL_16(0) );
1763         }
1764         else
1765         {
1766             printf( "s[%s] = r[0x%02x]", ifo_reg[9], OP_VAL_8(1)&0x0f );
1767         }
1768
1769         printf( "s[%s] = (s[%s]&0x7FFF)|0x%02x", 
1770                         ifo_reg[10], ifo_reg[10], OP_VAL_16(1)&0x8000);
1771         break;
1772     case 3:
1773         if( com.i_direct )
1774         {
1775             printf( "r[0x%02x] = 0x%02x", OP_VAL_8(3)&0x0f, OP_VAL_16(0) );
1776         }
1777         else
1778         {
1779             printf ("r[r[0x%02x]] = r[0x%02x]",
1780                                     OP_VAL_8(3)&0x0f, OP_VAL_8(1)&0x0f);
1781         }
1782         break;
1783     case 4:
1784         /*actually only bits 00011100 00011100 are set */
1785         if( com.i_direct )
1786         {
1787             printf ("s[%s] = 0x%02x", ifo_reg[11], OP_VAL_16(1));
1788         }
1789         else
1790         {
1791             printf ("s[%s] = r[0x%02x]", ifo_reg[11], OP_VAL_8(3)&0x0f );
1792         }
1793         break;
1794     case 6:
1795         /*actually, */
1796         /*s[%s]=(r[%s]&0x3FF) | (0x%02x << 0xA); */
1797         /*but it is way too ugly */
1798         if( com.i_direct )
1799         {
1800             printf( "s[%s] = 0x%02x", ifo_reg[8], OP_VAL_8(2)>>2 );
1801         }
1802         else
1803         {
1804             printf( "s[%s] = r[0x%02x]", ifo_reg[8], OP_VAL_8(3)&0x0f );
1805         }
1806         break;
1807     default:
1808         printf ("unknown");
1809     }
1810 }
1811
1812 static void IfoSet( ifo_command_t com )
1813 {
1814     IfoRegister( OP_VAL_16(0), 0 );
1815     printf( " %s ", IfoMath( com.i_cmd ) );
1816     IfoRegister( OP_VAL_16(1), com.i_direct );
1817 }
1818
1819 /*****************************************************************************
1820  * CommandRead : translates the command strings in ifo into command
1821  * structures.
1822  *****************************************************************************/
1823 void CommandRead( ifo_command_t com )
1824 {
1825     u8*     pi_code = (u8*)(&com);
1826
1827     switch( com.i_type )
1828     {
1829     /* Goto */
1830     case 0:
1831         /* Main command */
1832         if( !pi_code[1] )
1833         {
1834             printf( "NOP\n" );
1835         }
1836         else
1837         {
1838             if( com.i_cmp )
1839             {
1840                 printf ("if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
1841                                              ifo_cmp[com.i_cmp]);
1842                 IfoRegister (OP_VAL_16(1), com.i_dir_cmp);
1843                 printf (") ");
1844             }
1845         
1846             /* Sub command */
1847             switch( com.i_sub_cmd )
1848             {
1849             case 1:
1850                 printf( "goto Line 0x%02x", OP_VAL_16(2) );
1851                 break;
1852         
1853             case 2:
1854                 printf( "stop VM" );
1855                 break;
1856         
1857             case 3:
1858                 printf( "Set Parental Level To %s and goto Line 0x%02x",
1859                                      ifo_parental[OP_VAL_8(4)&0x7],
1860                                      OP_VAL_8(5) );
1861                 break;
1862         
1863             default:
1864                 printf( "Illegal" );
1865                 break;
1866             }
1867         }
1868         break;
1869
1870     /* Lnk */
1871     case 1:
1872         /* Main command */
1873         if( !pi_code[1] )
1874         {
1875             printf( "NOP\n" );
1876         }
1877         else
1878         {
1879             if( com.i_direct )
1880             {
1881                 if( com.i_cmp )
1882                 {
1883                     printf( "if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f,
1884                                                  ifo_cmp[com.i_cmp] );
1885                     IfoRegister( OP_VAL_8(5), 0 );
1886                     printf( ") " );
1887                 }
1888
1889                 /* Sub command */
1890                 IfoJmp( com );
1891             }
1892             else
1893             {    
1894                 if( com.i_cmp )
1895                 {
1896                     printf( "if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
1897                                                  ifo_cmp[com.i_cmp] );
1898                     IfoRegister( OP_VAL_16(1), com.i_dir_cmp );
1899                     printf( ") " );
1900                 }
1901
1902                 /* Sub command */
1903                 IfoLnk( com );
1904             }
1905         }
1906         break;
1907
1908     /* SetSystem */
1909     case 2:
1910         if( !pi_code[1] )
1911         {
1912             IfoSetSystem( com );
1913         }
1914         else if( com.i_cmp && !com.i_sub_cmd )
1915         {
1916             printf ("if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f, ifo_cmp[com.i_cmp]);
1917             IfoRegister( OP_VAL_8(5), 0 );
1918             printf (") ");
1919             IfoSetSystem( com );
1920         }
1921         else if( !com.i_cmp && com.i_sub_cmd )
1922         {
1923             printf( "if (" );
1924             IfoSetSystem( com );
1925             printf( ") " );
1926             IfoLnk( com );
1927         }
1928         else
1929         {
1930             printf("nop");
1931         }
1932         break;
1933
1934     /* Set */
1935     case 3:
1936           if( ! pi_code[1] )
1937         {
1938             IfoSet( com );
1939         }
1940         else if( com.i_cmp && !com.i_sub_cmd )
1941         {
1942             printf ("if (r[0x%02x] %s ", OP_VAL_8(0)&0x0f, ifo_cmp[com.i_cmp]);
1943             IfoRegister( OP_VAL_16(2), com.i_dir_cmp );
1944             printf (") ");
1945             IfoSet( com );
1946         }
1947         else if( !com.i_cmp && com.i_sub_cmd )
1948         {
1949             printf ("if (");
1950             IfoSet( com );
1951             printf (") ");
1952             IfoLnk( com );
1953         }
1954         else
1955         {
1956             printf( "nop" );
1957         }
1958         break;
1959
1960     /* 
1961      * math command on r[opcode[1]] and
1962      * direct?be2me_16(OP_VAL_8(0)):reg[OP_VAL_8(1)] is executed
1963      * ( unless command is swap; then r[opcode[1]] and r[OP_VAL_8(1)]
1964      * are swapped )
1965      * boolean operation cmp on r[opcode[1]] and
1966      * dir_cmp?be2me_16(OP_VAL_8(1)[1]):reg[OP_VAL_8(3)] is executed
1967      * on true result, buttons(c[6], c[7]) is called
1968      * problem is 'what is buttons()'
1969      */
1970     case 4:
1971         printf( "r[0x%X] ", pi_code[1] );
1972         printf( " %s ", IfoMath( com.i_cmd ) );
1973         if( com.i_cmd == 2 )
1974         {
1975             printf( "r[0x%X] ", OP_VAL_8(1) );
1976         }
1977         else
1978         {
1979             IfoRegister( OP_VAL_16(0), com.i_direct );
1980         }
1981         printf("; ");
1982
1983         printf( "if ( r[%d] %s ", pi_code[1], ifo_cmp[com.i_cmp] );
1984         IfoRegister( OP_VAL_8(1), com.i_dir_cmp );
1985         printf( " )  then {" );
1986         IfoAdvanced( &OP_VAL_8(4) );
1987         printf( "}" );
1988         break;
1989
1990     /*
1991      * opposite to case 4: boolean, math and buttons.
1992      */
1993     case 5:
1994     case 6:
1995         printf("if (");
1996
1997         if( !com.i_direct && com.i_dir_cmp )
1998         {
1999             printf( "0x%X", OP_VAL_16(1) );
2000         }
2001         else
2002         {
2003             IfoRegister( OP_VAL_8(3), 0 );
2004             if( OP_VAL_8(3)&0x80 )
2005             {
2006                 printf( "s[%s]", ifo_reg[OP_VAL_8(3)&0x1F] );
2007             }
2008             else
2009             {
2010                 printf( "r[0x%X]", OP_VAL_8(3)&0x1F);
2011                     /* 0x1F is either not a mistake, */
2012                     /* or Microsoft programmer's mistake!!! */
2013             }
2014         }
2015
2016         printf( " %s r[0x%X] ", ifo_cmp[com.i_cmp],
2017                                 com.i_direct ? OP_VAL_8(2) : OP_VAL_8(1) );
2018            printf( " )  then {" );
2019         printf( "r[0x%X] ", pi_code[1] & 0xF );
2020         printf( " %s ", IfoMath( com.i_cmd ) );
2021
2022         if( com.i_cmd == 0x02 )    /* swap */
2023         {
2024             printf("r[0x%X] ", OP_VAL_8(0)&0x1F);
2025         }
2026         else
2027         {
2028             if( com.i_direct )
2029             {
2030                 printf( "0x%X", OP_VAL_16(0) );
2031             }
2032             else
2033             {
2034                 if( OP_VAL_8(0) & 0x80 )
2035                 {
2036                     printf("s[%s]", ifo_reg[OP_VAL_8(0) & 0x1F] );
2037                 }
2038                 else
2039                 {
2040                     printf("r[0x%X]", OP_VAL_8(0) & 0x1F );
2041                 }
2042             }
2043         }
2044
2045         printf("; ");
2046         IfoAdvanced( &OP_VAL_8(4) );
2047         printf("}");
2048
2049         break;
2050
2051     default:
2052         printf( "Unknown Command\n" );
2053         break;
2054     }
2055
2056     return;
2057 }
2058
2059 /*****************************************************************************
2060  * CommandPrint : print in clear text (I hope so !) what a command does
2061  *****************************************************************************/
2062 void CommandPrint( ifo_t ifo )
2063 {
2064     return;
2065 }
2066
2067 #endif
2068
2069 /*****************************************************************************
2070  * ReadByte and so
2071  *****************************************************************************/
2072 static u8* FillBuffer( ifo_t* p_ifo, u8* p_buf, int i_pos )
2073 {
2074     p_ifo->i_pos = dvdcss_seek( p_ifo->dvdhandle, i_pos, DVDCSS_NOFLAGS );
2075     dvdcss_read( p_ifo->dvdhandle, p_buf, 1, DVDCSS_NOFLAGS );
2076
2077     return p_buf;
2078 }
2079
2080 static void ReadBytes( ifo_t* p_ifo, u8* p_buf, u8** pp_tmp,
2081                                      u8* pi_dest, int i_nb )
2082 {
2083     if( i_nb > DVD_LB_SIZE )
2084     {
2085 #if 0
2086         intf_Err( p_input, "excessive ReadBytes call (%i)", i_nb );
2087 #endif
2088     }
2089
2090     if( *pp_tmp + i_nb >= p_buf + DVD_LB_SIZE )
2091     {
2092         int i_spare = (int)( (p_buf + DVD_LB_SIZE) - *pp_tmp );
2093
2094         /* Copy the bytes remaining in the current buffer */
2095         memcpy( pi_dest, *pp_tmp, i_spare );
2096         pi_dest += i_spare;
2097         i_nb -= i_spare;
2098
2099         /* Load the next buffer */
2100         *pp_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_pos + 1 );
2101     }
2102
2103     memcpy( pi_dest, *pp_tmp, i_nb );
2104     *pp_tmp += i_nb;
2105
2106     return;
2107 }
2108
2109 static void DumpBytes( ifo_t* p_ifo, u8* p_buf, u8** pp_tmp, int i_nb )
2110 {
2111     if( i_nb > DVD_LB_SIZE )
2112     {
2113 #if 0
2114         intf_Err( p_input, "excessive DumpBytes call (%i)", i_nb );
2115 #endif
2116     }
2117
2118     *pp_tmp += i_nb;
2119
2120     if( *pp_tmp >= p_buf + DVD_LB_SIZE )
2121     {
2122         /* If we went too far, load the next buffer */
2123         *pp_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_pos + 1 )
2124                    + (int)( (*pp_tmp) - (p_buf + DVD_LB_SIZE) );
2125     }
2126
2127     return;
2128 }
2129
2130 #define ADDBYTE \
2131     if( *pp_tmp >= p_buf + DVD_LB_SIZE ) \
2132     { \
2133         *pp_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_pos + 1 ); \
2134     } \
2135     i_ret <<= 8; i_ret |= **pp_tmp; (*pp_tmp)++;
2136
2137 static u8 ReadByte( ifo_t * p_ifo, u8* p_buf, u8** pp_tmp )
2138 {
2139     u8     i_ret = 0;
2140     ADDBYTE;
2141     return i_ret;
2142 }
2143
2144 static u16 ReadWord( ifo_t * p_ifo, u8* p_buf, u8** pp_tmp )
2145 {
2146     u16    i_ret = 0;
2147     ADDBYTE; ADDBYTE;
2148     return i_ret;
2149 }
2150
2151 static u32 ReadDouble( ifo_t * p_ifo, u8* p_buf, u8** pp_tmp )
2152 {
2153     u32    i_ret = 0;
2154     ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE;
2155     return i_ret;
2156 }
2157
2158 static u64 ReadQuad( ifo_t * p_ifo, u8* p_buf, u8** pp_tmp )
2159 {
2160     u64    i_ret = 0;
2161     ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE;
2162     return i_ret;
2163 }
2164