/*==============================================================================

FICHIER     : [ifo.c]

DATE        : 2006/01/0020 19:36:04

CREATEUR    : [Linux!jef]

COMMENTAIRE :
		Released under GPL license, see gnu.org
================================================================================

==============================================================================*/
#define _LARGEFILE64_SOURCE
#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>

#include "dvdinfo.h"
#include "bswap.h"

/*@$#[ifo.c] static proto. AutoProtoSigV1.1. date: 106/01/20 20:51:55 */
#include "proto.h"
#ifdef __cplusplus
extern "C" {
#endif
static void UpdateVMG PROTO((ifo_handle_t *ifo, unsigned char *buffer));
static void UpdateFP_PGC PROTO((ifo_handle_t *ifo, unsigned char *buffer));
static void UpdatePGC PROTO((ifo_handle_t *ifo, unsigned char *_buffer, pgc_t *_pgc, int _offset));
static void UpdatePGC_COMMAND_TBL PROTO((ifo_handle_t *ifo, unsigned char *_buffer, pgc_command_tbl_t *_cmd_tbl, int _offset));
static void UpdatePGC_PROGRAM_MAP PROTO((ifo_handle_t *ifo, unsigned char *_buffer, pgc_program_map_t *_program_map, int _nr, int _offset));
static void UpdatePGC_CELL_PLAYBACK_TBL PROTO((ifo_handle_t *ifo, unsigned char *_buffer, cell_playback_t *_cell_playback, int _nr, int _offset));
static void UpdatePGC_CELL_POSITION_TBL PROTO((ifo_handle_t *ifo, unsigned char *_buffer, cell_position_t *_cell_position, int _nr, int _offset));
static void UpdateTT_SRPT PROTO((ifo_handle_t *ifo, unsigned char *_buffer));
static void UpdatePGCI_UT PROTO((ifo_handle_t *ifo, unsigned char *_buffer));
static void UpdatePGCIT PROTO((ifo_handle_t *ifo, unsigned char *_buffer));
static void UpdatePGCIT_internal PROTO((ifo_handle_t *ifo, unsigned char *_buffer, pgcit_t *_pgcit, int _offset));
static void UpdatePTL_MAIT PROTO((ifo_handle_t *ifo, unsigned char *_buffer));
static void UpdateVTS_ATRT PROTO((ifo_handle_t *ifo, unsigned char *_buffer));
static void UpdateTXTDT_MGI PROTO((ifo_handle_t *ifo, unsigned char *_buffer));
static void UpdateC_ADT PROTO((ifo_handle_t *ifo, unsigned char *_buffer));
static void UpdateC_ADT_Internal PROTO((ifo_handle_t *ifo, unsigned char *_buffer, c_adt_t *_c_adt, int _sector));
static void UpdateVOBU_ADMAP PROTO((ifo_handle_t *ifo, unsigned char *_buffer));
static void UpdateVOBU_ADMAP_Internal PROTO((ifo_handle_t *ifo, unsigned char *_buffer, vobu_admap_t *_vobu_admap, int _sector));
static void UpdateVTS PROTO((ifo_handle_t *ifo, unsigned char *_buffer));
static void UpdateVTS_PTT_SRPT PROTO((ifo_handle_t *ifo, unsigned char *_buffer));
static void UpdateVTS_TMAPT PROTO((ifo_handle_t *ifo, unsigned char *_buffer));
#ifdef __cplusplus
}
#endif
/*@$% end of AutoProtoSigV1.1 (Dont remove this line) [-I ../include]*/


/*------------------------------------------------------------------------------
	SAVEIFO-
Linux!jef 2006/01/20 19:39:54
------------------------------------------------------------------------------*/

