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