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