int SaveIfo( ifo_handle_t * ifo, int vts, char * targetDir )
{
	uint32_t size;
	char ifoFile[512];
	char bupFile[512];
	char fName[512];
	dvd_file_t * dvd_file;
	unsigned char * ifoBuffer;
	FILE * fp;

	if( vts == 0 ) {
		size = ifo->vmgi_mat->vmgi_last_sector + 1;
		strcpy( ifoFile, "/VIDEO_TS/VIDEO_TS.IFO");
		strcpy( bupFile, "/VIDEO_TS/VIDEO_TS.BUP");
	}
	else {
		size = ifo->vtsi_mat->vtsi_last_sector + 1;
		sprintf( ifoFile, "/VIDEO_TS/VTS_%02d_0.IFO", vts );
		sprintf( bupFile, "/VIDEO_TS/VTS_%02d_0.BUP", vts );
	}
	size *= DVD_BLOCK_LEN;

	if( size > 0 ) {
		dvd_file = DVDOpenFile( Dvd, vts, DVD_READ_INFO_FILE );
		if( !dvd_file )	return( -1 );
		ifoBuffer =(unsigned char *)malloc( size );

		if( DVDReadBytes( dvd_file, ifoBuffer, size ) != size )	{
			free( ifoBuffer );
			DVDCloseFile( dvd_file );
			return( -1 );
		}
		DVDCloseFile( dvd_file );
		if( vts == 0 ) {
			UpdateVMG( ifo, ifoBuffer );
			UpdateFP_PGC( ifo, ifoBuffer );
			UpdateTT_SRPT( ifo, ifoBuffer );
			UpdatePGCI_UT( ifo, ifoBuffer );
			UpdatePTL_MAIT( ifo, ifoBuffer );
			UpdateVTS_ATRT( ifo, ifoBuffer );
			UpdateTXTDT_MGI( ifo, ifoBuffer );
			UpdateC_ADT( ifo, ifoBuffer );
			UpdateVOBU_ADMAP( ifo, ifoBuffer );
		}
		else
		{
			UpdateVTS( ifo, ifoBuffer );
			UpdateVTS_PTT_SRPT( ifo, ifoBuffer );
			UpdatePGCIT( ifo, ifoBuffer );
			UpdatePGCI_UT( ifo, ifoBuffer );
			UpdateVTS_TMAPT( ifo, ifoBuffer );
			UpdateC_ADT( ifo, ifoBuffer );
			UpdateVOBU_ADMAP( ifo, ifoBuffer );
		}
		sprintf( fName, "%s/%s", targetDir, ifoFile );
		fp = fopen( fName, "w" );
		if( !fp ) {
			free( ifoBuffer );
			return( -1 );
		}
		fwrite( ifoBuffer, 1, size, fp );
		fclose( fp );

		sprintf( fName, "%s/%s", targetDir, bupFile );
		fp = fopen( fName, "w" );
		if( !fp ) {
			free( ifoBuffer );
			return( -1 );
		}
		fwrite( ifoBuffer, 1, size, fp );
		fclose( fp );
		free( ifoBuffer );
	}
	return( 0 );
}

/*------------------------------------------------------------------------------
	UPDATEVMG-
Linux!jef 2006/01/20 19:57:46
------------------------------------------------------------------------------*/

static void UpdateVMG( ifo_handle_t * ifo, unsigned char * buffer )
{
    vmgi_mat_t vmgi_mat;

    memcpy(&vmgi_mat,ifo->vmgi_mat,sizeof(vmgi_mat_t));

    B2N_32(vmgi_mat.vmg_last_sector);
    B2N_32(vmgi_mat.vmgi_last_sector);
    B2N_32(vmgi_mat.vmg_category);
    B2N_16(vmgi_mat.vmg_nr_of_volumes);
    B2N_16(vmgi_mat.vmg_this_volume_nr);
    B2N_16(vmgi_mat.vmg_nr_of_title_sets);
    B2N_64(vmgi_mat.vmg_pos_code);
    B2N_32(vmgi_mat.vmgi_last_byte);
    B2N_32(vmgi_mat.first_play_pgc);
    B2N_32(vmgi_mat.vmgm_vobs);
    B2N_32(vmgi_mat.tt_srpt);
    B2N_32(vmgi_mat.vmgm_pgci_ut);
    B2N_32(vmgi_mat.ptl_mait);
    B2N_32(vmgi_mat.vts_atrt);
    B2N_32(vmgi_mat.txtdt_mgi);
    B2N_32(vmgi_mat.vmgm_c_adt);
    B2N_32(vmgi_mat.vmgm_vobu_admap);
    B2N_16(vmgi_mat.vmgm_audio_attr.lang_code);
    B2N_16(vmgi_mat.vmgm_subp_attr.lang_code);

    memcpy( buffer,&vmgi_mat,sizeof(vmgi_mat_t));
}

/*------------------------------------------------------------------------------
	UPDATEFP_PGC-
Linux!jef 2006/01/20 19:59:55
------------------------------------------------------------------------------*/

static void UpdateFP_PGC( ifo_handle_t * ifo, unsigned char * buffer )
{
	int offset = ifo->vmgi_mat->first_play_pgc;

	UpdatePGC( ifo, buffer, ifo->first_play_pgc, offset );
}

/*------------------------------------------------------------------------------
	UPDATEPGC-
Linux!jef 2006/01/20 20:03:58
------------------------------------------------------------------------------*/

