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