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