/* @(#)ifo_read.c	1.3 02/12/12 joerg */
#ifndef lint
static	char sccsid[] =
	"@(#)ifo_read.c	1.3 02/12/12 joerg";
#endif
/*
 * Copyright (C) 2002 Olaf Beck <olaf_sc@yahoo.com>
 *		     Jörg Schilling <schilling@fokus.gmd.de>
 *		     (making the code portable)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/*
 * NOTE: This is a cut down version of libdvdread for mkisofs, due
 * to portability issues with the current libdvdread according to
 * the maintainer of mkisofs.
 * This cut down version only reads from a harddisk file structure
 * and it only implements the functions necessary inorder to make
 * mkisofs produce valid DVD-Video images.
 * DON'T USE THIS LIBRARY IN ANY OTHER PROGRAM GET THE REAL
 * LIBDVDREAD INSTEAD
 */
#ifdef DVD_VIDEO

#include <mconfig.h>
#include "mkisofs.h"
#include <fctldefs.h>
#include <utypes.h>
#include <schily.h>

#include "ifo_read.h"
#include "bswap.h"

LOCAL	ifo_handle_t *	ifoReadVTSI	__PR((int file, ifo_handle_t * ifofile));
LOCAL	ifo_handle_t *	ifoReadVGMI	__PR((int file, ifo_handle_t * ifofile));
EXPORT	ifo_handle_t *	ifoOpen		__PR((dvd_reader_t *dvd, int title));
LOCAL	void		ifoFree_TT_SRPT	__PR((ifo_handle_t *ifofile));
EXPORT	void		ifoClose	__PR((ifo_handle_t * ifofile));


LOCAL ifo_handle_t *
ifoReadVTSI(int file, ifo_handle_t *ifofile)
{
	off_t offset;
	UInt32_t sector;

	vtsi_mat_t * vtsi_mat;

	/* Make the VMG part NULL */
	ifofile->vmgi_mat = NULL;
	ifofile->tt_srpt = NULL;

	vtsi_mat = (vtsi_mat_t *)e_malloc(sizeof(vtsi_mat_t));
	if(!vtsi_mat) {
/*		fprintf(stderr, "Memmory allocation error\n");*/
		free(ifofile);
		return(0);
	}

	ifofile->vtsi_mat = vtsi_mat;

	/* Last sector of VTS i.e. last sector of BUP */

	offset = 12;

	if (lseek(file, offset, SEEK_SET) != offset) {
#ifdef	USE_LIBSCHILY
		errmsg("Faild to seek VIDEO_TS.IFO\n");
#else
		fprintf(stderr, "Faild to seek VIDEO_TS.IFO\n");
#endif
		ifoClose(ifofile);
		return(0);
	}

	if (read(file, &sector, sizeof(sector)) != sizeof(sector)) {
#ifdef	USE_LIBSCHILY
		errmsg("Faild to read VIDEO_TS.IFO\n");
#else
		fprintf(stderr, "Faild to read VIDEO_TS.IFO\n");
#endif
		ifoClose(ifofile);
		return(0);
	}

	B2N_32(sector);

	vtsi_mat->vts_last_sector = sector;

	/* Last sector of IFO */

	offset = 28;

	if (lseek(file, offset, SEEK_SET) != offset) {
#ifdef	USE_LIBSCHILY
		errmsg("Faild to seek VIDEO_TS.IFO\n");
#else
		fprintf(stderr, "Faild to seek VIDEO_TS.IFO\n");
#endif
		ifoClose(ifofile);
		return(0);
	}

	if (read(file, &sector, sizeof(sector)) != sizeof(sector)) {
#ifdef	USE_LIBSCHILY
		errmsg("Faild to read VIDEO_TS.IFO\n");
#else
		fprintf(stderr, "Faild to read VIDEO_TS.IFO\n");
#endif
		ifoClose(ifofile);
		return(0);
	}

	B2N_32(sector);

	vtsi_mat->vtsi_last_sector = sector;


	/* Star sector of VTS Menu VOB */

	offset = 192;

	if (lseek(file, offset, SEEK_SET) != offset) {
#ifdef	USE_LIBSCHILY
		errmsg("Faild to seek VIDEO_TS.IFO\n");
#else
		fprintf(stderr, "Faild to seek VIDEO_TS.IFO\n");
#endif
		ifoClose(ifofile);
		return(0);
	}


	if (read(file, &sector, sizeof(sector)) != sizeof(sector)) {
#ifdef	USE_LIBSCHILY
		errmsg("Faild to read VIDEO_TS.IFO\n");
#else
		fprintf(stderr, "Faild to read VIDEO_TS.IFO\n");
#endif
		ifoClose(ifofile);
		return(0);
	}

	B2N_32(sector);

	vtsi_mat->vtsm_vobs = sector;


	/* Start sector of VTS Title VOB */

	offset = 196;

	if (lseek(file, offset, SEEK_SET) != offset) {
#ifdef	USE_LIBSCHILY
		errmsg("Faild to seek VIDEO_TS.IFO\n");
#else
		fprintf(stderr, "Faild to seek VIDEO_TS.IFO\n");
#endif
		ifoClose(ifofile);
		return(0);
	}


	if (read(file, &sector, sizeof(sector)) != sizeof(sector)) {
#ifdef	USE_LIBSCHILY
		errmsg("Faild to read VIDEO_TS.IFO\n");
#else
		fprintf(stderr, "Faild to read VIDEO_TS.IFO\n");
#endif
		ifoClose(ifofile);
		return(0);
	}

	B2N_32(sector);

	vtsi_mat->vtstt_vobs = sector;

	return(ifofile);
}


