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