]> git.sesse.net Git - vlc/blob - plugins/dvd/dvd_ifo.c
56491d8d91dbd546090a9e505207e869d9c24cf1
[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.39 2001/11/07 03:37:27 stef 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                DVDCSS_NOFLAGS );
1052         
1053         p_title->chapter_map.pi_start_cell =
1054                     malloc( p_title->i_chapter_nb * sizeof(chapter_map_t) );
1055         
1056         if( p_title->chapter_map.pi_start_cell == NULL )
1057         {
1058             intf_ErrMsg( "ifo error: out of memory in Read Title" );
1059             return -1;
1060         }
1061
1062         ReadBytes( p_ifo, p_buf, &p_tmp, p_title->chapter_map.pi_start_cell,
1063                    p_title->i_chapter_nb );
1064     }
1065     else
1066     {
1067         p_title->chapter_map.pi_start_cell = NULL; 
1068     }
1069
1070     /* parsing of cell_play_t */
1071     if( p_title->i_cell_play_start_byte )
1072     {
1073         p_tmp = FillBuffer( p_ifo, p_buf, i_start +
1074                             OFF2LB( p_title->i_cell_play_start_byte+i_bytes ) )
1075                  + ( (p_title->i_cell_play_start_byte+i_bytes) & 0x7ff );
1076
1077         p_title->p_cell_play = malloc( p_title->i_cell_nb
1078                                         * sizeof(cell_play_t) );
1079     
1080         if( p_title->p_cell_play == NULL )
1081         {
1082             intf_ErrMsg( "ifo error: out of memory in ReadTitle" );
1083             return -1;
1084         }
1085
1086         for( i = 0 ; i < p_title->i_cell_nb ; i++ )
1087         {
1088 #define PLAY p_title->p_cell_play[i]
1089             PLAY.i_category = ReadWord( p_ifo, p_buf, &p_tmp );
1090             PLAY.i_still_time = ReadByte( p_ifo, p_buf, &p_tmp );
1091             PLAY.i_command_nb = ReadByte( p_ifo, p_buf, &p_tmp );
1092             PLAY.i_play_time = ReadDouble( p_ifo, p_buf, &p_tmp );
1093             PLAY.i_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
1094             PLAY.i_first_ilvu_vobu_esector = ReadDouble( p_ifo, p_buf, &p_tmp );
1095             PLAY.i_last_vobu_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
1096             PLAY.i_end_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
1097 #undef PLAY
1098         }
1099     }
1100
1101     /* Parsing of cell_pos_t */
1102     if( p_title->i_cell_pos_start_byte )
1103     {
1104         p_tmp = FillBuffer( p_ifo, p_buf, i_start +
1105                             OFF2LB( p_title->i_cell_pos_start_byte + i_bytes ) )
1106                  + ( (p_title->i_cell_pos_start_byte + i_bytes) & 0x7ff );
1107
1108         p_title->p_cell_pos = malloc( p_title->i_cell_nb
1109                                        * sizeof(cell_pos_t) );
1110
1111         if( p_title->p_cell_pos == NULL )
1112         {
1113             intf_ErrMsg( "ifo error: out of memory" );
1114             return -1;
1115         }
1116
1117         for( i = 0 ; i < p_title->i_cell_nb ; i++ )
1118         {
1119             p_title->p_cell_pos[i].i_vob_id = ReadWord( p_ifo, p_buf, &p_tmp );
1120             DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
1121             p_title->p_cell_pos[i].i_cell_id = ReadByte( p_ifo, p_buf, &p_tmp );
1122         }
1123     } 
1124
1125     return 0;
1126 }
1127
1128 /*****************************************************************************
1129  * FreeTitle: frees alla structure allocated by a call to ReadTitle
1130  *****************************************************************************/
1131 static int FreeTitle( title_t * p_title )
1132 {
1133     if( p_title->i_command_start_byte )
1134     {
1135         if( p_title->command.i_pre_command_nb )
1136         {
1137             free( p_title->command.p_pre_command );
1138         }
1139
1140         if( p_title->command.i_post_command_nb )
1141         {
1142             free( p_title->command.p_post_command );
1143         }
1144
1145         if( p_title->command.i_cell_command_nb )
1146         {
1147             free( p_title->command.p_cell_command );
1148         }
1149     }
1150
1151     if( p_title->i_chapter_map_start_byte )
1152     {
1153         free( p_title->chapter_map.pi_start_cell );
1154     }
1155
1156     if( p_title->i_cell_play_start_byte )
1157     {
1158         free( p_title->p_cell_play );
1159     }
1160
1161     if( p_title->i_cell_pos_start_byte )
1162     {
1163         free( p_title->p_cell_pos );
1164     }
1165
1166     return 0;
1167 }
1168
1169 /*****************************************************************************
1170  * ReadUnitInf : Fills Menu Language Unit Table/ PGC Info Table
1171  *****************************************************************************/
1172 static int ReadUnitInf( ifo_t * p_ifo, unit_inf_t * p_unit_inf,
1173                         int i_block, int i_bytes )
1174 {
1175     u8              p_buf[DVD_LB_SIZE];
1176     u8 *            p_tmp;
1177     int             i_start;
1178     int             i;
1179
1180     p_tmp = FillBuffer( p_ifo, p_buf, i_block ) + i_bytes;
1181
1182     i_start = p_ifo->i_pos;
1183     //fprintf( stderr, "Unit\n" );
1184
1185     p_unit_inf->i_title_nb = ReadWord( p_ifo, p_buf, &p_tmp );
1186     //fprintf( stderr, "Unit nb: %d\n", p_unit_inf->i_title_nb );
1187     DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
1188     p_unit_inf->i_end_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
1189
1190     p_unit_inf->p_title =
1191             malloc( p_unit_inf->i_title_nb * sizeof(unit_title_t) );
1192     if( p_unit_inf->p_title == NULL )
1193     {
1194         intf_ErrMsg( "ifo error: out of memory in ReadUnit" );
1195         return -1;
1196     }
1197
1198     for( i = 0 ; i < p_unit_inf->i_title_nb ; i++ )
1199     {
1200 #define TITLE p_unit_inf->p_title[i]
1201         TITLE.i_category_mask = ReadByte( p_ifo, p_buf, &p_tmp );
1202         TITLE.i_category = ReadByte( p_ifo, p_buf, &p_tmp );
1203         //fprintf( stderr, "cat mask %d: %x cat %x\n", i, TITLE.i_category_mask, TITLE.i_category );
1204         TITLE.i_parental_mask = ReadWord( p_ifo, p_buf, &p_tmp );
1205         TITLE.i_title_start_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
1206 #undef TITLE
1207     }
1208
1209     for( i = 0 ; i < p_unit_inf->i_title_nb ; i++ )
1210     {
1211         //fprintf( stderr, "Unit: PGC %d @ %d\n", i, p_ifo->i_pos );
1212         ReadTitle( p_ifo, &p_unit_inf->p_title[i].title, i_start +
1213             OFF2LB( p_unit_inf->p_title[i].i_title_start_byte + i_bytes ),
1214           (p_unit_inf->p_title[i].i_title_start_byte+i_bytes) & 0x7ff );
1215     }
1216
1217     return 0;
1218 }
1219
1220 /*****************************************************************************
1221  * FreeUnitInf : frees a structure allocated by ReadUnit
1222  *****************************************************************************/ 
1223 static int FreeUnitInf( unit_inf_t * p_unit_inf )
1224 {
1225     int i;
1226     
1227     if( p_unit_inf->p_title != NULL )
1228     {
1229         for( i = 0 ; i < p_unit_inf->i_title_nb ; i++ )
1230         {
1231             FreeTitle( &p_unit_inf->p_title[i].title );
1232         }
1233             
1234         free( p_unit_inf->p_title );
1235     }
1236
1237     return 0;
1238 }
1239
1240
1241 /*****************************************************************************
1242  * ReadTitleUnit: Fills the Title Unit structure.
1243  *****************************************************************************/
1244 static int ReadTitleUnit( ifo_t * p_ifo, title_unit_t * p_title_unit,
1245                           int i_block )
1246 {
1247     u8              p_buf[DVD_LB_SIZE];
1248     u8 *            p_tmp;
1249     int             i;
1250     int             i_start;
1251
1252     p_tmp = FillBuffer( p_ifo, p_buf, i_block );
1253     i_start = p_ifo->i_pos;
1254     //fprintf( stderr, "Unit Table\n" );
1255
1256     p_title_unit->i_unit_nb = ReadWord( p_ifo, p_buf, &p_tmp );
1257     DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
1258     p_title_unit->i_end_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
1259
1260     //fprintf(stderr, "Unit: nb %d end %d\n", p_title_unit->i_unit_nb, p_title_unit->i_end_byte );
1261
1262     p_title_unit->p_unit = malloc( p_title_unit->i_unit_nb * sizeof(unit_t) );
1263     if( p_title_unit->p_unit == NULL )
1264     {
1265         intf_ErrMsg( "ifo error: out of memory in ReadTitleUnit" );
1266         return -1;
1267     }
1268
1269     for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ )
1270     {
1271         //ReadBytes( p_ifo, p_buf, &p_tmp, p_title_unit->p_unit[i].ps_lang_code, 2 );
1272         p_title_unit->p_unit[i].i_lang_code = ReadWord( p_ifo, p_buf, &p_tmp );
1273         //fprintf( stderr, "lang %d %x\n", i,p_title_unit->p_unit[i].i_lang_code );
1274         DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
1275         p_title_unit->p_unit[i].i_existence_mask =
1276                                            ReadByte( p_ifo, p_buf, &p_tmp );
1277         p_title_unit->p_unit[i].i_unit_inf_start_byte =
1278                                            ReadDouble( p_ifo, p_buf, &p_tmp );
1279     }
1280
1281     p_title_unit->p_unit_inf =
1282                 malloc( p_title_unit->i_unit_nb * sizeof(unit_inf_t) );
1283     if( p_title_unit->p_unit_inf == NULL )
1284     {
1285         intf_ErrMsg( "ifo error: out of memory in ReadTitleUnit" );
1286         return -1;
1287     }
1288
1289     for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ )
1290     {
1291         ReadUnitInf( p_ifo, &p_title_unit->p_unit_inf[i], i_start +
1292                       OFF2LB( p_title_unit->p_unit[i].i_unit_inf_start_byte ),
1293                      p_title_unit->p_unit[i].i_unit_inf_start_byte & 0x7ff );
1294     }
1295
1296     return 0;
1297 }
1298
1299 /*****************************************************************************
1300  * FreeTitleUnit: frees a structure allocateed by ReadTitleUnit
1301  *****************************************************************************/
1302 static int FreeTitleUnit( title_unit_t * p_title_unit )
1303 {
1304     int     i;
1305
1306     if( p_title_unit->p_unit_inf != NULL )
1307     {
1308         for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ )
1309         {
1310             FreeUnitInf( &p_title_unit->p_unit_inf[i] );
1311         }
1312
1313         free( p_title_unit->p_unit_inf );
1314     }
1315
1316     return 0;
1317 }
1318
1319 /*****************************************************************************
1320  * ReadCellInf : Fills the Cell Information structure.
1321  *****************************************************************************/
1322 static int ReadCellInf( ifo_t * p_ifo, cell_inf_t * p_cell_inf, int i_block )
1323 {
1324     u8              p_buf[DVD_LB_SIZE];
1325     u8 *            p_tmp;
1326     int             i_start;
1327     int             i;
1328
1329     p_tmp = FillBuffer( p_ifo, p_buf, i_block );
1330     i_start = p_ifo->i_pos;
1331     //fprintf( stderr, "CELL ADD\n" );
1332
1333     p_cell_inf->i_vob_nb = ReadWord( p_ifo, p_buf, &p_tmp );
1334     DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
1335     p_cell_inf->i_end_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
1336
1337     p_cell_inf->i_cell_nb = (p_cell_inf->i_end_byte/* - 7*/) / sizeof(cell_map_t);
1338
1339     //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 );
1340
1341     p_cell_inf->p_cell_map =
1342                 malloc( p_cell_inf->i_cell_nb *sizeof(cell_map_t) );
1343     if( p_cell_inf->p_cell_map == NULL )
1344     {
1345         intf_ErrMsg( "ifo error: out of memory in ReadCellInf" );
1346         return -1;
1347     }
1348
1349     for( i = 0 ; i < p_cell_inf->i_cell_nb ; i++ )
1350     {
1351 #define MAP p_cell_inf->p_cell_map[i]
1352         MAP.i_vob_id = ReadWord( p_ifo, p_buf, &p_tmp );
1353         MAP.i_cell_id = ReadByte( p_ifo, p_buf, &p_tmp );
1354         DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
1355         MAP.i_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
1356         //fprintf(stderr, "sector[%d] %d (%d)\n", i,ntohl(*(u32*)(p_tmp)), p_ifo->i_pos);
1357         MAP.i_end_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
1358 #undef MAP
1359     }
1360     
1361     return 0;
1362 }
1363
1364 /*****************************************************************************
1365  * FreeCellInf : frees structures allocated by ReadCellInf
1366  *****************************************************************************/
1367 static int FreeCellInf( cell_inf_t * p_cell_inf )
1368 {
1369     free( p_cell_inf->p_cell_map );
1370
1371     return 0;
1372 }
1373
1374 /*****************************************************************************
1375  * ReadVobuMap : Fills the VOBU Map structure.
1376  *****************************************************************************/
1377 static int ReadVobuMap( ifo_t * p_ifo, vobu_map_t * p_vobu_map, int i_block )
1378 {
1379     u8                  p_buf[DVD_LB_SIZE];
1380     u8 *                p_tmp;
1381     int                 i_start;
1382     int                 i, i_max;
1383     
1384     p_tmp = FillBuffer( p_ifo, p_buf, i_block );
1385     i_start = p_ifo->i_pos;
1386     //fprintf( stderr, "VOBU ADMAP\n" );
1387
1388     p_vobu_map->i_end_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
1389     i_max = ( i_start + p_vobu_map->i_end_byte + 1 - p_ifo->i_pos )
1390              / sizeof(u32);
1391
1392     p_vobu_map->pi_vobu_start_sector = malloc( i_max * sizeof(u32) );
1393     if( p_vobu_map->pi_vobu_start_sector == NULL )
1394     {
1395         intf_ErrMsg( "ifo error: out of memory in ReadVobuMap" );
1396         return -1;
1397     }
1398
1399     for( i = 0 ; i < i_max ; i++ )
1400     {
1401         p_vobu_map->pi_vobu_start_sector[i] = ReadDouble( p_ifo, p_buf, &p_tmp );
1402     }
1403
1404     return 0;
1405 }
1406
1407 /*****************************************************************************
1408  * FreeVobuMap: frees structures allocated by ReadVobuMap
1409  *****************************************************************************/
1410 static int FreeVobuMap( vobu_map_t * p_vobu_map )
1411 {
1412     free( p_vobu_map->pi_vobu_start_sector );
1413
1414     return 0;
1415 }
1416
1417 /*
1418  * IFO virtual machine : a set of commands that give the
1419  * interactive behaviour of the dvd
1420  */
1421 #if 0
1422
1423 #define OP_VAL_16(i) (ntoh16( com.data.pi_16[i]))
1424 #define OP_VAL_8(i) ((com.data.pi_8[i]))
1425
1426 static char ifo_reg[][80]=
1427 {
1428     "Menu_Language_Code",
1429     "Audio_Stream_#",
1430     "SubPicture_Stream_#",
1431     "Angle_#",
1432     "VTS_#",
1433     "VTS_Title_#",
1434     "PGC_#",
1435     "PTT_#",
1436     "Highlighted_Button_#",
1437     "Nav_Timer",
1438     "TimedPGC",
1439     "Karaoke_audio_mixing_mode",
1440     "Parental_mgmt_country_code",
1441     "Parental_Level",
1442     "Player_Video_Cfg",
1443     "Player_Audio_Cfg",
1444     "Audio_language_code_setting",
1445     "Audio_language_extension_code",
1446     "SPU_language_code_setting",
1447     "SPU_language_extension_code",
1448     "?Player_Regional_Code",
1449     "Reserved_21",
1450     "Reserved_22",
1451     "Reserved_23"
1452 };
1453
1454 static char * IfoMath( char val )
1455 {
1456     static char math_op[][10] =
1457     {
1458         "none",
1459         "=", 
1460         "<->",    // swap
1461         "+=",
1462         "-=",
1463         "*=",
1464         "/=",
1465         "%=",
1466         "rnd",    // rnd
1467         "&=",
1468         "|=",
1469         "^=",
1470         "??",    // invalid
1471         "??",    // invalid
1472         "??",    // invalid
1473         "??"    // invalid
1474     };
1475
1476     return (char *) math_op[val & 0x0f];
1477 }
1478
1479
1480 char ifo_cmp[][10] =
1481 {
1482     "none",
1483     "&&",
1484     "==",
1485     "!=",
1486     ">=",
1487     ">",
1488     "<",
1489     "<="
1490 };
1491
1492 char ifo_parental[][10] =
1493 {
1494     "0",
1495     "G",
1496     "2",
1497     "PG",
1498     "PG-13",
1499     "5",
1500     "R",
1501     "NC-17"
1502 };
1503
1504 char ifo_menu_id[][80] =
1505 {
1506     "-0-",
1507     "-1-",
1508     "Title (VTS menu)",
1509     "Root",
1510     "Sub-Picture",
1511     "Audio",
1512     "Angle",
1513     "Part of Title",
1514 };
1515
1516 char * IfoMenuName( char index )
1517 {
1518     return ifo_menu_id[index&0x07];
1519 }
1520
1521 static void IfoRegister( u16 i_data, u8 i_direct)
1522 {
1523     if( i_direct )
1524     {
1525         if( 0/*isalpha( i_data >> 8 & 0xff )*/ )
1526         {
1527             printf("'%c%c'", i_data>>8&0xff, i_data&0xff);
1528         }
1529         else
1530         {
1531             printf("0x%02x", i_data);
1532         }
1533     }
1534     else
1535     {
1536         if( i_data & 0x80 )
1537         {
1538             i_data &= 0x1f;
1539
1540             if( i_data > 0x17 )
1541             {
1542                 printf("s[ILL]");
1543             }
1544             else
1545             {
1546                 printf("s[%s]", ifo_reg[i_data]);
1547             }
1548         }
1549         else
1550         {
1551             i_data &= 0x1f;
1552
1553             if( i_data > 0xf )
1554             {
1555                 printf("r[ILL]");
1556             }
1557             else
1558             {
1559                 printf("r[0x%02x]", i_data);
1560             }
1561         }
1562     }
1563 }
1564
1565 static void IfoAdvanced( u8 *pi_code )
1566 {
1567     u8      i_cmd = pi_code[0];
1568
1569     printf(" { ");
1570
1571     if( pi_code[1]>>2 )
1572     {
1573         printf( " Highlight button %d; ", pi_code[1]>>2 );
1574     }
1575
1576     if( i_cmd == 0xff )
1577     {
1578         printf( " Illegal " );
1579     }
1580
1581     if( i_cmd == 0x00 )
1582     {
1583         printf( "ReSuME %d", pi_code[7] );
1584     }
1585     else if( ( i_cmd & 0x06) == 0x02 )
1586     {    // XX01Y
1587         printf ("Link to %s cell ", ( i_cmd & 0x01 ) ? "prev" : "next");
1588     }
1589     else
1590     {
1591         printf( "advanced (0x%02x) ", i_cmd );
1592     }
1593     printf(" } ");
1594 }
1595
1596 static void IfoJmp( ifo_command_t com )
1597 {
1598
1599     printf ("jmp ");
1600
1601     switch( com.i_sub_cmd )
1602     {
1603     case 0x01:
1604         printf( "Exit" );
1605         break;
1606     case 0x02:
1607         printf( "VTS 0x%02x", OP_VAL_8(3) );
1608         break;
1609     case 0x03:
1610         printf( "This VTS Title 0x%02x", OP_VAL_8(3) );
1611         break;
1612     case 0x05:
1613         printf( "This VTS Title 0x%02x Part 0x%04x",
1614                             OP_VAL_8(3),
1615                             OP_VAL_8(0)<<8|OP_VAL_8(1));
1616         break;
1617     case 0x06:
1618 #if 0
1619             printf ("in SystemSpace ");
1620             switch (OP_VAL_8(3)>>4) {
1621                 case 0x00:
1622                     printf ("to play first PGC");
1623                     break;
1624                 case 0x01: {
1625                     printf ("to menu \"%s\"", decode_menuname (OP_VAL_8(3)));
1626                 }
1627                     break;
1628                 case 0x02:
1629                     printf ("to VTS 0x%02x and TTN 0x%02x", OP_VAL_8(1), OP_VAL_8(2));
1630                     break;
1631                 case 0x03:
1632                     printf ("to VMGM PGC number 0x%02x", OP_VAL_8(0)<<8 | OP_VAL_8(1));
1633                     break;
1634                 case 0x08:
1635                     printf ("vts 0x%02x lu 0x%02x menu \"%s\"", OP_VAL_8(2), OP_VAL_8(1), decode_menuname (OP_VAL_8(3)));
1636                     break;
1637 #else
1638         switch( OP_VAL_8(3)>>6 )
1639         {
1640         case 0x00:
1641             printf( "to play first PGC" );
1642             break;                
1643         case 0x01:
1644             printf( "to VMG title menu (?)" );
1645             break;
1646         case 0x02:
1647             printf( "vts 0x%02x lu 0x%02x menu \"%s\"",
1648                             OP_VAL_8(2),
1649                             OP_VAL_8(1),
1650                             IfoMenuName( OP_VAL_8(3)&0xF ) );
1651             break;                
1652         case 0x03:
1653             printf( "vmg pgc 0x%04x (?)", ( OP_VAL_8(0)<<8) | OP_VAL_8(1) );
1654             break;
1655 #endif
1656         }
1657         break;
1658     case 0x08:
1659 #if 0
1660             switch(OP_VAL_8(3)>>4) {
1661                 case 0x00:
1662                     printf ("system first pgc");
1663                     break;
1664                 case 0x01:
1665                     printf ("system title menu");
1666                     break;
1667                 case 0x02:
1668                     printf ("system menu \"%s\"", decode_menuname (OP_VAL_8(3)));
1669                     break;
1670                 case 0x03:
1671                     printf ("system vmg pgc %02x ????", OP_VAL_8(0)<<8|OP_VAL_8(1));
1672                     break;
1673                 case 0x08:
1674                     printf ("system lu 0x%02x menu \"%s\"", OP_VAL_8(2), decode_menuname (OP_VAL_8(3)));
1675                     break;
1676                 case 0x0c:
1677                     printf ("system vmg pgc 0x%02x", OP_VAL_8(0)<<8|OP_VAL_8(1));
1678                     break;
1679             }
1680 #else
1681         // OP_VAL_8(2) is number of cell
1682         // it is processed BEFORE switch
1683         // under some conditions, it is ignored
1684         // I don't understand exactly what it means
1685         printf( " ( spec cell 0x%02X ) ", OP_VAL_8(2) ); 
1686
1687         switch( OP_VAL_8(3)>>6 )
1688         {
1689         case 0:
1690             printf( "to FP PGC" );
1691             break;
1692         case 1:
1693             printf( "to VMG root menu (?)" );
1694             break;
1695         case 2:
1696             printf( "to VTS menu \"%s\" (?)",
1697                     IfoMenuName(OP_VAL_8(3)&0xF) );
1698             break; 
1699         case 3:
1700             printf( "vmg pgc 0x%02x (?)", (OP_VAL_8(0)<<8)|OP_VAL_8(1) );
1701             break;
1702         }    
1703 #endif
1704         break;
1705     }
1706 }
1707
1708 static void IfoLnk( ifo_command_t com )
1709 {
1710     u16     i_button=OP_VAL_8(4)>>2;
1711
1712     printf ("lnk to ");
1713
1714     switch( com.i_sub_cmd )
1715     {
1716     case 0x01:
1717         IfoAdvanced( &OP_VAL_8(4) );
1718         break;
1719
1720     case 0x04:
1721         printf( "PGC 0x%02x", OP_VAL_16(2) );
1722         break; 
1723
1724     case 0x05:
1725         printf( "PTT 0x%02x", OP_VAL_16(2) );
1726         break; 
1727
1728     case 0x06:
1729         printf( "Program 0x%02x this PGC", OP_VAL_8(5) );
1730         break;
1731
1732     case 0x07:
1733         printf( "Cell 0x%02x this PGC", OP_VAL_8(5) );
1734         break;
1735     default:
1736         return;
1737     }
1738
1739     if( i_button )
1740     {
1741         printf( ", Highlight 0x%02x", OP_VAL_8(4)>>2 );
1742     }
1743             
1744 }
1745
1746 void IfoSetSystem( ifo_command_t com )
1747 {
1748     switch( com.i_cmd )
1749     {
1750     case 1: {
1751         int i;
1752
1753         for( i=1; i<=3; i++ )
1754         {
1755             if( OP_VAL_8(i)&0x80 )
1756             {
1757                 if( com.i_direct )
1758                 {
1759                     printf ("s[%s] = 0x%02x;", ifo_reg[i], OP_VAL_8(i)&0xf);
1760                 }
1761                 else
1762                 {
1763                     printf ("s[%s] = r[0x%02x];", ifo_reg[i], OP_VAL_8(i)&0xf);
1764                 }
1765             }
1766         }
1767 #if 0
1768                 if(op->direct) {
1769                         if(OP_VAL_8(1]&0x80)
1770                                 printf ("s[%s] = 0x%02x;", reg_name[1], OP_VAL_8(1]&0xf);
1771                         if(OP_VAL_8(2)&0x80)
1772 //DENT: lwhat about 0x7f here ???
1773                                 printf ("s[%s] = 0x%02x;", reg_name[2], OP_VAL_8(2)&0x7f);
1774                         if(OP_VAL_8(3)&0x80)
1775                                 printf ("s[%s] = 0x%02x;", reg_name[3], OP_VAL_8(3)&0xf);
1776                 } else {
1777                         if(OP_VAL_8(1)&0x80)
1778                                 printf ("s[%s] = r[0x%02x];", reg_name[1], OP_VAL_8(1)&0xf);
1779                         if(OP_VAL_8(2)&0x80)
1780                                 printf ("s[%s] = r[0x%02x];", reg_name[2], OP_VAL_8(2)&0xf);
1781                         if(OP_VAL_8(3)&0x80)
1782                                 printf ("s[%s] = r[0x%02x];", reg_name[3], OP_VAL_8(3)&0xf);
1783                 }
1784 #endif
1785         }
1786         break;
1787     case 2:
1788         if( com.i_direct )
1789         {
1790             printf( "s[%s] = 0x%02x", ifo_reg[9], OP_VAL_16(0) );
1791         }
1792         else
1793         {
1794             printf( "s[%s] = r[0x%02x]", ifo_reg[9], OP_VAL_8(1)&0x0f );
1795         }
1796
1797         printf( "s[%s] = (s[%s]&0x7FFF)|0x%02x", 
1798                         ifo_reg[10], ifo_reg[10], OP_VAL_16(1)&0x8000);
1799         break;
1800     case 3:
1801         if( com.i_direct )
1802         {
1803             printf( "r[0x%02x] = 0x%02x", OP_VAL_8(3)&0x0f, OP_VAL_16(0) );
1804         }
1805         else
1806         {
1807             printf ("r[r[0x%02x]] = r[0x%02x]",
1808                                     OP_VAL_8(3)&0x0f, OP_VAL_8(1)&0x0f);
1809         }
1810         break;
1811     case 4:
1812         //actually only bits 00011100 00011100 are set
1813         if( com.i_direct )
1814         {
1815             printf ("s[%s] = 0x%02x", ifo_reg[11], OP_VAL_16(1));
1816         }
1817         else
1818         {
1819             printf ("s[%s] = r[0x%02x]", ifo_reg[11], OP_VAL_8(3)&0x0f );
1820         }
1821         break;
1822     case 6:
1823         //actually,
1824         //s[%s]=(r[%s]&0x3FF) | (0x%02x << 0xA);
1825         //but it is way too ugly
1826         if( com.i_direct )
1827         {
1828             printf( "s[%s] = 0x%02x", ifo_reg[8], OP_VAL_8(2)>>2 );
1829         }
1830         else
1831         {
1832             printf( "s[%s] = r[0x%02x]", ifo_reg[8], OP_VAL_8(3)&0x0f );
1833         }
1834         break;
1835     default:
1836         printf ("unknown");
1837     }
1838 }
1839
1840 static void IfoSet( ifo_command_t com )
1841 {
1842     IfoRegister( OP_VAL_16(0), 0 );
1843     printf( " %s ", IfoMath( com.i_cmd ) );
1844     IfoRegister( OP_VAL_16(1), com.i_direct );
1845 }
1846
1847 /*****************************************************************************
1848  * CommandRead : translates the command strings in ifo into command
1849  * structures.
1850  *****************************************************************************/
1851 void CommandRead( ifo_command_t com )
1852 {
1853     u8*     pi_code = (u8*)(&com);
1854
1855     switch( com.i_type )
1856     {
1857     /* Goto */
1858     case 0:
1859         /* Main command */
1860         if( !pi_code[1] )
1861         {
1862             printf( "NOP\n" );
1863         }
1864         else
1865         {
1866             if( com.i_cmp )
1867             {
1868                 printf ("if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
1869                                              ifo_cmp[com.i_cmp]);
1870                 IfoRegister (OP_VAL_16(1), com.i_dir_cmp);
1871                 printf (") ");
1872             }
1873         
1874             /* Sub command */
1875             switch( com.i_sub_cmd )
1876             {
1877             case 1:
1878                 printf( "goto Line 0x%02x", OP_VAL_16(2) );
1879                 break;
1880         
1881             case 2:
1882                 printf( "stop VM" );
1883                 break;
1884         
1885             case 3:
1886                 printf( "Set Parental Level To %s and goto Line 0x%02x",
1887                                      ifo_parental[OP_VAL_8(4)&0x7],
1888                                      OP_VAL_8(5) );
1889                 break;
1890         
1891             default:
1892                 printf( "Illegal" );
1893                 break;
1894             }
1895         }
1896         break;
1897
1898     /* Lnk */
1899     case 1:
1900         /* Main command */
1901         if( !pi_code[1] )
1902         {
1903             printf( "NOP\n" );
1904         }
1905         else
1906         {
1907             if( com.i_direct )
1908             {
1909                 if( com.i_cmp )
1910                 {
1911                     printf( "if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f,
1912                                                  ifo_cmp[com.i_cmp] );
1913                     IfoRegister( OP_VAL_8(5), 0 );
1914                     printf( ") " );
1915                 }
1916
1917                 /* Sub command */
1918                 IfoJmp( com );
1919             }
1920             else
1921             {    
1922                 if( com.i_cmp )
1923                 {
1924                     printf( "if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
1925                                                  ifo_cmp[com.i_cmp] );
1926                     IfoRegister( OP_VAL_16(1), com.i_dir_cmp );
1927                     printf( ") " );
1928                 }
1929
1930                 /* Sub command */
1931                 IfoLnk( com );
1932             }
1933         }
1934         break;
1935
1936     /* SetSystem */
1937     case 2:
1938         if( !pi_code[1] )
1939         {
1940             IfoSetSystem( com );
1941         }
1942         else if( com.i_cmp && !com.i_sub_cmd )
1943         {
1944             printf ("if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f, ifo_cmp[com.i_cmp]);
1945             IfoRegister( OP_VAL_8(5), 0 );
1946             printf (") ");
1947             IfoSetSystem( com );
1948         }
1949         else if( !com.i_cmp && com.i_sub_cmd )
1950         {
1951             printf( "if (" );
1952             IfoSetSystem( com );
1953             printf( ") " );
1954             IfoLnk( com );
1955         }
1956         else
1957         {
1958             printf("nop");
1959         }
1960         break;
1961
1962     /* Set */
1963     case 3:
1964           if( ! pi_code[1] )
1965         {
1966             IfoSet( com );
1967         }
1968         else if( com.i_cmp && !com.i_sub_cmd )
1969         {
1970             printf ("if (r[0x%02x] %s ", OP_VAL_8(0)&0x0f, ifo_cmp[com.i_cmp]);
1971             IfoRegister( OP_VAL_16(2), com.i_dir_cmp );
1972             printf (") ");
1973             IfoSet( com );
1974         }
1975         else if( !com.i_cmp && com.i_sub_cmd )
1976         {
1977             printf ("if (");
1978             IfoSet( com );
1979             printf (") ");
1980             IfoLnk( com );
1981         }
1982         else
1983         {
1984             printf( "nop" );
1985         }
1986         break;
1987
1988     /* 
1989      * math command on r[opcode[1]] and
1990      * direct?be2me_16(OP_VAL_8(0)):reg[OP_VAL_8(1)] is executed
1991      * ( unless command is swap; then r[opcode[1]] and r[OP_VAL_8(1)]
1992      * are swapped )
1993      * boolean operation cmp on r[opcode[1]] and
1994      * dir_cmp?be2me_16(OP_VAL_8(1)[1]):reg[OP_VAL_8(3)] is executed
1995      * on true result, buttons(c[6], c[7]) is called
1996      * problem is 'what is buttons()'
1997      */
1998     case 4:
1999         printf( "r[0x%X] ", pi_code[1] );
2000         printf( " %s ", IfoMath( com.i_cmd ) );
2001         if( com.i_cmd == 2 )
2002         {
2003             printf( "r[0x%X] ", OP_VAL_8(1) );
2004         }
2005         else
2006         {
2007             IfoRegister( OP_VAL_16(0), com.i_direct );
2008         }
2009         printf("; ");
2010
2011         printf( "if ( r[%d] %s ", pi_code[1], ifo_cmp[com.i_cmp] );
2012         IfoRegister( OP_VAL_8(1), com.i_dir_cmp );
2013         printf( " )  then {" );
2014         IfoAdvanced( &OP_VAL_8(4) );
2015         printf( "}" );
2016         break;
2017
2018     /*
2019      * opposite to case 4: boolean, math and buttons.
2020      */
2021     case 5:
2022     case 6:
2023         printf("if (");
2024
2025         if( !com.i_direct && com.i_dir_cmp )
2026         {
2027             printf( "0x%X", OP_VAL_16(1) );
2028         }
2029         else
2030         {
2031             IfoRegister( OP_VAL_8(3), 0 );
2032             if( OP_VAL_8(3)&0x80 )
2033             {
2034                 printf( "s[%s]", ifo_reg[OP_VAL_8(3)&0x1F] );
2035             }
2036             else
2037             {
2038                 printf( "r[0x%X]", OP_VAL_8(3)&0x1F);
2039                     // 0x1F is either not a mistake,
2040                     // or Microsoft programmer's mistake!!!
2041             }
2042         }
2043
2044         printf( " %s r[0x%X] ", ifo_cmp[com.i_cmp],
2045                                 com.i_direct ? OP_VAL_8(2) : OP_VAL_8(1) );
2046            printf( " )  then {" );
2047         printf( "r[0x%X] ", pi_code[1] & 0xF );
2048         printf( " %s ", IfoMath( com.i_cmd ) );
2049
2050         if( com.i_cmd == 0x02 )    // swap
2051         {
2052             printf("r[0x%X] ", OP_VAL_8(0)&0x1F);
2053         }
2054         else
2055         {
2056             if( com.i_direct )
2057             {
2058                 printf( "0x%X", OP_VAL_16(0) );
2059             }
2060             else
2061             {
2062                 if( OP_VAL_8(0) & 0x80 )
2063                 {
2064                     printf("s[%s]", ifo_reg[OP_VAL_8(0) & 0x1F] );
2065                 }
2066                 else
2067                 {
2068                     printf("r[0x%X]", OP_VAL_8(0) & 0x1F );
2069                 }
2070             }
2071         }
2072
2073         printf("; ");
2074         IfoAdvanced( &OP_VAL_8(4) );
2075         printf("}");
2076
2077         break;
2078
2079     default:
2080         printf( "Unknown Command\n" );
2081         break;
2082     }
2083
2084     return;
2085 }
2086
2087 /*****************************************************************************
2088  * CommandPrint : print in clear text (I hope so !) what a command does
2089  *****************************************************************************/
2090 void CommandPrint( ifo_t ifo )
2091 {
2092     return;
2093 }
2094
2095 #endif
2096
2097 /*****************************************************************************
2098  * ReadByte and so
2099  *****************************************************************************/
2100 static u8* FillBuffer( ifo_t* p_ifo, u8* p_buf, int i_pos )
2101 {
2102     p_ifo->i_pos = dvdcss_seek( p_ifo->dvdhandle, i_pos, DVDCSS_NOFLAGS );
2103     dvdcss_read( p_ifo->dvdhandle, p_buf, 1, DVDCSS_NOFLAGS );
2104
2105     return p_buf;
2106 }
2107
2108 static void ReadBytes( ifo_t* p_ifo, u8* p_buf, u8** pp_tmp,
2109                                      u8* pi_dest, int i_nb )
2110 {
2111     if( i_nb > DVD_LB_SIZE )
2112     {
2113         intf_ErrMsg( "ifo error: excessive ReadBytes call (%i)", i_nb );
2114     }
2115
2116     if( *pp_tmp + i_nb >= p_buf + DVD_LB_SIZE )
2117     {
2118         int i_spare = (int)( (p_buf + DVD_LB_SIZE) - *pp_tmp );
2119
2120         /* Copy the bytes remaining in the current buffer */
2121         memcpy( pi_dest, *pp_tmp, i_spare );
2122         pi_dest += i_spare;
2123         i_nb -= i_spare;
2124
2125         /* Load the next buffer */
2126         *pp_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_pos + 1 );
2127     }
2128
2129     memcpy( pi_dest, *pp_tmp, i_nb );
2130     *pp_tmp += i_nb;
2131
2132     return;
2133 }
2134
2135 static void DumpBytes( ifo_t* p_ifo, u8* p_buf, u8** pp_tmp, int i_nb )
2136 {
2137     if( i_nb > DVD_LB_SIZE )
2138     {
2139         intf_ErrMsg( "ifo error: excessive DumpBytes call (%i)", i_nb );
2140     }
2141
2142     *pp_tmp += i_nb;
2143
2144     if( *pp_tmp >= p_buf + DVD_LB_SIZE )
2145     {
2146         /* If we went too far, load the next buffer */
2147         *pp_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_pos + 1 )
2148                    + (int)( (*pp_tmp) - (p_buf + DVD_LB_SIZE) );
2149     }
2150
2151     return;
2152 }
2153
2154 #define ADDBYTE \
2155     if( *pp_tmp >= p_buf + DVD_LB_SIZE ) \
2156     { \
2157         *pp_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_pos + 1 ); \
2158     } \
2159     i_ret <<= 8; i_ret |= **pp_tmp; (*pp_tmp)++;
2160
2161 static u8 ReadByte( ifo_t * p_ifo, u8* p_buf, u8** pp_tmp )
2162 {
2163     u8     i_ret = 0;
2164     ADDBYTE;
2165     return i_ret;
2166 }
2167
2168 static u16 ReadWord( ifo_t * p_ifo, u8* p_buf, u8** pp_tmp )
2169 {
2170     u16    i_ret = 0;
2171     ADDBYTE; ADDBYTE;
2172     return i_ret;
2173 }
2174
2175 static u32 ReadDouble( ifo_t * p_ifo, u8* p_buf, u8** pp_tmp )
2176 {
2177     u32    i_ret = 0;
2178     ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE;
2179     return i_ret;
2180 }
2181
2182 static u64 ReadQuad( ifo_t * p_ifo, u8* p_buf, u8** pp_tmp )
2183 {
2184     u64    i_ret = 0;
2185     ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE;
2186     return i_ret;
2187 }
2188