LOCAL ifo_handle_t *
ifoReadVGMI(int file, ifo_handle_t *ifofile)
{
	off_t	offset;
	int	counter;
	UInt32_t sector;
	UInt16_t titles;

	vmgi_mat_t *vmgi_mat;
	tt_srpt_t *tt_srpt;

	/* Make the VTS part null */
	ifofile->vtsi_mat = NULL;

	vmgi_mat = (vmgi_mat_t *)e_malloc(sizeof(vmgi_mat_t));
	if(!vmgi_mat) {
/*		fprintf(stderr, "Memmory allocation error\n");*/
		free(ifofile);
		return(0);
	}

	ifofile->vmgi_mat = vmgi_mat;

	/* Last sector of VMG i.e. last sector of BUP */

	offset = 12;

	if (lseek(file, offset, SEEK_SET) != offset) {
#ifdef	USE_LIBSCHILY
		errmsg("Faild to seek VIDEO_TS.IFO\n");
#else
		fprintf(stderr, "Faild to seek VIDEO_TS.IFO\n");
#endif
		ifoClose(ifofile);
		return(0);
	}

	if (read(file, &sector, sizeof(sector)) != sizeof(sector)) {
#ifdef	USE_LIBSCHILY
		errmsg("Faild to read VIDEO_TS.IFO\n");
#else
		fprintf(stderr, "Faild to read VIDEO_TS.IFO\n");
#endif
		ifoClose(ifofile);
		return(0);
	}

	B2N_32(sector);

	vmgi_mat->vmg_last_sector = sector;

	/* Last sector of IFO */

	offset = 28;

	if (lseek(file, offset, SEEK_SET) != offset) {
#ifdef	USE_LIBSCHILY
		errmsg("Faild to seek VIDEO_TS.IFO\n");
#else
		fprintf(stderr, "Faild to seek VIDEO_TS.IFO\n");
#endif
		ifoClose(ifofile);
		return(0);
	}


	if (read(file, &sector, sizeof(sector)) != sizeof(sector)) {
#ifdef	USE_LIBSCHILY
		errmsg("Faild to read VIDEO_TS.IFO\n");
#else
		fprintf(stderr, "Faild to read VIDEO_TS.IFO\n");
#endif
		ifoClose(ifofile);
		return(0);
	}

	B2N_32(sector);

	vmgi_mat->vmgi_last_sector = sector;


	/* Number of VTS i.e. title sets */

	offset = 62;

	if (lseek(file, offset, SEEK_SET) != offset) {
#ifdef	USE_LIBSCHILY
		errmsg("Faild to seek VIDEO_TS.IFO\n");
#else
		fprintf(stderr, "Faild to seek VIDEO_TS.IFO\n");
#endif
		ifoClose(ifofile);
		return(0);
	}


	if (read(file, &titles, sizeof(titles)) != sizeof(titles)) {
#ifdef	USE_LIBSCHILY
		errmsg("Faild to read VIDEO_TS.IFO\n");
#else
		fprintf(stderr, "Faild to read VIDEO_TS.IFO\n");
#endif
		ifoClose(ifofile);
		return(0);
	}

	B2N_16(titles);

	vmgi_mat->vmg_nr_of_title_sets = titles;


	/* Star sector of VMG Menu VOB */

	offset = 192;

	if (lseek(file, offset, SEEK_SET) != offset) {
#ifdef	USE_LIBSCHILY
		errmsg("Faild to seek VIDEO_TS.IFO\n");
#else
		fprintf(stderr, "Faild to seek VIDEO_TS.IFO\n");
#endif
		ifoClose(ifofile);
		return(0);
	}


	if (read(file, &sector, sizeof(sector)) != sizeof(sector)) {
#ifdef	USE_LIBSCHILY
		errmsg("Faild to read VIDEO_TS.IFO\n");
#else
		fprintf(stderr, "Faild to read VIDEO_TS.IFO\n");
#endif
		ifoClose(ifofile);
		return(0);
	}

	B2N_32(sector);

	vmgi_mat->vmgm_vobs = sector;


	/* Sector offset to TT_SRPT */

	offset = 196;

	if (lseek(file, offset, SEEK_SET) != offset) {
#ifdef	USE_LIBSCHILY
		errmsg("Faild to seek VIDEO_TS.IFO\n");
#else
		fprintf(stderr, "Faild to seek VIDEO_TS.IFO\n");
#endif
		ifoClose(ifofile);
		return(0);
	}


	if (read(file, &sector, sizeof(sector)) != sizeof(sector)) {
#ifdef	USE_LIBSCHILY
		errmsg("Faild to read VIDEO_TS.IFO\n");
#else
		fprintf(stderr, "Faild to read VIDEO_TS.IFO\n");
#endif
		ifoClose(ifofile);
		return(0);
	}

	B2N_32(sector);

	vmgi_mat->tt_srpt = sector;

	tt_srpt = (tt_srpt_t *)e_malloc(sizeof(tt_srpt_t));
	if(!tt_srpt) {
/*		fprintf(stderr, "Memmory allocation error\n");*/
		ifoClose(ifofile);
		return(0);
	}

	ifofile->tt_srpt = tt_srpt;


	/* Number of titles in TT_SRPT */

	offset = 2048 * vmgi_mat->tt_srpt;

	if (lseek(file, offset, SEEK_SET) != offset) {
#ifdef	USE_LIBSCHILY
		errmsg("Faild to seek VIDEO_TS.IFO\n");
#else
		fprintf(stderr, "Faild to seek VIDEO_TS.IFO\n");
#endif
		return(0);
	}

	if (read(file, &titles, sizeof(titles)) != sizeof(titles)) {
#ifdef	USE_LIBSCHILY
		errmsg("Faild to read VIDEO_TS.IFO\n");
#else
		fprintf(stderr, "Faild to read VIDEO_TS.IFO\n");
#endif
		return(0);
	}

	B2N_16(titles);

	tt_srpt->nr_of_srpts = titles;

	tt_srpt->title = (title_info_t *)e_malloc(sizeof(title_info_t) * tt_srpt->nr_of_srpts);
	if(!tt_srpt->title) {
/*		fprintf(stderr, "Memmory allocation error\n");*/
		ifoClose(ifofile);
		return (0);
	}

	/* Start sector of each title in TT_SRPT */

	for (counter = 0; counter < tt_srpt->nr_of_srpts; counter++) {
		offset = (2048 * vmgi_mat->tt_srpt) + 8 + (counter * 12) + 8;
		if (lseek(file, offset, SEEK_SET) != offset) {
#ifdef	USE_LIBSCHILY
			errmsg("Faild to seek VIDEO_TS.IFO\n");
#else
			fprintf(stderr, "Faild to seek VIDEO_TS.IFO\n");
#endif
			ifoClose(ifofile);
			return(0);
		}

		if (read(file, &sector, sizeof(sector)) != sizeof(sector)) {
#ifdef	USE_LIBSCHILY
			errmsg("Faild to read VIDEO_TS.IFO\n");
#else
			fprintf(stderr, "Faild to read VIDEO_TS.IFO\n");
#endif
			ifoClose(ifofile);
			return(0);
		}

		B2N_32(sector);

		tt_srpt->title[counter].title_set_sector = sector;

	}
	return (ifofile);
}

