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