static void UpdatePGC( ifo_handle_t * ifo, unsigned char *_buffer, pgc_t *_pgc, int _offset )
{
	pgc_t pgc;
	int i;

	memcpy(&pgc,_pgc,sizeof(pgc_t));
	if( pgc.command_tbl_offset != 0 ) {
		UpdatePGC_COMMAND_TBL( ifo, _buffer , pgc.command_tbl, _offset+pgc.command_tbl_offset );
	}
	if( pgc.program_map_offset != 0 ) {
		UpdatePGC_PROGRAM_MAP( ifo, _buffer, pgc.program_map,pgc.nr_of_programs, _offset + pgc.program_map_offset );
	}
	if( pgc.cell_playback_offset != 0 ) {
		UpdatePGC_CELL_PLAYBACK_TBL( ifo, _buffer ,pgc.cell_playback,pgc.nr_of_cells,_offset + pgc.cell_playback_offset);
	}

	if( pgc.cell_position_offset != 0 ) {
		UpdatePGC_CELL_POSITION_TBL( ifo, _buffer,pgc.cell_position,pgc.nr_of_cells,_offset + pgc.cell_position_offset);
	}
	B2N_16(pgc.next_pgc_nr);
	B2N_16(pgc.prev_pgc_nr);
	B2N_16(pgc.goup_pgc_nr);
	B2N_16(pgc.command_tbl_offset);
	B2N_16(pgc.program_map_offset);
	B2N_16(pgc.cell_playback_offset);
	B2N_16(pgc.cell_position_offset);

	for(i = 0; i < 8; i++)	B2N_16(pgc.audio_control[i]);
	for(i = 0; i < 32; i++)	B2N_32(pgc.subp_control[i]);
	for(i = 0; i < 16; i++)	B2N_32(pgc.palette[i]);

	memcpy(_buffer+_offset,&pgc,PGC_SIZE);
}
/*------------------------------------------------------------------------------
	UPDATEPGC_COMMAND_TBL-
Linux!jef 2006/01/20 20:07:32
------------------------------------------------------------------------------*/

static void UpdatePGC_COMMAND_TBL( ifo_handle_t * ifo, unsigned char  *_buffer, pgc_command_tbl_t *_cmd_tbl,int _offset)
{
   struct {
        uint16_t nr_of_pre;
        uint16_t nr_of_post;
        uint16_t nr_of_cell;
        uint16_t zero_1;
    }
    ATTRIBUTE_PACKED cmd_tbl;

	memcpy(&cmd_tbl,_cmd_tbl,sizeof(cmd_tbl));
	B2N_16(cmd_tbl.nr_of_pre);
	B2N_16(cmd_tbl.nr_of_post);
	B2N_16(cmd_tbl.nr_of_cell);
	memcpy(_buffer+_offset,&cmd_tbl,sizeof(cmd_tbl));

//moves the offset to save vm_cmd
	_offset +=sizeof(cmd_tbl);

	if(_cmd_tbl->nr_of_pre != 0) {
		unsigned int pre_cmds_size  = _cmd_tbl->nr_of_pre * COMMAND_DATA_SIZE;

		memcpy(_buffer + _offset,_cmd_tbl->pre_cmds,pre_cmds_size);
		_offset +=pre_cmds_size;
	}

	if(_cmd_tbl->nr_of_post != 0) {
		unsigned int post_cmds_size = _cmd_tbl->nr_of_post * COMMAND_DATA_SIZE;

		memcpy(_buffer + _offset,_cmd_tbl->post_cmds,post_cmds_size);
		_offset += post_cmds_size;
	}

	if(_cmd_tbl->nr_of_cell != 0) {
		unsigned int cell_cmds_size = _cmd_tbl->nr_of_cell * COMMAND_DATA_SIZE;

		memcpy(_buffer +_offset,_cmd_tbl->cell_cmds,cell_cmds_size);
	}
}

/*------------------------------------------------------------------------------
	UPDATEPGC_PROGRAM_MAP-
Linux!jef 2006/01/20 20:09:17
------------------------------------------------------------------------------*/

static void UpdatePGC_PROGRAM_MAP( ifo_handle_t * ifo, unsigned char *_buffer,pgc_program_map_t *_program_map, int _nr,int _offset)
{
    int size = _nr * sizeof(pgc_program_map_t);

    memcpy(_buffer+_offset, _program_map,size);
}
/*------------------------------------------------------------------------------
	UPDATEPGC_CELL_PLAYBACK_TBL-
Linux!jef 2006/01/20 20:09:58
------------------------------------------------------------------------------*/

static void UpdatePGC_CELL_PLAYBACK_TBL( ifo_handle_t * ifo, unsigned char *_buffer, cell_playback_t *_cell_playback,int _nr, int _offset)
{
	cell_playback_t *cell_playback;
	int size = _nr * sizeof(cell_playback_t);
	int i;

	cell_playback=(cell_playback_t*) malloc(size);
	memcpy(cell_playback,_cell_playback,size);

	for( i = 0; i < _nr; i++) {
		B2N_32(cell_playback[i].first_sector);
		B2N_32(cell_playback[i].first_ilvu_end_sector);
		B2N_32(cell_playback[i].last_vobu_start_sector);
		B2N_32(cell_playback[i].last_sector);
	}

	memcpy(_buffer + _offset,cell_playback,size);
	free(cell_playback);
}

