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