EXPORT ifo_handle_t *
ifoOpen(dvd_reader_t *dvd, int title)
{
	/* The main ifofile structure */
	ifo_handle_t *ifofile;

	/* File handles and offset */
	int file;
	off_t offset;
	char full_path[ PATH_MAX + 1 ];

	/* Identifier of the IFO */
	char identifier[13];

	identifier[0] = '\0';

	ifofile = (ifo_handle_t *)e_malloc(sizeof(ifo_handle_t));

	memset(ifofile, 0, sizeof(ifo_handle_t));

	if(title) {
		snprintf(full_path, sizeof(full_path),
				"%s/VIDEO_TS/VTS_%02d_0.IFO", dvd->path_root, title);
	} else {
		snprintf(full_path, sizeof(full_path),
				"%s/VIDEO_TS/VIDEO_TS.IFO", dvd->path_root);
	}

	if ((file = open(full_path, O_RDONLY | O_BINARY)) == -1) {
#ifdef	USE_LIBSCHILY
		errmsg("Faild to open %s\n", full_path);
#else
		fprintf(stderr, "Faild to open %s\n", full_path);
#endif
		free(ifofile);
		return(0);
	}

	offset = 0;

	/* Determine if we have a VMGI or VTSI */

	if (read(file, identifier, sizeof(identifier)) != sizeof(identifier)) {
#ifdef	USE_LIBSCHILY
		errmsg("Faild to read VIDEO_TS.IFO\n");
#else
		fprintf(stderr, "Faild to read VIDEO_TS.IFO\n");
#endif
		return(0);
	}

	if ((strstr("DVDVIDEO-VMG", identifier) != 0) && (title == 0)) {
		ifofile = ifoReadVGMI(file, ifofile);
		close(file);
		return(ifofile);
	} else if ((strstr("DVDVIDEO-VTS", identifier) != 0) && (title != 0)) {
		ifofile = ifoReadVTSI(file, ifofile);
		close(file);
		return(ifofile);
	} else {
#ifdef	USE_LIBSCHILY
		errmsgno(EX_BAD, "Giving up this is not a valid IFO file\n");
#else
		fprintf(stderr, "Giving up this is not a valid IFO file\n");
#endif
		close(file);
		free(ifofile);
		ifofile=0;
		return(0);
	}
}

LOCAL void
ifoFree_TT_SRPT(ifo_handle_t *ifofile)
{
	if(!ifofile)
		return;

	if(ifofile->tt_srpt) {
		if(ifofile->tt_srpt->title) {
			free(ifofile->tt_srpt->title);
		}
		free(ifofile->tt_srpt);
		ifofile->tt_srpt = 0;
	}
	return;
}

EXPORT void
ifoClose(ifo_handle_t *ifofile)
{

	if(!ifofile)
		return;

	ifoFree_TT_SRPT(ifofile);

	if (ifofile->vmgi_mat) {
		free(ifofile->vtsi_mat);
	}

	if (ifofile->vtsi_mat) {
		free(ifofile->vtsi_mat);
	}

	free(ifofile);
	ifofile=0;
}
#endif /* DVD_VIDEO */