/*------------------------------------------------------------------------------
	UPDATEPGC_CELL_POSITION_TBL-
Linux!jef 2006/01/20 20:11:21
------------------------------------------------------------------------------*/
static void UpdatePGC_CELL_POSITION_TBL( ifo_handle_t * ifo, unsigned char *_buffer,cell_position_t *_cell_position,int _nr, int _offset)
{
	cell_position_t * cell_position;
	int size = _nr * sizeof(cell_position_t);
	int i;

	cell_position=(cell_position_t*)malloc(size);
	memcpy(cell_position,_cell_position,size);
	for( i = 0; i < _nr; i++ ) {
		B2N_16(cell_position[i].vob_id_nr);
	}
	memcpy(_buffer + _offset,cell_position,size);
	free(cell_position);
}

/*------------------------------------------------------------------------------
	UPDATETT_SRPT-
Linux!jef 2006/01/20 20:12:43
------------------------------------------------------------------------------*/
static void UpdateTT_SRPT( ifo_handle_t * ifo, unsigned char *_buffer )
{
	if( ifo->vmgi_mat->tt_srpt != 0 ) {
		tt_srpt_t * tt_srpt;
		int offset = ifo->vmgi_mat->tt_srpt * DVD_BLOCK_LEN;
		int  info_length;
		title_info_t * title_info;
		int i;

		tt_srpt=(tt_srpt_t*) malloc(sizeof(tt_srpt_t));
		memcpy( tt_srpt, ifo->tt_srpt,sizeof(tt_srpt_t));


		info_length = tt_srpt->last_byte + 1 - TT_SRPT_SIZE;
		title_info =(title_info_t*) malloc(info_length);
		memcpy(title_info, tt_srpt->title,info_length);

		for( i =  0; i < tt_srpt->nr_of_srpts; i++) {
			B2N_16(title_info[i].nr_of_ptts);
			B2N_16(title_info[i].parental_id);
			B2N_32(title_info[i].title_set_sector);
		}
		memcpy(_buffer+offset+TT_SRPT_SIZE,title_info,info_length);

		free(title_info);

		B2N_16(tt_srpt->nr_of_srpts);
		B2N_32(tt_srpt->last_byte);
		memcpy(_buffer+offset,tt_srpt,TT_SRPT_SIZE);
		free (tt_srpt);
	}
}
/*------------------------------------------------------------------------------
	UPDATEPGCI_UT-
Linux!jef 2006/01/20 20:15:23
------------------------------------------------------------------------------*/

static void UpdatePGCI_UT( ifo_handle_t * ifo, unsigned char *_buffer)
{
	int sector,sector2;
	pgci_ut_t * pgci_ut;
	pgci_lu_t *pgci_lu;
	int i;

	if( ifo->vmgi_mat ) {
		if( ifo->vmgi_mat->vmgm_pgci_ut == 0)
			return;
		sector = ifo->vmgi_mat->vmgm_pgci_ut *DVD_BLOCK_LEN;
	}
	else {
		if( ifo->vtsi_mat) {
			if( ifo->vtsi_mat->vtsm_pgci_ut == 0)
				return;
// A v�ifier : si sector = secteur physique ou offset
			sector = ifo->vtsi_mat->vtsm_pgci_ut * DVD_BLOCK_LEN;
		}
		else {
        		return;
		}
	}
	sector2=sector;
	pgci_ut = (pgci_ut_t*)malloc( sizeof(pgci_ut_t));
	memcpy( pgci_ut,ifo->pgci_ut,sizeof(pgci_ut_t));
	B2N_16(pgci_ut->nr_of_lus);
	B2N_32(pgci_ut->last_byte);

	memcpy(_buffer+sector,pgci_ut,PGCI_UT_SIZE);

	sector += PGCI_UT_SIZE;
	free(pgci_ut);

	pgci_lu = (pgci_lu_t*)malloc(sizeof(pgci_lu_t));

	for( i = 0; i < ifo->pgci_ut->nr_of_lus; i++) {
		memcpy(pgci_lu, &(ifo->pgci_ut->lu[i]), PGCI_LU_SIZE);
		B2N_16(pgci_lu->lang_code);
		B2N_32(pgci_lu->lang_start_byte);
		memcpy(_buffer+sector,pgci_lu,PGCI_LU_SIZE);
		UpdatePGCIT_internal( ifo, _buffer, ifo->pgci_ut->lu[i].pgcit,sector2 + ifo->pgci_ut->lu[i].lang_start_byte);
		sector += PGCI_LU_SIZE;
	}
	free(pgci_lu);
}
/*------------------------------------------------------------------------------
	UPDATEPGCIT-
Linux!jef 2006/01/20 20:19:47
------------------------------------------------------------------------------*/

