* Applied patch from Jon Lech Johansen <jon-vl@nanocrew.net> to compile
[vlc.git] / plugins / dvd / dvd_ifo.c
blob5644b170b700c015a2c7504ffe72af018a2de29f
1 /*****************************************************************************
2 * dvd_ifo.c: Functions for ifo parsing
3 *****************************************************************************
4 * Copyright (C) 1999-2001 VideoLAN
5 * $Id: dvd_ifo.c,v 1.28 2001/05/31 01:37:08 sam Exp $
7 * Author: Stéphane Borel <stef@via.ecp.fr>
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
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.
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.
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 *****************************************************************************/
29 /*****************************************************************************
30 * Preamble
31 *****************************************************************************/
32 #include "defs.h"
33 #include "config.h"
35 #include <stdio.h>
36 #include <stdlib.h>
38 #ifdef HAVE_UNISTD_H
39 #include <unistd.h>
40 #elif defined( _MSC_VER ) && defined( _WIN32 )
41 #include <io.h>
42 #endif
44 #include <string.h>
45 #include <fcntl.h>
47 #include "common.h"
49 #include "intf_msg.h"
50 #include "dvd_ifo.h"
51 #include "dvd_udf.h"
52 #include "input_dvd.h"
55 * Local prototypes
57 void CommandRead ( command_desc_t );
58 static int ReadTitle ( ifo_t * , title_t *, off_t );
59 static int FreeTitle ( title_t * );
60 static int ReadUnitInf ( ifo_t * , unit_inf_t *, off_t );
61 static int FreeUnitInf ( unit_inf_t * );
62 static int ReadTitleUnit ( ifo_t * , title_unit_t *, off_t );
63 static int FreeTitleUnit ( title_unit_t * );
64 static int ReadVobuMap ( ifo_t * , vobu_map_t *, off_t );
65 static int FreeVobuMap ( vobu_map_t * );
66 static int ReadCellInf ( ifo_t * , cell_inf_t *, off_t );
67 static int FreeCellInf ( cell_inf_t * );
68 static int FreeTitleSet ( vts_t * );
70 /*****************************************************************************
71 * ReadByte and so
72 *****************************************************************************/
73 static __inline__ u8* FillBuffer( ifo_t* p_ifo, u8* pi_buffer, off_t i_pos )
75 memset( pi_buffer, 0, DVD_LB_SIZE );
76 p_ifo->i_pos = lseek( p_ifo->i_fd, i_pos, SEEK_SET );
77 read( p_ifo->i_fd, pi_buffer, DVD_LB_SIZE );
79 return pi_buffer;
82 static __inline__ u8 ReadByte( ifo_t * p_ifo, u8* pi_buffer, u8** pp_current )
84 u8 i_ret;
86 if( *pp_current > pi_buffer + DVD_LB_SIZE )
88 *pp_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_pos + DVD_LB_SIZE );
91 i_ret = *(*pp_current)++;
93 return i_ret;
96 static __inline__ u16 ReadWord( ifo_t* p_ifo, u8* pi_buffer, u8** pp_current )
98 u16 i_ret;
100 if( *pp_current > pi_buffer + DVD_LB_SIZE - 2 )
102 *pp_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_pos + DVD_LB_SIZE );
105 i_ret = U16_AT(*pp_current);
106 (*pp_current) += 2;
108 return i_ret;
111 static __inline__ u32 ReadDouble( ifo_t * p_ifo, u8* pi_buffer,
112 u8** pp_current )
114 u32 i_ret;
116 if( *pp_current > pi_buffer + DVD_LB_SIZE - 4 )
118 *pp_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_pos + DVD_LB_SIZE);
119 // intf_WarnMsg( 1, "new buffer in double @ %lld", p_ifo->i_pos );
122 i_ret = U32_AT(*pp_current);
123 (*pp_current) += 4;
125 return i_ret;
128 static __inline__ u64 ReadQuad( ifo_t* p_ifo, u8* pi_buffer, u8** pp_current )
130 u64 i_ret;
132 if( *pp_current > pi_buffer + DVD_LB_SIZE - 8 )
134 *pp_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_pos + DVD_LB_SIZE );
137 i_ret = U64_AT(*pp_current);
138 (*pp_current) += 8;
140 return i_ret;
143 static __inline__ void ReadBits( ifo_t* p_ifo, u8* pi_buffer, u8** pp_current,
144 u8* pi_dest, int i_nb )
146 if( *pp_current > pi_buffer + DVD_LB_SIZE - i_nb )
148 *pp_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_pos + DVD_LB_SIZE );
151 memcpy( pi_dest, *pp_current, i_nb );
152 *pp_current += i_nb;
154 return;
157 static __inline__ void DumpBits( ifo_t* p_ifo, u8* pi_buffer,
158 u8** pp_current, int i_nb )
160 if( *pp_current > pi_buffer + DVD_LB_SIZE - i_nb )
162 *pp_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_pos + DVD_LB_SIZE );
165 *pp_current += i_nb;
167 return;
171 * IFO Management.
173 /*****************************************************************************
174 * IfoCreate : Creates an ifo structure and prepares for parsing directly
175 * on DVD device
176 *****************************************************************************/
177 int IfoCreate( thread_dvd_data_t * p_dvd )
179 p_dvd->p_ifo = malloc( sizeof(ifo_t) );
180 if( p_dvd->p_ifo == NULL )
182 intf_ErrMsg( "ifo error: unable to allocate memory. aborting" );
183 return -1;
186 /* if we are here the dvd device has already been opened */
187 p_dvd->p_ifo->i_fd = p_dvd->i_fd;
189 return 0;
192 /*****************************************************************************
193 * IfoInit : Reads information from the management table.
194 *****************************************************************************/
195 int IfoInit( ifo_t * p_ifo )
197 u8 pi_buffer[DVD_LB_SIZE];
198 u8* p_current;
199 u64 i_temp;
200 u32 i_lba;
201 int i, j, k;
202 off_t i_start;
204 /* find the start sector of video information on the dvd */
205 i_lba = UDFFindFile( p_ifo->i_fd, "/VIDEO_TS/VIDEO_TS.IFO");
207 p_ifo->i_off = (off_t)(i_lba) * DVD_LB_SIZE;
209 p_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_off );
210 //i_start = p_ifo->i_pos;
212 * read the video manager information table
214 #define manager_inf p_ifo->vmg.manager_inf
215 //fprintf( stderr, "VMGI\n" );
217 ReadBits( p_ifo, pi_buffer, &p_current, manager_inf.psz_id, 12 );
218 manager_inf.psz_id[12] = '\0';
219 manager_inf.i_vmg_end_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
220 DumpBits( p_ifo, pi_buffer, &p_current, 12 );
221 manager_inf.i_vmg_inf_end_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
222 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
223 manager_inf.i_spec_ver = ReadByte( p_ifo, pi_buffer, &p_current );
224 manager_inf.i_cat = ReadDouble( p_ifo, pi_buffer, &p_current );
225 manager_inf.i_volume_nb = ReadWord( p_ifo, pi_buffer, &p_current );
226 manager_inf.i_volume = ReadWord( p_ifo, pi_buffer, &p_current );
227 manager_inf.i_disc_side = ReadByte( p_ifo, pi_buffer, &p_current );
228 DumpBits( p_ifo, pi_buffer, &p_current, 19 );
229 manager_inf.i_title_set_nb = ReadWord( p_ifo, pi_buffer, &p_current );
230 ReadBits( p_ifo, pi_buffer, &p_current, manager_inf.ps_provider_id, 32 );
231 manager_inf.i_pos_code = ReadQuad( p_ifo, pi_buffer, &p_current );
232 DumpBits( p_ifo, pi_buffer, &p_current, 24 );
233 manager_inf.i_vmg_inf_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
234 manager_inf.i_first_play_title_start_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
235 DumpBits( p_ifo, pi_buffer, &p_current, 56 );
236 manager_inf.i_vob_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
237 manager_inf.i_title_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
238 manager_inf.i_title_unit_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
239 manager_inf.i_parental_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
240 manager_inf.i_vts_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
241 manager_inf.i_text_data_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
242 manager_inf.i_cell_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
243 manager_inf.i_vobu_map_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
244 DumpBits( p_ifo, pi_buffer, &p_current, 32 );
245 // GETS( &manager_inf.video_atrt );
246 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
247 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
248 manager_inf.i_audio_nb = ReadByte( p_ifo, pi_buffer, &p_current );
249 //fprintf( stderr, "vmgi audio nb : %d\n", manager_inf.i_audio_nb );
250 for( i=0 ; i < 8 ; i++ )
252 i_temp = ReadQuad( p_ifo, pi_buffer, &p_current );
254 DumpBits( p_ifo, pi_buffer, &p_current, 17 );
255 manager_inf.i_spu_nb = ReadByte( p_ifo, pi_buffer, &p_current );
256 //fprintf( stderr, "vmgi subpic nb : %d\n", manager_inf.i_spu_nb );
257 for( i=0 ; i < manager_inf.i_spu_nb ; i++ )
259 ReadBits( p_ifo, pi_buffer, &p_current, (u8*)(&i_temp), 6 );
260 /* FIXME : take care of endianness */
264 * read first play title.
266 if( ReadTitle( p_ifo, &p_ifo->vmg.title, p_ifo->i_off +
267 manager_inf.i_first_play_title_start_byte ) < 0 )
269 return -1;
273 * fills the title information structure.
275 #define title_inf p_ifo->vmg.title_inf
276 if( manager_inf.i_title_inf_start_sector )
278 p_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_off +
279 manager_inf.i_title_inf_start_sector *DVD_LB_SIZE );
280 //fprintf( stderr, "title inf %lld\n", p_ifo->i_pos );
282 title_inf.i_title_nb = ReadWord( p_ifo, pi_buffer, &p_current );
283 //fprintf( stderr, "title_inf: TTU nb %d\n", title_inf.i_title_nb );
284 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
285 title_inf.i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
287 /* parsing of title attributes */
288 title_inf.p_attr = malloc( title_inf.i_title_nb *sizeof(title_attr_t) );
289 if( title_inf.p_attr == NULL )
291 intf_ErrMsg( "ifo error: out of memory in IfoInit" );
292 return -1;
295 for( i = 0 ; i < title_inf.i_title_nb ; i++ )
297 title_inf.p_attr[i].i_play_type = ReadByte( p_ifo, pi_buffer, &p_current );
298 title_inf.p_attr[i].i_angle_nb = ReadByte( p_ifo, pi_buffer, &p_current );
299 title_inf.p_attr[i].i_chapter_nb = ReadWord( p_ifo, pi_buffer, &p_current );
300 title_inf.p_attr[i].i_parental_id = ReadWord( p_ifo, pi_buffer, &p_current );
301 title_inf.p_attr[i].i_title_set_num = ReadByte( p_ifo, pi_buffer, &p_current );
302 title_inf.p_attr[i].i_title_num = ReadByte( p_ifo, pi_buffer, &p_current );
303 title_inf.p_attr[i].i_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
304 //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 );
307 else
309 title_inf.p_attr = NULL;
311 #undef title_inf
314 * fills the title unit structure.
316 if( manager_inf.i_title_unit_start_sector )
318 if( ReadTitleUnit( p_ifo, &p_ifo->vmg.title_unit, p_ifo->i_off +
319 manager_inf.i_title_unit_start_sector *DVD_LB_SIZE ) < 0 )
321 return -1;
326 * fills the structure about parental information.
328 #define parental p_ifo->vmg.parental_inf
329 if( manager_inf.i_parental_inf_start_sector )
331 p_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_off +
332 manager_inf.i_parental_inf_start_sector *DVD_LB_SIZE );
333 i_start = p_ifo->i_pos;
335 //fprintf( stderr, "PTL\n" );
337 parental.i_country_nb = ReadWord( p_ifo, pi_buffer, &p_current );
338 parental.i_vts_nb = ReadWord( p_ifo, pi_buffer, &p_current );
339 parental.i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
341 parental.p_parental_desc = malloc( parental.i_country_nb *
342 sizeof(parental_desc_t) );
343 if( parental.p_parental_desc == NULL )
345 intf_ErrMsg( "ifo error: out of memory in IfoInit" );
346 return -1;
349 for( i = 0 ; i < parental.i_country_nb ; i++ )
351 ReadBits( p_ifo, pi_buffer, &p_current,
352 parental.p_parental_desc[i].ps_country_code, 2 );
353 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
354 parental.p_parental_desc[i].i_parental_mask_start_byte =
355 ReadWord( p_ifo, pi_buffer, &p_current );
356 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
359 parental.p_parental_mask = malloc( parental.i_country_nb *
360 sizeof(parental_mask_t) );
361 if( parental.p_parental_mask == NULL )
363 intf_ErrMsg( "ifo erro: out of memory in IfoInit" );
364 return -1;
367 for( i = 0 ; i < parental.i_country_nb ; i++ )
369 p_current = FillBuffer( p_ifo, pi_buffer, i_start +
370 parental.p_parental_desc[i].i_parental_mask_start_byte );
371 for( j = 0 ; j < 8 ; j++ )
373 parental.p_parental_mask[i].ppi_mask[j] =
374 malloc( ( parental.i_vts_nb + 1 ) *sizeof(u16) );
375 if( parental.p_parental_mask[i].ppi_mask[j] == NULL )
377 intf_ErrMsg( "ifo error: out of memory in IfoInit" );
378 return -1;
380 for( k = 0 ; k < parental.i_vts_nb + 1 ; k++ )
382 parental.p_parental_mask[i].ppi_mask[j][k] =
383 ReadWord( p_ifo, pi_buffer, &p_current );
388 #undef parental
391 * information and attributes about for each vts.
393 #define vts_inf p_ifo->vmg.vts_inf
394 if( manager_inf.i_vts_inf_start_sector )
396 u64 i_temp;
398 p_current = FillBuffer( p_ifo, pi_buffer, p_ifo->i_off +
399 manager_inf.i_vts_inf_start_sector *DVD_LB_SIZE );
400 i_start = p_ifo->i_pos;
402 //fprintf( stderr, "VTS ATTR\n" );
404 vts_inf.i_vts_nb = ReadWord( p_ifo, pi_buffer, &p_current );;
405 //fprintf( stderr, "VTS ATTR Nb: %d\n", vts_inf.i_vts_nb );
406 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
407 vts_inf.i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
408 vts_inf.pi_vts_attr_start_byte =
409 malloc( vts_inf.i_vts_nb *sizeof(u32) );
410 if( vts_inf.pi_vts_attr_start_byte == NULL )
412 intf_ErrMsg( "ifo error: out of memory in IfoInit" );
413 return -1;
416 for( i = 0 ; i < vts_inf.i_vts_nb ; i++ )
418 vts_inf.pi_vts_attr_start_byte[i] = ReadDouble( p_ifo, pi_buffer, &p_current );
421 vts_inf.p_vts_attr = malloc( vts_inf.i_vts_nb *sizeof(vts_attr_t) );
422 if( vts_inf.p_vts_attr == NULL )
424 intf_ErrMsg( "ifo erro: out of memory in IfoInit" );
425 return -1;
428 for( i = 0 ; i < vts_inf.i_vts_nb ; i++ )
430 p_current = FillBuffer( p_ifo, pi_buffer, i_start +
431 vts_inf.pi_vts_attr_start_byte[i] );
432 vts_inf.p_vts_attr[i].i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
433 vts_inf.p_vts_attr[i].i_cat_app_type = ReadDouble( p_ifo, pi_buffer, &p_current );
434 // GETS( &vts_inf.p_vts_attr[i].vts_menu_video_attr );
435 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
436 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
437 vts_inf.p_vts_attr[i].i_vts_menu_audio_nb = ReadByte( p_ifo, pi_buffer, &p_current );
438 //fprintf( stderr, "m audio nb : %d\n", vts_inf.p_vts_attr[i].i_vts_menu_audio_nb );
439 for( j = 0 ; j < 8 ; j++ )
441 i_temp = ReadQuad( p_ifo, pi_buffer, &p_current );;
443 DumpBits( p_ifo, pi_buffer, &p_current, 17 );
444 vts_inf.p_vts_attr[i].i_vts_menu_spu_nb = ReadByte( p_ifo, pi_buffer, &p_current );
445 //fprintf( stderr, "m subp nb : %d\n", vts_inf.p_vts_attr[i].i_vts_menu_spu_nb );
446 for( j = 0 ; j < 28 ; j++ )
448 ReadBits( p_ifo, pi_buffer, &p_current, (u8*)(&i_temp), 6 );
449 /* FIXME : Fix endianness issue here */
451 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
452 // GETS( &vts_inf.p_vts_attr[i].vtstt_video_vts_inf );
453 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
454 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
455 vts_inf.p_vts_attr[i].i_vts_title_audio_nb =
456 ReadDouble( p_ifo, pi_buffer, &p_current );
457 //fprintf( stderr, "tt audio nb : %d\n", vts_inf.p_vts_attr[i].i_vts_title_audio_nb );
458 for( j = 0 ; j < 8 ; j++ )
460 i_temp = ReadQuad( p_ifo, pi_buffer, &p_current );;
462 DumpBits( p_ifo, pi_buffer, &p_current, 17 );
463 vts_inf.p_vts_attr[i].i_vts_title_spu_nb = ReadByte( p_ifo, pi_buffer, &p_current );
464 //fprintf( stderr, "tt subp nb : %d\n", vts_inf.p_vts_attr[i].i_vts_title_spu_nb );
465 for( j=0 ; j<28/*vts_inf.p_vts_vts_inf[i].i_vtstt_subpic_nb*/ ; j++ )
467 ReadBits( p_ifo, pi_buffer, &p_current, (u8*)(&i_temp), 6 );
468 /* FIXME : Fix endianness issue here */
472 #undef vts_inf
475 * global cell map.
477 if( manager_inf.i_cell_inf_start_sector )
479 if( ReadCellInf( p_ifo, &p_ifo->vmg.cell_inf, p_ifo->i_off +
480 manager_inf.i_cell_inf_start_sector *DVD_LB_SIZE ) < 0 )
482 return -1;
487 * global vob unit map.
489 if( manager_inf.i_vobu_map_start_sector )
491 if( ReadVobuMap( p_ifo, &p_ifo->vmg.vobu_map, p_ifo->i_off +
492 manager_inf.i_vobu_map_start_sector *DVD_LB_SIZE ) < 0 )
494 return -1;
497 #undef manager_inf
499 p_ifo->vts.b_initialized = 0;
501 intf_WarnMsg( 2, "ifo info: vmg initialized" );
503 return 0;
506 /*****************************************************************************
507 * IfoTitleSet: Parse vts*.ifo files to fill the Video Title Set structure.
508 *****************************************************************************/
509 int IfoTitleSet( ifo_t * p_ifo )
511 u8 pi_buffer[DVD_LB_SIZE];
512 u8 * p_current;
513 off_t i_off;
514 off_t i_start;
515 u64 i_temp;
516 u16 i_short;
517 int i, j;
519 if( p_ifo->vts.b_initialized )
521 FreeTitleSet( &p_ifo->vts );
524 i_off =
525 (off_t)( p_ifo->vmg.title_inf.p_attr[p_ifo->i_title-1].i_start_sector )
526 * DVD_LB_SIZE
527 + p_ifo->i_off;
529 //fprintf(stderr, "offset: %lld\n" , i_off );
531 p_current = FillBuffer( p_ifo, pi_buffer, i_off );
532 //i_start = p_ifo->i_pos;
533 p_ifo->vts.i_pos = p_ifo->i_pos;
535 #define manager_inf p_ifo->vts.manager_inf
537 * reads manager information
539 //fprintf( stderr, "VTSI\n" );
541 ReadBits( p_ifo, pi_buffer, &p_current, manager_inf.psz_id , 12 );
542 manager_inf.psz_id[12] = '\0';
543 manager_inf.i_end_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
544 DumpBits( p_ifo, pi_buffer, &p_current, 12 );
545 manager_inf.i_inf_end_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
546 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
547 manager_inf.i_spec_ver = ReadByte( p_ifo, pi_buffer, &p_current );
548 manager_inf.i_cat = ReadDouble( p_ifo, pi_buffer, &p_current );
549 DumpBits( p_ifo, pi_buffer, &p_current, 90 );
550 manager_inf.i_inf_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
551 DumpBits( p_ifo, pi_buffer, &p_current, 60 );
552 manager_inf.i_menu_vob_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
553 manager_inf.i_title_vob_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
554 manager_inf.i_title_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
555 manager_inf.i_title_unit_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
556 manager_inf.i_menu_unit_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
557 manager_inf.i_time_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
558 manager_inf.i_menu_cell_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
559 manager_inf.i_menu_vobu_map_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
560 manager_inf.i_cell_inf_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
561 manager_inf.i_vobu_map_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
562 DumpBits( p_ifo, pi_buffer, &p_current, 24 );
563 // GETS( &manager_inf.m_video_atrt );
564 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
565 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
566 manager_inf.i_menu_audio_nb = ReadByte( p_ifo, pi_buffer, &p_current );
567 for( i = 0 ; i < 8 ; i++ )
569 i_temp = ReadQuad( p_ifo, pi_buffer, &p_current );
571 DumpBits( p_ifo, pi_buffer, &p_current, 17 );
572 manager_inf.i_menu_spu_nb = ReadByte( p_ifo, pi_buffer, &p_current );
573 for( i = 0 ; i < 28 ; i++ )
575 ReadBits( p_ifo, pi_buffer, &p_current, (u8*)(&i_temp), 6 );
576 /* FIXME : take care of endianness */
578 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
580 i_short = ReadWord( p_ifo, pi_buffer, &p_current );
581 i_short >>= 2;
582 manager_inf.video_attr.i_mode = i_short & 0x1;
583 i_short >>= 1;
584 manager_inf.video_attr.i_letterboxed = i_short & 0x1;
585 i_short >>= 1;
586 manager_inf.video_attr.i_source_res = i_short & 0x3;
587 i_short >>= 2;
588 manager_inf.video_attr.i_line21_2 = i_short & 0x1;
589 i_short >>= 1;
590 manager_inf.video_attr.i_line21_1 = i_short & 0x1;
591 i_short >>= 1;
592 manager_inf.video_attr.i_perm_displ = i_short & 0x3;
593 i_short >>= 2;
594 manager_inf.video_attr.i_ratio = i_short & 0x3;
595 i_short >>= 2;
596 manager_inf.video_attr.i_system = i_short & 0x3;
597 i_short >>= 2;
598 manager_inf.video_attr.i_compression = i_short & 0x3;
600 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
601 manager_inf.i_audio_nb = ReadByte( p_ifo, pi_buffer, &p_current );
602 //fprintf( stderr, "vtsi audio nb : %d\n", manager_inf.i_audio_nb );
603 for( i = 0 ; i < 8 ; i++ )
605 i_temp = ReadQuad( p_ifo, pi_buffer, &p_current );
606 //fprintf( stderr, "Audio %d: %llx\n", i, i_temp );
607 i_temp >>= 8;
608 manager_inf.p_audio_attr[i].i_bar = i_temp & 0xff;
609 i_temp >>= 8;
610 manager_inf.p_audio_attr[i].i_caption = i_temp & 0xff;
611 i_temp >>= 8;
612 manager_inf.p_audio_attr[i].i_foo = i_temp & 0xff;
613 i_temp >>= 8;
614 manager_inf.p_audio_attr[i].i_lang_code = i_temp & 0xffff;
615 i_temp >>= 16;
616 manager_inf.p_audio_attr[i].i_num_channels = i_temp & 0x7;
617 i_temp >>= 3;
618 manager_inf.p_audio_attr[i].i_test = i_temp & 0x1;
619 i_temp >>= 1;
620 manager_inf.p_audio_attr[i].i_sample_freq = i_temp & 0x3;
621 i_temp >>= 2;
622 manager_inf.p_audio_attr[i].i_quantization = i_temp & 0x3;
623 i_temp >>= 2;
624 manager_inf.p_audio_attr[i].i_appl_mode = i_temp & 0x3;
625 i_temp >>= 2;
626 manager_inf.p_audio_attr[i].i_type = i_temp & 0x3;
627 i_temp >>= 2;
628 manager_inf.p_audio_attr[i].i_multichannel_extension = i_temp & 0x1;
629 i_temp >>= 1;
630 manager_inf.p_audio_attr[i].i_coding_mode = i_temp & 0x7;
632 DumpBits( p_ifo, pi_buffer, &p_current, 17 );
633 manager_inf.i_spu_nb = ReadByte( p_ifo, pi_buffer, &p_current );
634 //fprintf( stderr, "vtsi subpic nb : %d\n", manager_inf.i_spu_nb );
635 for( i=0 ; i<manager_inf.i_spu_nb ; i++ )
637 ReadBits( p_ifo, pi_buffer, &p_current, (u8*)(&i_temp), 6 );
638 i_temp = hton64( i_temp ) >> 16;
639 //fprintf( stderr, "Subpic %d: %llx\n", i, i_temp );
640 manager_inf.p_spu_attr[i].i_caption = i_temp & 0xff;
641 i_temp >>= 8;
642 manager_inf.p_spu_attr[i].i_foo = i_temp & 0xff;
643 i_temp >>= 8;
644 manager_inf.p_spu_attr[i].i_lang_code = i_temp & 0xffff;
645 i_temp >>= 16;
646 manager_inf.p_spu_attr[i].i_prefix = i_temp & 0xffff;
650 * reads title information: set of pointers to title
652 #define title_inf p_ifo->vts.title_inf
653 if( manager_inf.i_title_inf_start_sector )
655 p_current = FillBuffer( p_ifo, pi_buffer, p_ifo->vts.i_pos +
656 manager_inf.i_title_inf_start_sector *DVD_LB_SIZE );
658 i_start = p_ifo->i_pos;
660 //fprintf( stderr, "VTS PTR\n" );
662 title_inf.i_title_nb = ReadWord( p_ifo, pi_buffer, &p_current );
663 //fprintf( stderr, "VTS title_inf nb: %d\n", title_inf.i_title_nb );
664 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
665 title_inf.i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
667 title_inf.pi_start_byte = malloc( title_inf.i_title_nb *sizeof(u32) );
668 if( title_inf.pi_start_byte == NULL )
670 intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" );
671 return -1;
674 for( i = 0 ; i < title_inf.i_title_nb ; i++ )
676 title_inf.pi_start_byte[i] = ReadDouble( p_ifo, pi_buffer, &p_current );
679 /* Parsing of tts */
680 title_inf.p_title_start = malloc( title_inf.i_title_nb
681 *sizeof(title_start_t) );
682 if( title_inf.p_title_start == NULL )
684 intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" );
685 return -1;
688 for( i = 0 ; i < title_inf.i_title_nb ; i++ )
690 p_current = FillBuffer( p_ifo, pi_buffer, i_start +
691 title_inf.pi_start_byte[i] );
693 title_inf.p_title_start[i].i_title_id =
694 ReadWord( p_ifo, pi_buffer, &p_current );
695 title_inf.p_title_start[i].i_chapter = ReadWord( p_ifo, pi_buffer, &p_current );
696 //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 );
699 #undef title_inf
702 * menu unit information
704 if( manager_inf.i_menu_unit_start_sector )
706 if( ReadTitleUnit( p_ifo, &p_ifo->vts.menu_unit, p_ifo->vts.i_pos +
707 manager_inf.i_menu_unit_start_sector *DVD_LB_SIZE ) < 0 )
709 return -1;
714 * title unit information
716 if( manager_inf.i_title_unit_start_sector )
718 if( ReadUnitInf( p_ifo, &p_ifo->vts.title_unit, p_ifo->vts.i_pos +
719 manager_inf.i_title_unit_start_sector *DVD_LB_SIZE ) < 0 )
721 return -1;
726 * time map inforamtion
728 #define time_inf p_ifo->vts.time_inf
729 if( manager_inf.i_time_inf_start_sector )
731 u8 pi_buffer[DVD_LB_SIZE];
733 p_current = FillBuffer( p_ifo, pi_buffer, p_ifo->vts.i_pos +
734 manager_inf.i_time_inf_start_sector *DVD_LB_SIZE );
736 //fprintf( stderr, "TMAP\n" );
738 time_inf.i_nb = ReadWord( p_ifo, pi_buffer, &p_current );;
739 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
740 time_inf.i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
742 time_inf.pi_start_byte = malloc( time_inf.i_nb *sizeof(u32) );
743 if( time_inf.pi_start_byte == NULL )
745 intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" );
746 return -1;
749 for( i = 0 ; i < time_inf.i_nb ; i++ )
751 time_inf.pi_start_byte[i] = ReadDouble( p_ifo, pi_buffer, &p_current );
754 time_inf.p_time_map = malloc( time_inf.i_nb *sizeof(time_map_t) );
755 if( time_inf.p_time_map == NULL )
757 intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" );
758 return -1;
761 for( i = 0 ; i < time_inf.i_nb ; i++ )
763 time_inf.p_time_map[i].i_time_unit = ReadByte( p_ifo, pi_buffer, &p_current );
764 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
765 time_inf.p_time_map[i].i_entry_nb = ReadWord( p_ifo, pi_buffer, &p_current );
767 time_inf.p_time_map[i].pi_sector =
768 malloc( time_inf.p_time_map[i].i_entry_nb *sizeof(u32) );
769 if( time_inf.p_time_map[i].pi_sector == NULL )
771 intf_ErrMsg( "ifo error: out of memory in IfoTitleSet" );
772 return -1;
775 for( j = 0 ; j < time_inf.p_time_map[i].i_entry_nb ; j++ )
777 time_inf.p_time_map[i].pi_sector[j] = ReadDouble( p_ifo, pi_buffer, &p_current );
781 #undef time_inf
783 if( manager_inf.i_menu_cell_inf_start_sector )
785 if( ReadCellInf( p_ifo, &p_ifo->vts.menu_cell_inf, p_ifo->vts.i_pos +
786 manager_inf.i_menu_cell_inf_start_sector *DVD_LB_SIZE ) < 0 )
788 return -1;
792 if( manager_inf.i_menu_vobu_map_start_sector )
794 if( ReadVobuMap( p_ifo, &p_ifo->vts.menu_vobu_map, p_ifo->vts.i_pos +
795 manager_inf.i_menu_vobu_map_start_sector *DVD_LB_SIZE ) < 0 )
797 return -1;
801 if( manager_inf.i_cell_inf_start_sector )
803 if( ReadCellInf( p_ifo, &p_ifo->vts.cell_inf, p_ifo->vts.i_pos +
804 manager_inf.i_cell_inf_start_sector *DVD_LB_SIZE ) )
806 return -1;
810 if( manager_inf.i_vobu_map_start_sector )
812 if( ReadVobuMap( p_ifo, &p_ifo->vts.vobu_map, p_ifo->vts.i_pos +
813 manager_inf.i_vobu_map_start_sector *DVD_LB_SIZE ) )
815 return -1;
818 #undef manager_inf
820 intf_WarnMsg( 2, "ifo info: vts %d initialized",
821 p_ifo->vmg.title_inf.p_attr[p_ifo->i_title-1].i_title_set_num );
823 p_ifo->vts.b_initialized = 1;
825 return 0;
828 /*****************************************************************************
829 * FreeTitleSet : free all structures allocated by IfoTitleSet
830 *****************************************************************************/
831 static int FreeTitleSet( vts_t * p_vts )
833 int i;
835 if( p_vts->manager_inf.i_vobu_map_start_sector )
837 FreeVobuMap( &p_vts->vobu_map );
840 if( p_vts->manager_inf.i_cell_inf_start_sector )
842 FreeCellInf( &p_vts->cell_inf );
845 if( p_vts->manager_inf.i_menu_vobu_map_start_sector )
847 FreeVobuMap( &p_vts->menu_vobu_map );
850 if( p_vts->manager_inf.i_menu_cell_inf_start_sector )
852 FreeCellInf( &p_vts->menu_cell_inf );
855 if( p_vts->manager_inf.i_time_inf_start_sector )
857 for( i = 0 ; i < p_vts->time_inf.i_nb ; i++ )
859 free( p_vts->time_inf.p_time_map[i].pi_sector );
862 free( p_vts->time_inf.p_time_map );
863 free( p_vts->time_inf.pi_start_byte );
866 if( p_vts->manager_inf.i_title_unit_start_sector )
868 FreeUnitInf( &p_vts->title_unit );
871 if( p_vts->manager_inf.i_menu_unit_start_sector )
873 FreeTitleUnit( &p_vts->menu_unit );
876 if( p_vts->manager_inf.i_title_inf_start_sector )
878 free( p_vts->title_inf.pi_start_byte );
879 free( p_vts->title_inf.p_title_start );
882 p_vts->b_initialized = 0;
884 return 0;
887 /*****************************************************************************
888 * IfoDestroy : Frees all the memory allocated to ifo structures
889 *****************************************************************************/
890 void IfoDestroy( ifo_t * p_ifo )
892 int i, j;
894 FreeTitleSet( &p_ifo->vts );
896 if( p_ifo->vmg.manager_inf.i_vobu_map_start_sector )
898 FreeVobuMap( &p_ifo->vmg.vobu_map );
901 if( p_ifo->vmg.manager_inf.i_cell_inf_start_sector )
903 FreeCellInf( &p_ifo->vmg.cell_inf );
906 if( p_ifo->vmg.manager_inf.i_vts_inf_start_sector )
908 free( p_ifo->vmg.vts_inf.p_vts_attr );
909 free( p_ifo->vmg.vts_inf.pi_vts_attr_start_byte );
912 /* free parental information structures */
913 if( p_ifo->vmg.manager_inf.i_parental_inf_start_sector )
915 for( i = 0 ; i < p_ifo->vmg.parental_inf.i_country_nb ; i++ )
917 for( j = 0 ; j < 8 ; j++ )
919 free( p_ifo->vmg.parental_inf.p_parental_mask[i].ppi_mask[j] );
923 free( p_ifo->vmg.parental_inf.p_parental_mask );
924 free( p_ifo->vmg.parental_inf.p_parental_desc );
927 if( p_ifo->vmg.manager_inf.i_title_unit_start_sector )
929 FreeTitleUnit( &p_ifo->vmg.title_unit );
932 if( p_ifo->vmg.manager_inf.i_title_inf_start_sector )
934 free( p_ifo->vmg.title_inf.p_attr );
937 FreeTitle( &p_ifo->vmg.title );
939 free( p_ifo );
941 return;
944 * Function common to Video Manager and Video Title set Processing
947 /*****************************************************************************
948 * ReadTitle : Fills the title structure.
949 *****************************************************************************
950 * Titles are logical stream units that correspond to a whole inside the dvd.
951 * Several title can point to the same part of the physical DVD, and give
952 * map to different anglesfor instance.
953 *****************************************************************************/
954 static int ReadTitle( ifo_t * p_ifo, title_t * p_title, off_t i_pos )
956 u8 pi_buffer[DVD_LB_SIZE];
957 u8 * p_current;
958 off_t i_start;
959 u16 i_audio;
960 u32 i_spu;
961 int i;
963 p_current = FillBuffer( p_ifo, pi_buffer, i_pos );
965 i_start = p_ifo->i_pos;
967 //fprintf( stderr, "PGC @ %lld\n",p_ifo->i_pos );
969 DumpBits( p_ifo, pi_buffer, &p_current, 2);
970 p_title->i_chapter_nb = ReadByte( p_ifo, pi_buffer, &p_current );
971 p_title->i_cell_nb = ReadByte( p_ifo, pi_buffer, &p_current );
972 //fprintf( stderr, "title: Prg: %d Cell: %d\n",p_title->i_chapter_nb,p_title->i_cell_nb );
973 p_title->i_play_time = ReadDouble( p_ifo, pi_buffer, &p_current );
974 p_title->i_prohibited_user_op = ReadDouble( p_ifo, pi_buffer, &p_current );
975 for( i = 0 ; i < 8 ; i++ )
977 i_audio = ReadWord( p_ifo, pi_buffer, &p_current );
978 p_title->pi_audio_status[i].i_foo = i_audio & 0xff;
979 i_audio >>= 8;
980 p_title->pi_audio_status[i].i_position = i_audio & 0x07;
981 i_audio >>= 7;
982 p_title->pi_audio_status[i].i_available = i_audio;
984 for( i = 0 ; i < 32 ; i++ )
986 i_spu = ReadDouble( p_ifo, pi_buffer, &p_current );
987 p_title->pi_spu_status[i].i_position_pan = i_spu & 0x1f;
988 i_spu >>= 8;
989 p_title->pi_spu_status[i].i_position_letter = i_spu & 0x1f;
990 i_spu >>= 8;
991 p_title->pi_spu_status[i].i_position_wide = i_spu & 0x1f;
992 i_spu >>= 8;
993 p_title->pi_spu_status[i].i_position_43 = i_spu & 0x1f;
994 i_spu >>= 7;
995 p_title->pi_spu_status[i].i_available = i_spu;
997 p_title->i_next_title_num = ReadWord( p_ifo, pi_buffer, &p_current );
998 p_title->i_prev_title_num = ReadWord( p_ifo, pi_buffer, &p_current );
999 p_title->i_go_up_title_num = ReadWord( p_ifo, pi_buffer, &p_current );
1000 //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 );
1001 p_title->i_still_time = ReadByte( p_ifo, pi_buffer, &p_current );
1002 p_title->i_play_mode = ReadByte( p_ifo, pi_buffer, &p_current );
1003 for( i = 0 ; i < 16 ; i++ )
1005 p_title->pi_yuv_color[i] = ReadDouble( p_ifo, pi_buffer, &p_current );
1006 /* FIXME : We have to erase the extra bit */
1008 p_title->i_command_start_byte = ReadWord( p_ifo, pi_buffer, &p_current );
1009 p_title->i_chapter_map_start_byte = ReadWord( p_ifo, pi_buffer, &p_current );
1010 p_title->i_cell_play_start_byte = ReadWord( p_ifo, pi_buffer, &p_current );
1011 p_title->i_cell_pos_start_byte = ReadWord( p_ifo, pi_buffer, &p_current );
1013 /* parsing of command_t */
1014 if( p_title->i_command_start_byte )
1016 p_current = FillBuffer( p_ifo, pi_buffer,
1017 i_start + p_title->i_command_start_byte );
1019 /* header */
1020 p_title->command.i_pre_command_nb = ReadWord( p_ifo, pi_buffer, &p_current );
1021 p_title->command.i_post_command_nb = ReadWord( p_ifo, pi_buffer, &p_current );
1022 p_title->command.i_cell_command_nb = ReadWord( p_ifo, pi_buffer, &p_current );
1023 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
1025 /* pre-title commands */
1026 if( p_title->command.i_pre_command_nb )
1028 p_title->command.p_pre_command =
1029 malloc( p_title->command.i_pre_command_nb
1030 *sizeof(command_desc_t) );
1032 if( p_title->command.p_pre_command == NULL )
1034 intf_ErrMsg( "ifo error: out of memory in ReadTitle" );
1035 return -1;
1038 for( i = 0 ; i < p_title->command.i_pre_command_nb ; i++ )
1040 p_title->command.p_pre_command[i] = ReadQuad( p_ifo, pi_buffer, &p_current );
1043 else
1045 p_title->command.p_pre_command = NULL;
1048 /* post-title commands */
1049 if( p_title->command.i_post_command_nb )
1051 p_title->command.p_post_command =
1052 malloc( p_title->command.i_post_command_nb
1053 *sizeof(command_desc_t) );
1055 if( p_title->command.p_post_command == NULL )
1057 intf_ErrMsg( "ifo error: out of memory in ReadTitle" );
1058 return -1;
1061 for( i=0 ; i<p_title->command.i_post_command_nb ; i++ )
1063 p_title->command.p_post_command[i] = ReadQuad( p_ifo, pi_buffer, &p_current );
1066 else
1068 p_title->command.p_post_command = NULL;
1071 /* cell commands */
1072 if( p_title->command.i_cell_command_nb )
1074 p_title->command.p_cell_command =
1075 malloc( p_title->command.i_cell_command_nb
1076 *sizeof(command_desc_t) );
1078 if( p_title->command.p_cell_command == NULL )
1080 intf_ErrMsg( "ifo error: out of memory in ReadTitle" );
1081 return -1;
1084 for( i=0 ; i<p_title->command.i_cell_command_nb ; i++ )
1086 p_title->command.p_cell_command[i] = ReadQuad( p_ifo, pi_buffer, &p_current );
1089 else
1091 p_title->command.p_cell_command = NULL;
1095 /* parsing of chapter_map_t: it gives the entry cell for each chapter */
1096 if( p_title->i_chapter_map_start_byte )
1098 p_ifo->i_pos = lseek( p_ifo->i_fd,
1099 i_start + p_title->i_chapter_map_start_byte,
1100 SEEK_SET );
1102 p_title->chapter_map.pi_start_cell =
1103 malloc( p_title->i_chapter_nb *sizeof(chapter_map_t) );
1105 if( p_title->chapter_map.pi_start_cell == NULL )
1107 intf_ErrMsg( "ifo error: out of memory in Read Title" );
1108 return -1;
1111 ReadBits( p_ifo, pi_buffer, &p_current, p_title->chapter_map.pi_start_cell,
1112 p_title->i_chapter_nb );
1114 else
1116 p_title->chapter_map.pi_start_cell = NULL;
1119 /* parsing of cell_play_t */
1120 if( p_title->i_cell_play_start_byte )
1122 p_current = FillBuffer( p_ifo, pi_buffer,
1123 i_start + p_title->i_cell_play_start_byte );
1125 p_title->p_cell_play = malloc( p_title->i_cell_nb
1126 *sizeof(cell_play_t) );
1128 if( p_title->p_cell_play == NULL )
1130 intf_ErrMsg( "ifo error: out of memory in ReadTitle" );
1131 return -1;
1134 for( i = 0 ; i < p_title->i_cell_nb ; i++ )
1136 p_title->p_cell_play[i].i_category = ReadWord( p_ifo, pi_buffer, &p_current );
1137 p_title->p_cell_play[i].i_still_time = ReadByte( p_ifo, pi_buffer, &p_current );
1138 p_title->p_cell_play[i].i_command_nb = ReadByte( p_ifo, pi_buffer, &p_current );
1139 p_title->p_cell_play[i].i_play_time = ReadDouble( p_ifo, pi_buffer, &p_current );
1140 p_title->p_cell_play[i].i_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
1141 p_title->p_cell_play[i].i_first_ilvu_vobu_esector =
1142 ReadDouble( p_ifo, pi_buffer, &p_current );
1143 p_title->p_cell_play[i].i_last_vobu_start_sector =
1144 ReadDouble( p_ifo, pi_buffer, &p_current );
1145 p_title->p_cell_play[i].i_end_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
1149 /* Parsing of cell_pos_t */
1150 if( p_title->i_cell_pos_start_byte )
1152 p_current = FillBuffer( p_ifo, pi_buffer,
1153 i_start + p_title->i_cell_pos_start_byte );
1155 p_title->p_cell_pos = malloc( p_title->i_cell_nb
1156 *sizeof(cell_pos_t) );
1158 if( p_title->p_cell_pos == NULL )
1160 intf_ErrMsg( "ifo error: out of memory" );
1161 return -1;
1164 for( i = 0 ; i < p_title->i_cell_nb ; i++ )
1166 p_title->p_cell_pos[i].i_vob_id = ReadWord( p_ifo, pi_buffer, &p_current );
1167 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
1168 p_title->p_cell_pos[i].i_cell_id = ReadByte( p_ifo, pi_buffer, &p_current );
1172 return 0;
1175 /*****************************************************************************
1176 * FreeTitle: frees alla structure allocated by a call to ReadTitle
1177 *****************************************************************************/
1178 static int FreeTitle( title_t * p_title )
1180 if( p_title->i_command_start_byte )
1182 if( p_title->command.i_pre_command_nb )
1184 free( p_title->command.p_pre_command );
1187 if( p_title->command.i_post_command_nb )
1189 free( p_title->command.p_post_command );
1192 if( p_title->command.i_cell_command_nb )
1194 free( p_title->command.p_cell_command );
1197 if( p_title->i_chapter_map_start_byte )
1199 free( p_title->chapter_map.pi_start_cell );
1202 if( p_title->i_cell_play_start_byte )
1204 free( p_title->p_cell_play );
1207 if( p_title->i_cell_pos_start_byte )
1209 free( p_title->p_cell_pos );
1213 return 0;
1216 /*****************************************************************************
1217 * ReadUnitInf : Fills Menu Language Unit Table/ PGC Info Table
1218 *****************************************************************************/
1219 static int ReadUnitInf( ifo_t * p_ifo, unit_inf_t * p_unit_inf, off_t i_pos )
1221 u8 pi_buffer[DVD_LB_SIZE];
1222 u8 * p_current;
1223 off_t i_start;
1224 int i;
1226 p_current = FillBuffer( p_ifo, pi_buffer, i_pos );
1228 i_start = p_ifo->i_pos;
1229 //fprintf( stderr, "Unit\n" );
1231 p_unit_inf->i_title_nb = ReadWord( p_ifo, pi_buffer, &p_current );
1232 //fprintf( stderr, "Unit nb: %d\n", p_unit_inf->i_title_nb );
1233 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
1234 p_unit_inf->i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
1236 p_unit_inf->p_title =
1237 malloc( p_unit_inf->i_title_nb *sizeof(unit_title_t) );
1238 if( p_unit_inf->p_title == NULL )
1240 intf_ErrMsg( "ifo error: out of memory in ReadUnit" );
1241 return -1;
1244 for( i = 0 ; i < p_unit_inf->i_title_nb ; i++ )
1246 p_unit_inf->p_title[i].i_category_mask = ReadByte( p_ifo, pi_buffer, &p_current );
1247 p_unit_inf->p_title[i].i_category = ReadByte( p_ifo, pi_buffer, &p_current );
1248 //fprintf( stderr, "cat mask %d: %x cat %x\n", i, p_unit_inf->p_title[i].i_category_mask, p_unit_inf->p_title[i].i_category );
1249 p_unit_inf->p_title[i].i_parental_mask = ReadWord( p_ifo, pi_buffer, &p_current );
1250 p_unit_inf->p_title[i].i_title_start_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
1253 for( i = 0 ; i < p_unit_inf->i_title_nb ; i++ )
1255 //fprintf( stderr, "Unit: PGC %d @ %lld\n", i, p_ifo->i_pos );
1256 ReadTitle( p_ifo, &p_unit_inf->p_title[i].title, i_start +
1257 p_unit_inf->p_title[i].i_title_start_byte );
1260 return 0;
1263 /*****************************************************************************
1264 * FreeUnitInf : frees a structure allocated by ReadUnit
1265 *****************************************************************************/
1266 static int FreeUnitInf( unit_inf_t * p_unit_inf )
1268 if( p_unit_inf->p_title != NULL )
1270 free( p_unit_inf->p_title );
1273 return 0;
1277 /*****************************************************************************
1278 * ReadTitleUnit: Fills the Title Unit structure.
1279 *****************************************************************************/
1280 static int ReadTitleUnit( ifo_t * p_ifo, title_unit_t * p_title_unit,
1281 off_t i_pos )
1283 u8 pi_buffer[DVD_LB_SIZE];
1284 u8 * p_current;
1285 int i;
1286 off_t i_start;
1288 p_current = FillBuffer( p_ifo, pi_buffer, i_pos );
1289 i_start = p_ifo->i_pos;
1290 //fprintf( stderr, "Unit Table\n" );
1292 p_title_unit->i_unit_nb = ReadWord( p_ifo, pi_buffer, &p_current );
1293 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
1294 p_title_unit->i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
1296 //fprintf(stderr, "Unit: nb %d end %d\n", p_title_unit->i_unit_nb, p_title_unit->i_end_byte );
1298 p_title_unit->p_unit = malloc( p_title_unit->i_unit_nb *sizeof(unit_t) );
1299 if( p_title_unit->p_unit == NULL )
1301 intf_ErrMsg( "ifo error: out of memory in ReadTitleUnit" );
1302 return -1;
1305 for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ )
1307 //ReadBits( p_ifo, pi_buffer, &p_current, p_title_unit->p_unit[i].ps_lang_code, 2 );
1308 p_title_unit->p_unit[i].i_lang_code = ReadWord( p_ifo, pi_buffer, &p_current );
1309 //fprintf( stderr, "lang %d %x\n", i,p_title_unit->p_unit[i].i_lang_code );
1310 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
1311 p_title_unit->p_unit[i].i_existence_mask = ReadByte( p_ifo, pi_buffer, &p_current );
1312 p_title_unit->p_unit[i].i_unit_inf_start_byte =
1313 ReadDouble( p_ifo, pi_buffer, &p_current );
1316 p_title_unit->p_unit_inf =
1317 malloc( p_title_unit->i_unit_nb *sizeof(unit_inf_t) );
1318 if( p_title_unit->p_unit_inf == NULL )
1320 intf_ErrMsg( "ifo error: out of memory in ReadTitleUnit" );
1321 return -1;
1324 for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ )
1326 ReadUnitInf( p_ifo, &p_title_unit->p_unit_inf[i], i_start +
1327 p_title_unit->p_unit[i].i_unit_inf_start_byte );
1330 return 0;
1333 /*****************************************************************************
1334 * FreeTitleUnit: frees a structure allocateed by ReadTitleUnit
1335 *****************************************************************************/
1336 static int FreeTitleUnit( title_unit_t * p_title_unit )
1338 int i;
1340 if( p_title_unit->p_unit_inf != NULL )
1342 for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ )
1344 FreeUnitInf( &p_title_unit->p_unit_inf[i] );
1347 free( p_title_unit->p_unit_inf );
1350 return 0;
1353 /*****************************************************************************
1354 * ReadCellInf : Fills the Cell Information structure.
1355 *****************************************************************************/
1356 static int ReadCellInf( ifo_t * p_ifo, cell_inf_t * p_cell_inf, off_t i_pos )
1358 u8 pi_buffer[DVD_LB_SIZE];
1359 u8 * p_current;
1360 off_t i_start;
1361 int i;
1363 p_current = FillBuffer( p_ifo, pi_buffer, i_pos );
1364 i_start = p_ifo->i_pos;
1365 //fprintf( stderr, "CELL ADD\n" );
1367 p_cell_inf->i_vob_nb = ReadWord( p_ifo, pi_buffer, &p_current );
1368 DumpBits( p_ifo, pi_buffer, &p_current, 2 );
1369 p_cell_inf->i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
1371 p_cell_inf->i_cell_nb = (p_cell_inf->i_end_byte/* - 7*/) / sizeof(cell_map_t);
1373 //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 );
1375 p_cell_inf->p_cell_map =
1376 malloc( p_cell_inf->i_cell_nb *sizeof(cell_map_t) );
1377 if( p_cell_inf->p_cell_map == NULL )
1379 intf_ErrMsg( "ifo error: out of memory in ReadCellInf" );
1380 return -1;
1383 for( i = 0 ; i < p_cell_inf->i_cell_nb ; i++ )
1385 p_cell_inf->p_cell_map[i].i_vob_id = ReadWord( p_ifo, pi_buffer, &p_current );
1386 p_cell_inf->p_cell_map[i].i_cell_id = ReadByte( p_ifo, pi_buffer, &p_current );
1387 DumpBits( p_ifo, pi_buffer, &p_current, 1 );
1388 p_cell_inf->p_cell_map[i].i_start_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
1389 // fprintf(stderr, "sector[%d] %d (%lld)\n", i,ntohl(*(u32*)(p_current)), p_ifo->i_pos);
1390 p_cell_inf->p_cell_map[i].i_end_sector = ReadDouble( p_ifo, pi_buffer, &p_current );
1393 return 0;
1396 /*****************************************************************************
1397 * FreeCellInf : frees structures allocated by ReadCellInf
1398 *****************************************************************************/
1399 static int FreeCellInf( cell_inf_t * p_cell_inf )
1401 free( p_cell_inf->p_cell_map );
1403 return 0;
1406 /*****************************************************************************
1407 * ReadVobuMap : Fills the VOBU Map structure.
1408 *****************************************************************************/
1409 static int ReadVobuMap( ifo_t * p_ifo, vobu_map_t * p_vobu_map, off_t i_pos )
1411 u8 pi_buffer[DVD_LB_SIZE];
1412 u8 * p_current;
1413 off_t i_start;
1414 int i, i_max;
1416 p_current = FillBuffer( p_ifo, pi_buffer, i_pos );
1417 i_start = p_ifo->i_pos;
1418 //fprintf( stderr, "VOBU ADMAP\n" );
1420 p_vobu_map->i_end_byte = ReadDouble( p_ifo, pi_buffer, &p_current );
1421 i_max = ( i_start + p_vobu_map->i_end_byte + 1 - p_ifo->i_pos )
1422 / sizeof(u32);
1424 p_vobu_map->pi_vobu_start_sector = malloc( i_max *sizeof(u32) );
1425 if( p_vobu_map->pi_vobu_start_sector == NULL )
1427 intf_ErrMsg( "ifo error: out of memory in ReadVobuMap" );
1428 return -1;
1431 for( i = 0 ; i < i_max ; i++ )
1433 p_vobu_map->pi_vobu_start_sector[i] = ReadDouble( p_ifo, pi_buffer, &p_current );
1436 return 0;
1439 /*****************************************************************************
1440 * FreeVobuMap: frees structures allocated by ReadVobuMap
1441 *****************************************************************************/
1442 static int FreeVobuMap( vobu_map_t * p_vobu_map )
1444 free( p_vobu_map->pi_vobu_start_sector );
1446 return 0;
1450 * IFO virtual machine : a set of commands that give the
1451 * interactive behaviour of the dvd
1453 #if 0
1455 #define OP_VAL_16(i) (ntoh16( com.data.pi_16[i]))
1456 #define OP_VAL_8(i) ((com.data.pi_8[i]))
1458 static char ifo_reg[][80]=
1460 "Menu_Language_Code",
1461 "Audio_Stream_#",
1462 "SubPicture_Stream_#",
1463 "Angle_#",
1464 "VTS_#",
1465 "VTS_Title_#",
1466 "PGC_#",
1467 "PTT_#",
1468 "Highlighted_Button_#",
1469 "Nav_Timer",
1470 "TimedPGC",
1471 "Karaoke_audio_mixing_mode",
1472 "Parental_mgmt_country_code",
1473 "Parental_Level",
1474 "Player_Video_Cfg",
1475 "Player_Audio_Cfg",
1476 "Audio_language_code_setting",
1477 "Audio_language_extension_code",
1478 "SPU_language_code_setting",
1479 "SPU_language_extension_code",
1480 "?Player_Regional_Code",
1481 "Reserved_21",
1482 "Reserved_22",
1483 "Reserved_23"
1486 static char * IfoMath( char val )
1488 static char math_op[][10] =
1490 "none",
1491 "=",
1492 "<->", // swap
1493 "+=",
1494 "-=",
1495 "*=",
1496 "/=",
1497 "%=",
1498 "rnd", // rnd
1499 "&=",
1500 "|=",
1501 "^=",
1502 "??", // invalid
1503 "??", // invalid
1504 "??", // invalid
1505 "??" // invalid
1508 return (char *) math_op[val & 0x0f];
1512 char ifo_cmp[][10] =
1514 "none",
1515 "&&",
1516 "==",
1517 "!=",
1518 ">=",
1519 ">",
1520 "<",
1521 "<="
1524 char ifo_parental[][10] =
1526 "0",
1527 "G",
1528 "2",
1529 "PG",
1530 "PG-13",
1531 "5",
1532 "R",
1533 "NC-17"
1536 char ifo_menu_id[][80] =
1538 "-0-",
1539 "-1-",
1540 "Title (VTS menu)",
1541 "Root",
1542 "Sub-Picture",
1543 "Audio",
1544 "Angle",
1545 "Part of Title",
1548 char * IfoMenuName( char index )
1550 return ifo_menu_id[index&0x07];
1553 static void IfoRegister( u16 i_data, u8 i_direct)
1555 if( i_direct )
1557 if( 0/*isalpha( i_data >> 8 & 0xff )*/ )
1559 printf("'%c%c'", i_data>>8&0xff, i_data&0xff);
1561 else
1563 printf("0x%02x", i_data);
1566 else
1568 if( i_data & 0x80 )
1570 i_data &= 0x1f;
1572 if( i_data > 0x17 )
1574 printf("s[ILL]");
1576 else
1578 printf("s[%s]", ifo_reg[i_data]);
1581 else
1583 i_data &= 0x1f;
1585 if( i_data > 0xf )
1587 printf("r[ILL]");
1589 else
1591 printf("r[0x%02x]", i_data);
1597 static void IfoAdvanced( u8 *pi_code )
1599 u8 i_cmd = pi_code[0];
1601 printf(" { ");
1603 if( pi_code[1]>>2 )
1605 printf( " Highlight button %d; ", pi_code[1]>>2 );
1608 if( i_cmd == 0xff )
1610 printf( " Illegal " );
1613 if( i_cmd == 0x00 )
1615 printf( "ReSuME %d", pi_code[7] );
1617 else if( ( i_cmd & 0x06) == 0x02 )
1618 { // XX01Y
1619 printf ("Link to %s cell ", ( i_cmd & 0x01 ) ? "prev" : "next");
1621 else
1623 printf( "advanced (0x%02x) ", i_cmd );
1625 printf(" } ");
1628 static void IfoJmp( ifo_command_t com )
1631 printf ("jmp ");
1633 switch( com.i_sub_cmd )
1635 case 0x01:
1636 printf( "Exit" );
1637 break;
1638 case 0x02:
1639 printf( "VTS 0x%02x", OP_VAL_8(3) );
1640 break;
1641 case 0x03:
1642 printf( "This VTS Title 0x%02x", OP_VAL_8(3) );
1643 break;
1644 case 0x05:
1645 printf( "This VTS Title 0x%02x Part 0x%04x",
1646 OP_VAL_8(3),
1647 OP_VAL_8(0)<<8|OP_VAL_8(1));
1648 break;
1649 case 0x06:
1650 #if 0
1651 printf ("in SystemSpace ");
1652 switch (OP_VAL_8(3)>>4) {
1653 case 0x00:
1654 printf ("to play first PGC");
1655 break;
1656 case 0x01: {
1657 printf ("to menu \"%s\"", decode_menuname (OP_VAL_8(3)));
1659 break;
1660 case 0x02:
1661 printf ("to VTS 0x%02x and TTN 0x%02x", OP_VAL_8(1), OP_VAL_8(2));
1662 break;
1663 case 0x03:
1664 printf ("to VMGM PGC number 0x%02x", OP_VAL_8(0)<<8 | OP_VAL_8(1));
1665 break;
1666 case 0x08:
1667 printf ("vts 0x%02x lu 0x%02x menu \"%s\"", OP_VAL_8(2), OP_VAL_8(1), decode_menuname (OP_VAL_8(3)));
1668 break;
1669 #else
1670 switch( OP_VAL_8(3)>>6 )
1672 case 0x00:
1673 printf( "to play first PGC" );
1674 break;
1675 case 0x01:
1676 printf( "to VMG title menu (?)" );
1677 break;
1678 case 0x02:
1679 printf( "vts 0x%02x lu 0x%02x menu \"%s\"",
1680 OP_VAL_8(2),
1681 OP_VAL_8(1),
1682 IfoMenuName( OP_VAL_8(3)&0xF ) );
1683 break;
1684 case 0x03:
1685 printf( "vmg pgc 0x%04x (?)", ( OP_VAL_8(0)<<8) | OP_VAL_8(1) );
1686 break;
1687 #endif
1689 break;
1690 case 0x08:
1691 #if 0
1692 switch(OP_VAL_8(3)>>4) {
1693 case 0x00:
1694 printf ("system first pgc");
1695 break;
1696 case 0x01:
1697 printf ("system title menu");
1698 break;
1699 case 0x02:
1700 printf ("system menu \"%s\"", decode_menuname (OP_VAL_8(3)));
1701 break;
1702 case 0x03:
1703 printf ("system vmg pgc %02x ????", OP_VAL_8(0)<<8|OP_VAL_8(1));
1704 break;
1705 case 0x08:
1706 printf ("system lu 0x%02x menu \"%s\"", OP_VAL_8(2), decode_menuname (OP_VAL_8(3)));
1707 break;
1708 case 0x0c:
1709 printf ("system vmg pgc 0x%02x", OP_VAL_8(0)<<8|OP_VAL_8(1));
1710 break;
1712 #else
1713 // OP_VAL_8(2) is number of cell
1714 // it is processed BEFORE switch
1715 // under some conditions, it is ignored
1716 // I don't understand exactly what it means
1717 printf( " ( spec cell 0x%02X ) ", OP_VAL_8(2) );
1719 switch( OP_VAL_8(3)>>6 )
1721 case 0:
1722 printf( "to FP PGC" );
1723 break;
1724 case 1:
1725 printf( "to VMG root menu (?)" );
1726 break;
1727 case 2:
1728 printf( "to VTS menu \"%s\" (?)",
1729 IfoMenuName(OP_VAL_8(3)&0xF) );
1730 break;
1731 case 3:
1732 printf( "vmg pgc 0x%02x (?)", (OP_VAL_8(0)<<8)|OP_VAL_8(1) );
1733 break;
1735 #endif
1736 break;
1740 static void IfoLnk( ifo_command_t com )
1742 u16 i_button=OP_VAL_8(4)>>2;
1744 printf ("lnk to ");
1746 switch( com.i_sub_cmd )
1748 case 0x01:
1749 IfoAdvanced( &OP_VAL_8(4) );
1750 break;
1752 case 0x04:
1753 printf( "PGC 0x%02x", OP_VAL_16(2) );
1754 break;
1756 case 0x05:
1757 printf( "PTT 0x%02x", OP_VAL_16(2) );
1758 break;
1760 case 0x06:
1761 printf( "Program 0x%02x this PGC", OP_VAL_8(5) );
1762 break;
1764 case 0x07:
1765 printf( "Cell 0x%02x this PGC", OP_VAL_8(5) );
1766 break;
1767 default:
1768 return;
1771 if( i_button )
1773 printf( ", Highlight 0x%02x", OP_VAL_8(4)>>2 );
1778 void IfoSetSystem( ifo_command_t com )
1780 switch( com.i_cmd )
1782 case 1: {
1783 int i;
1785 for( i=1; i<=3; i++ )
1787 if( OP_VAL_8(i)&0x80 )
1789 if( com.i_direct )
1791 printf ("s[%s] = 0x%02x;", ifo_reg[i], OP_VAL_8(i)&0xf);
1793 else
1795 printf ("s[%s] = r[0x%02x];", ifo_reg[i], OP_VAL_8(i)&0xf);
1799 #if 0
1800 if(op->direct) {
1801 if(OP_VAL_8(1]&0x80)
1802 printf ("s[%s] = 0x%02x;", reg_name[1], OP_VAL_8(1]&0xf);
1803 if(OP_VAL_8(2)&0x80)
1804 //DENT: lwhat about 0x7f here ???
1805 printf ("s[%s] = 0x%02x;", reg_name[2], OP_VAL_8(2)&0x7f);
1806 if(OP_VAL_8(3)&0x80)
1807 printf ("s[%s] = 0x%02x;", reg_name[3], OP_VAL_8(3)&0xf);
1808 } else {
1809 if(OP_VAL_8(1)&0x80)
1810 printf ("s[%s] = r[0x%02x];", reg_name[1], OP_VAL_8(1)&0xf);
1811 if(OP_VAL_8(2)&0x80)
1812 printf ("s[%s] = r[0x%02x];", reg_name[2], OP_VAL_8(2)&0xf);
1813 if(OP_VAL_8(3)&0x80)
1814 printf ("s[%s] = r[0x%02x];", reg_name[3], OP_VAL_8(3)&0xf);
1816 #endif
1818 break;
1819 case 2:
1820 if( com.i_direct )
1822 printf( "s[%s] = 0x%02x", ifo_reg[9], OP_VAL_16(0) );
1824 else
1826 printf( "s[%s] = r[0x%02x]", ifo_reg[9], OP_VAL_8(1)&0x0f );
1829 printf( "s[%s] = (s[%s]&0x7FFF)|0x%02x",
1830 ifo_reg[10], ifo_reg[10], OP_VAL_16(1)&0x8000);
1831 break;
1832 case 3:
1833 if( com.i_direct )
1835 printf( "r[0x%02x] = 0x%02x", OP_VAL_8(3)&0x0f, OP_VAL_16(0) );
1837 else
1839 printf ("r[r[0x%02x]] = r[0x%02x]",
1840 OP_VAL_8(3)&0x0f, OP_VAL_8(1)&0x0f);
1842 break;
1843 case 4:
1844 //actually only bits 00011100 00011100 are set
1845 if( com.i_direct )
1847 printf ("s[%s] = 0x%02x", ifo_reg[11], OP_VAL_16(1));
1849 else
1851 printf ("s[%s] = r[0x%02x]", ifo_reg[11], OP_VAL_8(3)&0x0f );
1853 break;
1854 case 6:
1855 //actually,
1856 //s[%s]=(r[%s]&0x3FF) | (0x%02x << 0xA);
1857 //but it is way too ugly
1858 if( com.i_direct )
1860 printf( "s[%s] = 0x%02x", ifo_reg[8], OP_VAL_8(2)>>2 );
1862 else
1864 printf( "s[%s] = r[0x%02x]", ifo_reg[8], OP_VAL_8(3)&0x0f );
1866 break;
1867 default:
1868 printf ("unknown");
1872 static void IfoSet( ifo_command_t com )
1874 IfoRegister( OP_VAL_16(0), 0 );
1875 printf( " %s ", IfoMath( com.i_cmd ) );
1876 IfoRegister( OP_VAL_16(1), com.i_direct );
1879 /*****************************************************************************
1880 * CommandRead : translates the command strings in ifo into command
1881 * structures.
1882 *****************************************************************************/
1883 void CommandRead( ifo_command_t com )
1885 u8* pi_code = (u8*)(&com);
1887 switch( com.i_type )
1889 /* Goto */
1890 case 0:
1891 /* Main command */
1892 if( !pi_code[1] )
1894 printf( "NOP\n" );
1896 else
1898 if( com.i_cmp )
1900 printf ("if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
1901 ifo_cmp[com.i_cmp]);
1902 IfoRegister (OP_VAL_16(1), com.i_dir_cmp);
1903 printf (") ");
1906 /* Sub command */
1907 switch( com.i_sub_cmd )
1909 case 1:
1910 printf( "goto Line 0x%02x", OP_VAL_16(2) );
1911 break;
1913 case 2:
1914 printf( "stop VM" );
1915 break;
1917 case 3:
1918 printf( "Set Parental Level To %s and goto Line 0x%02x",
1919 ifo_parental[OP_VAL_8(4)&0x7],
1920 OP_VAL_8(5) );
1921 break;
1923 default:
1924 printf( "Illegal" );
1925 break;
1928 break;
1930 /* Lnk */
1931 case 1:
1932 /* Main command */
1933 if( !pi_code[1] )
1935 printf( "NOP\n" );
1937 else
1939 if( com.i_direct )
1941 if( com.i_cmp )
1943 printf( "if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f,
1944 ifo_cmp[com.i_cmp] );
1945 IfoRegister( OP_VAL_8(5), 0 );
1946 printf( ") " );
1949 /* Sub command */
1950 IfoJmp( com );
1952 else
1954 if( com.i_cmp )
1956 printf( "if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
1957 ifo_cmp[com.i_cmp] );
1958 IfoRegister( OP_VAL_16(1), com.i_dir_cmp );
1959 printf( ") " );
1962 /* Sub command */
1963 IfoLnk( com );
1966 break;
1968 /* SetSystem */
1969 case 2:
1970 if( !pi_code[1] )
1972 IfoSetSystem( com );
1974 else if( com.i_cmp && !com.i_sub_cmd )
1976 printf ("if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f, ifo_cmp[com.i_cmp]);
1977 IfoRegister( OP_VAL_8(5), 0 );
1978 printf (") ");
1979 IfoSetSystem( com );
1981 else if( !com.i_cmp && com.i_sub_cmd )
1983 printf( "if (" );
1984 IfoSetSystem( com );
1985 printf( ") " );
1986 IfoLnk( com );
1988 else
1990 printf("nop");
1992 break;
1994 /* Set */
1995 case 3:
1996 if( ! pi_code[1] )
1998 IfoSet( com );
2000 else if( com.i_cmp && !com.i_sub_cmd )
2002 printf ("if (r[0x%02x] %s ", OP_VAL_8(0)&0x0f, ifo_cmp[com.i_cmp]);
2003 IfoRegister( OP_VAL_16(2), com.i_dir_cmp );
2004 printf (") ");
2005 IfoSet( com );
2007 else if( !com.i_cmp && com.i_sub_cmd )
2009 printf ("if (");
2010 IfoSet( com );
2011 printf (") ");
2012 IfoLnk( com );
2014 else
2016 printf( "nop" );
2018 break;
2021 * math command on r[opcode[1]] and
2022 * direct?be2me_16(OP_VAL_8(0)):reg[OP_VAL_8(1)] is executed
2023 * ( unless command is swap; then r[opcode[1]] and r[OP_VAL_8(1)]
2024 * are swapped )
2025 * boolean operation cmp on r[opcode[1]] and
2026 * dir_cmp?be2me_16(OP_VAL_8(1)[1]):reg[OP_VAL_8(3)] is executed
2027 * on true result, buttons(c[6], c[7]) is called
2028 * problem is 'what is buttons()'
2030 case 4:
2031 printf( "r[0x%X] ", pi_code[1] );
2032 printf( " %s ", IfoMath( com.i_cmd ) );
2033 if( com.i_cmd == 2 )
2035 printf( "r[0x%X] ", OP_VAL_8(1) );
2037 else
2039 IfoRegister( OP_VAL_16(0), com.i_direct );
2041 printf("; ");
2043 printf( "if ( r[%d] %s ", pi_code[1], ifo_cmp[com.i_cmp] );
2044 IfoRegister( OP_VAL_8(1), com.i_dir_cmp );
2045 printf( " ) then {" );
2046 IfoAdvanced( &OP_VAL_8(4) );
2047 printf( "}" );
2048 break;
2051 * opposite to case 4: boolean, math and buttons.
2053 case 5:
2054 case 6:
2055 printf("if (");
2057 if( !com.i_direct && com.i_dir_cmp )
2059 printf( "0x%X", OP_VAL_16(1) );
2061 else
2063 IfoRegister( OP_VAL_8(3), 0 );
2064 if( OP_VAL_8(3)&0x80 )
2066 printf( "s[%s]", ifo_reg[OP_VAL_8(3)&0x1F] );
2068 else
2070 printf( "r[0x%X]", OP_VAL_8(3)&0x1F);
2071 // 0x1F is either not a mistake,
2072 // or Microsoft programmer's mistake!!!
2076 printf( " %s r[0x%X] ", ifo_cmp[com.i_cmp],
2077 com.i_direct ? OP_VAL_8(2) : OP_VAL_8(1) );
2078 printf( " ) then {" );
2079 printf( "r[0x%X] ", pi_code[1] & 0xF );
2080 printf( " %s ", IfoMath( com.i_cmd ) );
2082 if( com.i_cmd == 0x02 ) // swap
2084 printf("r[0x%X] ", OP_VAL_8(0)&0x1F);
2086 else
2088 if( com.i_direct )
2090 printf( "0x%X", OP_VAL_16(0) );
2092 else
2094 if( OP_VAL_8(0) & 0x80 )
2096 printf("s[%s]", ifo_reg[OP_VAL_8(0) & 0x1F] );
2098 else
2100 printf("r[0x%X]", OP_VAL_8(0) & 0x1F );
2105 printf("; ");
2106 IfoAdvanced( &OP_VAL_8(4) );
2107 printf("}");
2109 break;
2111 default:
2112 printf( "Unknown Command\n" );
2113 break;
2116 return;
2119 /*****************************************************************************
2120 * CommandPrint : print in clear text (I hope so !) what a command does
2121 *****************************************************************************/
2122 void CommandPrint( ifo_t ifo )
2124 return;
2127 #endif