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