static void UpdatePGCIT( ifo_handle_t * ifo, unsigned char *_buffer )
{
	if( !ifo->vtsi_mat )	return ;

	if( ifo->vtsi_mat->vts_pgcit == 0 ) /* mandatory */
		return ;

	UpdatePGCIT_internal( ifo, _buffer, ifo->vts_pgcit, ifo->vtsi_mat->vts_pgcit * DVD_BLOCK_LEN);
}
/*------------------------------------------------------------------------------
	UPDATEPGCIT_INTERNAL-
Linux!jef 2006/01/20 20:20:57
------------------------------------------------------------------------------*/

static void UpdatePGCIT_internal( ifo_handle_t * ifo, unsigned char *_buffer, pgcit_t *_pgcit, int _offset)
{
	pgcit_t * pgcit;
	int info_length;
	int offset;
	int i;
	pgci_srp_t * pgci_srp;

	pgcit=(pgcit_t*)malloc(sizeof(pgcit_t));
	memcpy(pgcit,_pgcit,sizeof(pgcit_t));
	B2N_16(pgcit->nr_of_pgci_srp);
	B2N_32(pgcit->last_byte);
	memcpy(_buffer+_offset ,pgcit,PGCIT_SIZE);
	free(pgcit);

	info_length = pgcit->nr_of_pgci_srp * PGCI_SRP_SIZE;
	pgci_srp=(pgci_srp_t*)malloc(sizeof(pgci_srp_t));

	offset=_offset+PGCIT_SIZE;

	for( i = 0; i < _pgcit->nr_of_pgci_srp; i++) {
		memcpy(pgci_srp, &(_pgcit->pgci_srp[i]), PGCI_SRP_SIZE);
		B2N_16(pgci_srp->ptl_id_mask);
		B2N_32(pgci_srp->pgc_start_byte);
//a desactiver pour checkBuffer
//memcpy(_buffer+offset,pgci_srp,PGCI_SRP_SIZE);

		offset+=PGCI_SRP_SIZE;

		UpdatePGC( ifo, _buffer,_pgcit->pgci_srp[i].pgc,_offset + _pgcit->pgci_srp[i].pgc_start_byte);
	}
	free(pgci_srp);
}

/*------------------------------------------------------------------------------
	UPDATEPTL_MAIT-
Linux!jef 2006/01/20 20:23:14
------------------------------------------------------------------------------*/

static void UpdatePTL_MAIT( ifo_handle_t * ifo, unsigned char *_buffer )
{
	ptl_mait_t * ptl_mait;
	int offset;
	int info_length;
	int i;
	ptl_mait_country_t * ptl_mait_country;

	if( !ifo->vmgi_mat ) return;

	if( ifo->vmgi_mat->ptl_mait == 0)	return;

	ptl_mait=(ptl_mait_t*)malloc(sizeof(ptl_mait_t));
	memcpy(ptl_mait,ifo->ptl_mait,sizeof(ptl_mait_t));

	B2N_16(ptl_mait->nr_of_countries);
	B2N_16(ptl_mait->nr_of_vtss);
	B2N_32(ptl_mait->last_byte);

	offset = ifo->vmgi_mat->ptl_mait * DVD_BLOCK_LEN;
	memcpy(_buffer+offset,ptl_mait,PTL_MAIT_SIZE);
	free(ptl_mait);

	offset+=PTL_MAIT_SIZE;

	info_length = ifo->ptl_mait->nr_of_countries * sizeof(ptl_mait_country_t);
	ptl_mait_country = (ptl_mait_country_t*) malloc (sizeof(ptl_mait_country_t));

	for( i = 0; i < ptl_mait->nr_of_countries; i++) {
		memcpy(ptl_mait_country,&(ifo->ptl_mait->countries[i]),PTL_MAIT_COUNTRY_SIZE);
		B2N_16(ptl_mait_country->country_code);
		B2N_16(ptl_mait_country->pf_ptl_mai_start_byte);
		memcpy(_buffer +offset,ptl_mait_country,PTL_MAIT_COUNTRY_SIZE);
		offset+=PTL_MAIT_COUNTRY_SIZE;
	}
	free(ptl_mait_country);
}
/*------------------------------------------------------------------------------
	UPDATEVTS_ATRT-
Linux!jef 2006/01/20 20:25:55
------------------------------------------------------------------------------*/

