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