static void UpdateVTS_ATRT( ifo_handle_t * ifo, unsigned char *_buffer )
{
	int sector;
	vts_atrt_t *vts_atrt;
	int info_length;
	uint32_t *data;
	int i;

	if( ifo->vmgi_mat->vts_atrt == 0)	return;

	sector = ifo->vmgi_mat->vts_atrt * DVD_BLOCK_LEN;
	vts_atrt = (vts_atrt_t*)malloc(sizeof(vts_atrt_t));
	memcpy(vts_atrt, ifo->vts_atrt,VTS_ATRT_SIZE);
	B2N_16(vts_atrt->nr_of_vtss);
	B2N_32(vts_atrt->last_byte);
	memcpy(_buffer+sector,vts_atrt,VTS_ATRT_SIZE);
	free(vts_atrt);

	sector += VTS_ATRT_SIZE;
	vts_atrt = ifo->vts_atrt;
	info_length = vts_atrt->nr_of_vtss * sizeof(uint32_t);
	data=(uint32_t*) malloc(info_length);
	memcpy (data,ifo->vts_atrt->vts_atrt_offsets,info_length);

	for( i = 0; i < ifo->vts_atrt->nr_of_vtss; i++) {
		B2N_32(data[i]);
	}
	memcpy(_buffer+sector,data,info_length);
	free(data);

	data = (uint32_t*)ifo->vts_atrt->vts_atrt_offsets;
	info_length = vts_atrt->nr_of_vtss * sizeof(vts_attributes_t);
//	for( i = 0; i < ifo->vts_atrt->nr_of_vtss; i++) {
//		unsigned int offset = data[i];
// A VOIR
// updateVTS_ATTRIBUTES(_buffer+sector+offset,&(ifo->vts_atrt->vts[i]));
//	}
}
/*------------------------------------------------------------------------------
	UPDATETXTDT_MGI-
Linux!jef 2006/01/20 20:28:28
------------------------------------------------------------------------------*/

static void UpdateTXTDT_MGI( ifo_handle_t * ifo, unsigned char * _buffer )
{
	int offset;

	if( ifo->vmgi_mat->txtdt_mgi == 0)	return;
	offset= ifo->vmgi_mat->txtdt_mgi * DVD_BLOCK_LEN;
	memcpy(_buffer+offset, ifo->txtdt_mgi,TXTDT_MGI_SIZE);
}
/*------------------------------------------------------------------------------
	UPDATEC_ADT-
Linux!jef 2006/01/20 20:30:10
------------------------------------------------------------------------------*/

static void UpdateC_ADT( ifo_handle_t * ifo, unsigned char * _buffer )
{
	int sector;

	if( ifo->vmgi_mat ) {
		if( ifo->vmgi_mat->vmgm_c_adt != 0) {
			sector = ifo->vmgi_mat->vmgm_c_adt * DVD_BLOCK_LEN;
			UpdateC_ADT_Internal( ifo, _buffer, ifo->menu_c_adt,sector);
		}
	}
	else {
		if( ifo->vtsi_mat ) {
			if( ifo->vtsi_mat->vtsm_c_adt != 0) {
				sector = ifo->vtsi_mat->vtsm_c_adt * DVD_BLOCK_LEN;
				UpdateC_ADT_Internal( ifo, _buffer, ifo->menu_c_adt,sector);
			}
			if( ifo->vtsi_mat->vts_c_adt !=0) {
				sector = ifo->vtsi_mat->vts_c_adt * DVD_BLOCK_LEN;
				UpdateC_ADT_Internal( ifo, _buffer, ifo->vts_c_adt,sector);
			}
		}
		else {
			return ;
		}
	}
}
/*------------------------------------------------------------------------------
	UPDATEC_ADT_INTERNAL-
Linux!jef 2006/01/20 20:33:05
------------------------------------------------------------------------------*/

static void UpdateC_ADT_Internal( ifo_handle_t * ifo, unsigned char *_buffer,c_adt_t *_c_adt,int _sector )
{
	c_adt_t * c_adt;
	int offset;
	int info_length;
	cell_adr_t *cell_adr,*ptr;
	int i;

	c_adt =(c_adt_t*) malloc (sizeof(c_adt_t));
	memcpy(c_adt,_c_adt,sizeof(c_adt_t));
	B2N_16(c_adt->nr_of_vobs);
	B2N_32(c_adt->last_byte);
	memcpy(_buffer+_sector,c_adt,C_ADT_SIZE);
	free(c_adt);

	offset =_sector + C_ADT_SIZE;

	info_length = _c_adt->last_byte + 1 - C_ADT_SIZE;

	cell_adr=(cell_adr_t*) malloc(sizeof(cell_adr_t));

	ptr= _c_adt->cell_adr_table;
	for( i = 0; i < info_length/sizeof(cell_adr_t); i++) {
		memcpy(cell_adr,&(ptr[i]),sizeof(cell_adr_t));
		B2N_16(cell_adr->vob_id);
		B2N_32(cell_adr->start_sector);
		B2N_32(cell_adr->last_sector);
		memcpy(_buffer+offset,cell_adr,sizeof(cell_adr_t));
		offset+=sizeof(cell_adr_t);
	}
	free(cell_adr);
}
/*------------------------------------------------------------------------------
	UPDATEVOBU_ADMAP-
Linux!jef 2006/01/20 20:35:22
------------------------------------------------------------------------------*/

static void UpdateVOBU_ADMAP( ifo_handle_t * ifo, unsigned char * _buffer )
{
	int sector;

	if( ifo->vmgi_mat ) {
		if( ifo->vmgi_mat->vmgm_vobu_admap == 0)	return ;
		sector = ifo->vmgi_mat->vmgm_vobu_admap * DVD_BLOCK_LEN;
		UpdateVOBU_ADMAP_Internal( ifo, _buffer, ifo->menu_vobu_admap,sector);
	}
	else {
		if( ifo->vtsi_mat ) {
			if( ifo->vtsi_mat->vtsm_vobu_admap != 0) {
				sector = ifo->vtsi_mat->vtsm_vobu_admap * DVD_BLOCK_LEN;
				UpdateVOBU_ADMAP_Internal( ifo, _buffer, ifo->menu_vobu_admap,sector);
			}
			if ( ifo->vtsi_mat->vts_vobu_admap !=0) {
				sector = ifo->vtsi_mat->vts_vobu_admap * DVD_BLOCK_LEN;
				UpdateVOBU_ADMAP_Internal( ifo, _buffer, ifo->vts_vobu_admap,sector);
			}
		}
		else {
			return ;
		}
	}
}
/*------------------------------------------------------------------------------
	UPDATEVOBU_ADMAP_INTERNAL-
Linux!jef 2006/01/20 20:38:21
------------------------------------------------------------------------------*/

static void UpdateVOBU_ADMAP_Internal( ifo_handle_t * ifo, unsigned char *_buffer,vobu_admap_t *_vobu_admap,int _sector )
{
	vobu_admap_t *vobu_admap;
	int offset;
	int info_length;
	uint32_t *vobu_start_sectors;
	int i;

	vobu_admap=(vobu_admap_t*)malloc(sizeof(vobu_admap_t));
	memcpy(vobu_admap,_vobu_admap,sizeof(vobu_admap_t));
	B2N_32(vobu_admap->last_byte);
	memcpy(_buffer+_sector,vobu_admap,VOBU_ADMAP_SIZE);
	free(vobu_admap);

	offset = _sector + VOBU_ADMAP_SIZE;

	info_length = _vobu_admap->last_byte + 1 - VOBU_ADMAP_SIZE;
	vobu_start_sectors=(uint32_t*)malloc(info_length);
	memcpy(vobu_start_sectors,_vobu_admap->vobu_start_sectors,info_length);

	for( i = 0; i < info_length/sizeof(uint32_t); i++)	B2N_32(vobu_start_sectors[i]);

	memcpy(_buffer+offset,vobu_start_sectors,info_length);

	free(vobu_start_sectors);
}
/*------------------------------------------------------------------------------
	UPDATEVTS-
Linux!jef 2006/01/20 20:40:07
------------------------------------------------------------------------------*/

static void UpdateVTS( ifo_handle_t * ifo, unsigned char *_buffer )
{
	vtsi_mat_t *vtsi_mat;
	int i;

	vtsi_mat = (vtsi_mat_t *)malloc(sizeof(vtsi_mat_t));
	memcpy(vtsi_mat, ifo->vtsi_mat,sizeof(vtsi_mat_t));

	B2N_32(vtsi_mat->vts_last_sector);
	B2N_32(vtsi_mat->vtsi_last_sector);
	B2N_32(vtsi_mat->vts_category);
	B2N_32(vtsi_mat->vtsi_last_byte);
	B2N_32(vtsi_mat->vtsm_vobs);
	B2N_32(vtsi_mat->vtstt_vobs);
	B2N_32(vtsi_mat->vts_ptt_srpt);
	B2N_32(vtsi_mat->vts_pgcit);
	B2N_32(vtsi_mat->vtsm_pgci_ut);
	B2N_32(vtsi_mat->vts_tmapt);
	B2N_32(vtsi_mat->vtsm_c_adt);
	B2N_32(vtsi_mat->vtsm_vobu_admap);
	B2N_32(vtsi_mat->vts_c_adt);
	B2N_32(vtsi_mat->vts_vobu_admap);
	B2N_16(vtsi_mat->vtsm_audio_attr.lang_code);
	B2N_16(vtsi_mat->vtsm_subp_attr.lang_code);
	for( i = 0; i < 8; i++)		B2N_16(vtsi_mat->vts_audio_attr[i].lang_code);
	for( i = 0; i < 32; i++)	B2N_16(vtsi_mat->vts_subp_attr[i].lang_code);

	memcpy(_buffer,vtsi_mat,sizeof(vtsi_mat_t));
	free(vtsi_mat);
}
/*------------------------------------------------------------------------------
	UPDATEVTS_PTT_SRPT-
Linux!jef 2006/01/20 20:41:50
------------------------------------------------------------------------------*/

static void UpdateVTS_PTT_SRPT( ifo_handle_t * ifo, unsigned char *_buffer )
{
	vts_ptt_srpt_t * vts_ptt_srpt;
	int offset;

	if(!ifo->vtsi_mat)	return ;

	if(ifo->vtsi_mat->vts_ptt_srpt == 0)	return ;

	vts_ptt_srpt = (vts_ptt_srpt_t *)malloc(sizeof(vts_ptt_srpt_t));
	memcpy(vts_ptt_srpt,ifo->vts_ptt_srpt,sizeof(vts_ptt_srpt_t));
	offset = ifo->vtsi_mat->vts_ptt_srpt * DVD_BLOCK_LEN;

	B2N_16(vts_ptt_srpt->nr_of_srpts);
	B2N_32(vts_ptt_srpt->last_byte);

	memcpy(_buffer+offset,vts_ptt_srpt,VTS_PTT_SRPT_SIZE);
	free(vts_ptt_srpt);
}

/*!
    \fn kIFO::checkBuffer()
 */

/*------------------------------------------------------------------------------
	UPDATEVTS_TMAPT-
Linux!jef 2006/01/20 20:43:28
------------------------------------------------------------------------------*/

static void UpdateVTS_TMAPT( ifo_handle_t * ifo, unsigned char *_buffer )
{
	vts_tmapt_t *vts_tmapt1,*vts_tmapt;
	uint32_t offset, offset0, offset1;
	int info_length;
	uint32_t *vts_tmap_srp;
	int i, j;
	int info_length1;
	int info_length2;
	map_ent_t *map_ent;

	if(!ifo->vtsi_mat)	return ;

	if(ifo->vtsi_mat->vts_tmapt == 0) { /* optional(?) */
		return ;
	}

	vts_tmapt1 = (vts_tmapt_t *)malloc(sizeof(vts_tmapt_t));
	memcpy(vts_tmapt1,ifo->vts_tmapt,sizeof(vts_tmapt_t));
	offset = ifo->vtsi_mat->vts_tmapt * DVD_BLOCK_LEN;
	B2N_16(vts_tmapt1->nr_of_tmaps);
	B2N_32(vts_tmapt1->last_byte);
	offset0=offset;
	offset+=VTS_TMAPT_SIZE;

	vts_tmapt=ifo->vts_tmapt;
	info_length = vts_tmapt->nr_of_tmaps * 4;
	vts_tmap_srp = (uint32_t *)malloc(info_length);
	memcpy(vts_tmap_srp,vts_tmapt->tmap_offset,info_length);
	for( i = 0; i < vts_tmapt->nr_of_tmaps; i++)	B2N_32(vts_tmap_srp[i]);
	offset1=offset;
	info_length1=info_length;
	offset += info_length;

	info_length = vts_tmapt->nr_of_tmaps * sizeof(vts_tmap_t);
	vts_tmap_t * tmap = (vts_tmap_t *)malloc(info_length);
	memcpy(tmap,vts_tmapt->tmap,info_length);
	for( i = 0; i < vts_tmapt->nr_of_tmaps; i++) {
		B2N_16(tmap[i].nr_of_entries);
		memcpy(_buffer+offset,&(tmap[i]),VTS_TMAP_SIZE);
		vts_tmapt1->last_byte=+offset+VTS_TMAP_SIZE-1;
		offset+=VTS_TMAP_SIZE;
		vts_tmap_srp[i]=offset-offset1+4;
		B2N_32(vts_tmap_srp[i]);
		if(vts_tmapt->tmap[i].nr_of_entries == 0) { // Early out if zero entries
			continue;
		}
		info_length2 = vts_tmapt->tmap[i].nr_of_entries * sizeof(map_ent_t);
		map_ent = (map_ent_t *)malloc(info_length2);
		memcpy(map_ent,vts_tmapt->tmap[i].map_ent,info_length2);
		for( j = 0; j < vts_tmapt->tmap[i].nr_of_entries; j++) {
			B2N_32(map_ent[j]);
			memcpy(_buffer+offset,&(map_ent[j]),sizeof(map_ent_t));
			vts_tmapt1->last_byte=offset+sizeof(map_ent_t)-1;
			offset+=sizeof(map_ent_t);
		}
		free(map_ent);
	}
	memcpy(_buffer+offset1,vts_tmap_srp,info_length1);
	free(vts_tmap_srp);

	free(tmap);
	vts_tmapt1->last_byte-=offset0;
	B2N_32(vts_tmapt1->last_byte);
	memcpy(_buffer+offset0,vts_tmapt1,VTS_TMAPT_SIZE);
	free(vts_tmapt1);
}
