/* * This file has been modified for the cdrkit suite. * * The behaviour and appearence of the program code below can differ to a major * extent from the version distributed by the original author(s). * * For details, see Changelog file distributed with the cdrkit package. If you * received this file from another source then ask the distributing person for * a log of modifications. * */ /* @(#)dvd_file.c 1.3 04/03/04 joerg */ /* * DVD_VIDEO code * Copyright (c) 2002 Olaf Beck - olaf_sc@yahoo.com * Jörg Schilling * (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 version 2 * as published by the Free Software Foundation. * * 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; see the file COPYING. If not, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef DVD_VIDEO #include #include "genisoimage.h" #include #include "dvd_reader.h" #include "dvd_file.h" #include "ifo_read.h" static void bsort(int sector[], int title[], int size); static void uniq(int sector[], int title[], int title_sets_array[], int sector_sets_array[], int titles); static void DVDFreeFileSetArrays(int *sector, int *title, int *title_sets_array, int *sector_sets_array); void DVDFreeFileSet(title_set_info_t *title_set_info); title_set_info_t *DVDGetFileSet(char *dvd); int DVDGetFilePad(title_set_info_t *title_set_info, char *name); static void bsort(int sector[], int title[], int size) { int temp_title; int temp_sector; int i; int j; /* this is not bubble sort, this is primitive selection sort. Replace with * bubble sort later, maybe bidirectional, aka Coctail Sort */ for (i = 0; i < size; i++) { for (j = 0; j < size; j++) { if (sector[i] < sector[j]) { temp_sector = sector[i]; temp_title = title[i]; sector[i] = sector[j]; title[i] = title[j]; sector[j] = temp_sector; title[j] = temp_title; } } } } static void uniq(int sector[], int title[], int title_sets_array[], int sector_sets_array[], int titles) { int i; int j; for (i = 0, j = 0; j < titles; ) { if (sector[j] != sector[j+1]) { title_sets_array[i] = title[j]; sector_sets_array[i] = sector[j]; #ifdef DEBUG fprintf(stderr, "Sector offset is %d\n", sector_sets_array[i]); #endif i++; j++; } else { do { if (j < titles) j++; } while (sector[j] == sector[j+1]); } } } static void DVDFreeFileSetArrays(int *sector, int *title, int *title_sets_array, int *sector_sets_array) { free(sector); free(title); free(title_sets_array); free(sector_sets_array); } void DVDFreeFileSet(title_set_info_t *title_set_info) { free(title_set_info->title_set); free(title_set_info); } title_set_info_t * DVDGetFileSet(char *dvd) { /* * TODO Fix close of files if * we error out * We also assume that all * DVD files are of valid * size i.e. file%2048 == 0 */ /* title interation */ int title_sets; int titles; int counter; int i; /* DVD file structures */ dvd_reader_t * _dvd = NULL; ifo_handle_t * vmg_ifo = NULL; ifo_handle_t * vts_ifo = NULL; dvd_file_t * vmg_vob_file = NULL; dvd_file_t * vmg_ifo_file = NULL; dvd_file_t * vts_ifo_file = NULL; dvd_file_t * vts_menu_file = NULL; dvd_file_t * vts_title_file = NULL; /* The sizes it self of each file */ int ifo; int bup; int menu_vob; int title_vob; /* Arrays keeping the title - filset relationship */ int * sector; int * title; int * title_sets_array; int * sector_sets_array; /* DVD Video files */ struct stat fileinfo; char temppoint[PATH_MAX + 1]; /* The Title Set Info struct*/ title_set_info_t * title_set_info; /* Temporary mount point - to be used later */ char mountpoint[PATH_MAX + 1]; strncpy(mountpoint, dvd, sizeof (mountpoint)); mountpoint[sizeof (mountpoint)-1] = '\0'; _dvd = DVDOpen(dvd); if (!_dvd) { #ifdef USE_LIBSCHILY errmsgno(EX_BAD, "Can't open device '%s'\n", dvd); #else fprintf(stderr, "Can't open device\n"); #endif return (0); } vmg_ifo = ifoOpen(_dvd, 0); if (!vmg_ifo) { #ifdef USE_LIBSCHILY errmsgno(EX_BAD, "Can't open VMG info for '%s'.\n", dvd); #else fprintf(stderr, "Can't open VMG info.\n"); #endif return (0); } /* Check mount point */ snprintf(temppoint, sizeof (temppoint), "%s/VIDEO_TS/VIDEO_TS.IFO", mountpoint); if (stat(temppoint, &fileinfo) < 0) { /* If we can't stat the file, give up */ #ifdef USE_LIBSCHILY errmsg("Can't stat %s\n", temppoint); #else fprintf(stderr, "Can't stat %s\n", temppoint); perror(""); #endif return (0); } title_sets = vmg_ifo->vmgi_mat->vmg_nr_of_title_sets; titles = vmg_ifo->tt_srpt->nr_of_srpts; sector = e_malloc(titles * sizeof (int)); memset(sector, 0, titles * sizeof (int)); title = e_malloc(titles * sizeof (int)); title_sets_array = e_malloc(title_sets * sizeof (int)); sector_sets_array = e_malloc(title_sets * sizeof (int)); title_set_info = (title_set_info_t *)e_malloc(sizeof (title_set_info_t)); title_set_info->title_set = (title_set_t *)e_malloc((title_sets + 1) * sizeof (title_set_t)); title_set_info->num_titles = title_sets; /* Fill and sort the arrays for titles*/ if (titles >= 1) { for (counter = 0; counter < titles; counter++) { sector[counter] = vmg_ifo->tt_srpt->title[counter].title_set_sector; title[counter] = counter + 1; } } /* Yes, we should probably do a better sort than B - but what the heck*/ bsort(sector, title, titles); /* * Since title sets and titles are not the same we will need to sort * out "bogus" titles */ uniq(sector, title, title_sets_array, sector_sets_array, titles); /* Open VIDEO_TS.VOB is present */ vmg_vob_file = DVDOpenFile(_dvd, 0, DVD_READ_MENU_VOBS); /* Check VIDEO_TS title set */ vmg_ifo_file = DVDOpenFile(_dvd, 0, DVD_READ_INFO_FILE); if ((vmg_vob_file == 0) && vmg_ifo->vmgi_mat->vmg_last_sector + 1 < 2 * DVDFileSize(vmg_ifo_file)) { #ifdef USE_LIBSCHILY errmsgno(EX_BAD, "IFO is not of correct size aborting\n"); #else fprintf(stderr, "IFO is not of correct size aborting\n"); #endif DVDFreeFileSetArrays(sector, title, title_sets_array, sector_sets_array); DVDFreeFileSet(title_set_info); return (0); } else if ((vmg_vob_file != 0) && (vmg_ifo->vmgi_mat->vmg_last_sector + 1 < 2 * DVDFileSize(vmg_ifo_file) + DVDFileSize(vmg_vob_file))) { #ifdef USE_LIBSCHILY errmsgno(EX_BAD, "Either VIDEO_TS.IFO or VIDEO_TS.VOB is not of correct size"); #else fprintf(stderr, "Either VIDEO_TS.IFO or VIDEO_TS.VOB is not of correct size"); #endif DVDFreeFileSetArrays(sector, title, title_sets_array, sector_sets_array); DVDFreeFileSet(title_set_info); return (0); } /* Find the actuall right size of VIDEO_TS.IFO */ if (vmg_vob_file == 0) { if (vmg_ifo->vmgi_mat->vmg_last_sector + 1 > 2 * DVDFileSize(vmg_ifo_file)) { ifo = vmg_ifo->vmgi_mat->vmg_last_sector - DVDFileSize(vmg_ifo_file) + 1; } else { ifo = vmg_ifo->vmgi_mat->vmgi_last_sector + 1; } } else { if (vmg_ifo->vmgi_mat->vmgi_last_sector + 1 < vmg_ifo->vmgi_mat->vmgm_vobs) { ifo = vmg_ifo->vmgi_mat->vmgm_vobs; } else { ifo = vmg_ifo->vmgi_mat->vmgi_last_sector + 1; } } title_set_info->title_set[0].size_ifo = ifo * 2048; title_set_info->title_set[0].realsize_ifo = fileinfo.st_size; title_set_info->title_set[0].pad_ifo = ifo - DVDFileSize(vmg_ifo_file); /* Find the actuall right size of VIDEO_TS.VOB */ if (vmg_vob_file != 0) { if (ifo + DVDFileSize(vmg_ifo_file) + DVDFileSize(vmg_vob_file) - 1 < vmg_ifo->vmgi_mat->vmg_last_sector) { menu_vob = vmg_ifo->vmgi_mat->vmg_last_sector - ifo - DVDFileSize(vmg_ifo_file) + 1; } else { menu_vob = vmg_ifo->vmgi_mat->vmg_last_sector - ifo - DVDFileSize(vmg_ifo_file) + 1; } snprintf(temppoint, sizeof (temppoint), "%s/VIDEO_TS/VIDEO_TS.VOB", mountpoint); if (stat(temppoint, &fileinfo) < 0) { #ifdef USE_LIBSCHILY errmsg("calc: Can't stat %s\n", temppoint); #else fprintf(stderr, "calc: Can't stat %s\n", temppoint); perror(""); #endif DVDFreeFileSetArrays(sector, title, title_sets_array, sector_sets_array); DVDFreeFileSet(title_set_info); return (0); } title_set_info->title_set[0].realsize_menu = fileinfo.st_size; title_set_info->title_set[0].pad_menu = menu_vob - DVDFileSize(vmg_vob_file); title_set_info->title_set[0].size_menu = menu_vob * 2048; DVDCloseFile(vmg_vob_file); } else { title_set_info->title_set[0].size_menu = 0; title_set_info->title_set[0].realsize_menu = 0; title_set_info->title_set[0].pad_menu = 0; menu_vob = 0; } /* Finding the actuall right size of VIDEO_TS.BUP */ if (title_sets >= 1) { bup = sector_sets_array[0] - menu_vob - ifo; } else { /* Just in case we burn a DVD-Video without any title_sets */ bup = vmg_ifo->vmgi_mat->vmg_last_sector + 1 - menu_vob - ifo; } /* Never trust the BUP file - use a copy of the IFO */ snprintf(temppoint, sizeof (temppoint), "%s/VIDEO_TS/VIDEO_TS.IFO", mountpoint); if (stat(temppoint, &fileinfo) < 0) { #ifdef USE_LIBSCHILY errmsg("calc: Can't stat %s\n", temppoint); #else fprintf(stderr, "calc: Can't stat %s\n", temppoint); perror(""); #endif DVDFreeFileSetArrays(sector, title, title_sets_array, sector_sets_array); DVDFreeFileSet(title_set_info); return (0); } title_set_info->title_set[0].realsize_bup = fileinfo.st_size; title_set_info->title_set[0].size_bup = bup * 2048; title_set_info->title_set[0].pad_bup = bup - DVDFileSize(vmg_ifo_file); /* Take care of the titles which we don't have in VMG */ title_set_info->title_set[0].number_of_vob_files = 0; title_set_info->title_set[0].realsize_vob[0] = 0; title_set_info->title_set[0].pad_title = 0; DVDCloseFile(vmg_ifo_file); if (title_sets >= 1) { for (counter = 0; counter < title_sets; counter++) { vts_ifo = ifoOpen(_dvd, counter + 1); if (!vts_ifo) { #ifdef USE_LIBSCHILY errmsgno(EX_BAD, "Can't open VTS info.\n"); #else fprintf(stderr, "Can't open VTS info.\n"); #endif DVDFreeFileSetArrays(sector, title, title_sets_array, sector_sets_array); DVDFreeFileSet(title_set_info); return (0); } snprintf(temppoint, sizeof (temppoint), "%s/VIDEO_TS/VTS_%02i_0.IFO", mountpoint, counter + 1); if (stat(temppoint, &fileinfo) < 0) { #ifdef USE_LIBSCHILY errmsg("calc: Can't stat %s\n", temppoint); #else fprintf(stderr, "calc: Can't stat %s\n", temppoint); perror(""); #endif DVDFreeFileSetArrays(sector, title, title_sets_array, sector_sets_array); DVDFreeFileSet(title_set_info); return (0); } /* Test if VTS_XX_0.VOB is present */ vts_menu_file = DVDOpenFile(_dvd, counter + 1, DVD_READ_MENU_VOBS); /* Test if VTS_XX_X.VOB are present */ vts_title_file = DVDOpenFile(_dvd, counter + 1, DVD_READ_TITLE_VOBS); /* Check VIDEO_TS.IFO */ vts_ifo_file = DVDOpenFile(_dvd, counter + 1, DVD_READ_INFO_FILE); /* * Checking that title will fit in the * space given by the ifo file */ if (vts_ifo->vtsi_mat->vts_last_sector + 1 < 2 * DVDFileSize(vts_ifo_file)) { #ifdef USE_LIBSCHILY errmsgno(EX_BAD, "IFO is not of correct size aborting.\n"); #else fprintf(stderr, "IFO is not of correct size aborting\n"); #endif DVDFreeFileSetArrays(sector, title, title_sets_array, sector_sets_array); DVDFreeFileSet(title_set_info); return (0); } else if ((vts_title_file != 0) && (vts_menu_file != 0) && (vts_ifo->vtsi_mat->vts_last_sector + 1 < 2 * DVDFileSize(vts_ifo_file) + DVDFileSize(vts_title_file) + DVDFileSize(vts_menu_file))) { #ifdef USE_LIBSCHILY errmsgno(EX_BAD, "Either VIDEO_TS.IFO or VIDEO_TS.VOB is not of correct size.\n"); #else fprintf(stderr, "Either VIDEO_TS.IFO or VIDEO_TS.VOB is not of correct size"); #endif DVDFreeFileSetArrays(sector, title, title_sets_array, sector_sets_array); DVDFreeFileSet(title_set_info); return (0); } else if ((vts_title_file != 0) && (vts_menu_file == 0) && (vts_ifo->vtsi_mat->vts_last_sector + 1 < 2 * DVDFileSize(vts_ifo_file) + DVDFileSize(vts_title_file))) { #ifdef USE_LIBSCHILY errmsgno(EX_BAD, "Either VIDEO_TS.IFO or VIDEO_TS.VOB is not of correct size.\n"); #else fprintf(stderr, "Either VIDEO_TS.IFO or VIDEO_TS.VOB is not of correct size"); #endif DVDFreeFileSetArrays(sector, title, title_sets_array, sector_sets_array); DVDFreeFileSet(title_set_info); return (0); } else if ((vts_menu_file != 0) && (vts_title_file == 0) && (vts_ifo->vtsi_mat->vts_last_sector + 1 < 2 * DVDFileSize(vts_ifo_file) + DVDFileSize(vts_menu_file))) { #ifdef USE_LIBSCHILY errmsgno(EX_BAD, "Either VIDEO_TS.IFO or VIDEO_TS.VOB is not of correct size.\n"); #else fprintf(stderr, "Either VIDEO_TS.IFO or VIDEO_TS.VOB is not of correct size"); #endif DVDFreeFileSetArrays(sector, title, title_sets_array, sector_sets_array); DVDFreeFileSet(title_set_info); return (0); } /* Find the actuall right size of VTS_XX_0.IFO */ if ((vts_title_file == 0) && (vts_menu_file == 0)) { if (vts_ifo->vtsi_mat->vts_last_sector + 1 > 2 * DVDFileSize(vts_ifo_file)) { ifo = vts_ifo->vtsi_mat->vts_last_sector - DVDFileSize(vts_ifo_file) + 1; } else { ifo = vts_ifo->vtsi_mat->vts_last_sector - DVDFileSize(vts_ifo_file) + 1; } } else if (vts_title_file == 0) { if (vts_ifo->vtsi_mat->vtsi_last_sector + 1 < vts_ifo->vtsi_mat->vtstt_vobs) { ifo = vmg_ifo->vtsi_mat->vtstt_vobs; } else { ifo = vmg_ifo->vtsi_mat->vtstt_vobs; } } else { if (vts_ifo->vtsi_mat->vtsi_last_sector + 1 < vts_ifo->vtsi_mat->vtsm_vobs) { ifo = vts_ifo->vtsi_mat->vtsm_vobs; } else { ifo = vts_ifo->vtsi_mat->vtsi_last_sector + 1; } } title_set_info->title_set[counter + 1].size_ifo = ifo * 2048; title_set_info->title_set[counter + 1].realsize_ifo = fileinfo.st_size; title_set_info->title_set[counter + 1].pad_ifo = ifo - DVDFileSize(vts_ifo_file); /* Find the actuall right size of VTS_XX_0.VOB */ if (vts_menu_file != 0) { if (vts_ifo->vtsi_mat->vtsm_vobs == 0) { /* * Apparently start sector 0 means that * VTS_XX_0.VOB is empty after all... */ menu_vob = 0; if (DVDFileSize(vts_menu_file) != 0) { /* * Paranoia: we most likely never * come here... */ #ifdef USE_LIBSCHILY errmsgno(EX_BAD, "%s/VIDEO_TS/VTS_%02i_0.IFO appears to be corrupted.\n", mountpoint, counter+1); #else fprintf(stderr, "%s/VIDEO_TS/VTS_%02i_0.IFO appears to be corrupted.\n", mountpoint, counter+1); #endif return (0); } } else if ((vts_title_file != 0) && (vts_ifo->vtsi_mat->vtstt_vobs - vts_ifo->vtsi_mat->vtsm_vobs > DVDFileSize(vts_menu_file))) { menu_vob = vts_ifo->vtsi_mat->vtstt_vobs - vts_ifo->vtsi_mat->vtsm_vobs; } else if ((vts_title_file == 0) && (vts_ifo->vtsi_mat->vtsm_vobs + DVDFileSize(vts_menu_file) + DVDFileSize(vts_ifo_file) - 1 < vts_ifo->vtsi_mat->vts_last_sector)) { menu_vob = vts_ifo->vtsi_mat->vts_last_sector - DVDFileSize(vts_ifo_file) - vts_ifo->vtsi_mat->vtsm_vobs + 1; } else { menu_vob = vts_ifo->vtsi_mat->vtstt_vobs - vts_ifo->vtsi_mat->vtsm_vobs; } snprintf(temppoint, sizeof (temppoint), "%s/VIDEO_TS/VTS_%02i_0.VOB", mountpoint, counter + 1); if (stat(temppoint, &fileinfo) < 0) { #ifdef USE_LIBSCHILY errmsg("calc: Can't stat %s\n", temppoint); #else fprintf(stderr, "calc: Can't stat %s\n", temppoint); perror(""); #endif DVDFreeFileSetArrays(sector, title, title_sets_array, sector_sets_array); DVDFreeFileSet(title_set_info); return (0); } title_set_info->title_set[counter + 1].realsize_menu = fileinfo.st_size; title_set_info->title_set[counter + 1].size_menu = menu_vob * 2048; title_set_info->title_set[counter + 1].pad_menu = menu_vob - DVDFileSize(vts_menu_file); } else { title_set_info->title_set[counter + 1].size_menu = 0; title_set_info->title_set[counter + 1].realsize_menu = 0; title_set_info->title_set[counter + 1].pad_menu = 0; menu_vob = 0; } /* Find the actuall total size of VTS_XX_[1 to 9].VOB */ if (vts_title_file != 0) { if (ifo + menu_vob + DVDFileSize(vts_ifo_file) - 1 < vts_ifo->vtsi_mat->vts_last_sector) { title_vob = vts_ifo->vtsi_mat->vts_last_sector + 1 - ifo - menu_vob - DVDFileSize(vts_ifo_file); } else { title_vob = vts_ifo->vtsi_mat->vts_last_sector + 1 - ifo - menu_vob - DVDFileSize(vts_ifo_file); } /* * Find out how many vob files * and the size of them */ for (i = 0; i < 9; ++i) { snprintf(temppoint, sizeof (temppoint), "%s/VIDEO_TS/VTS_%02i_%i.VOB", mountpoint, counter + 1, i + 1); if (stat(temppoint, &fileinfo) < 0) { break; } title_set_info->title_set[counter + 1].realsize_vob[i] = fileinfo.st_size; } title_set_info->title_set[counter + 1].number_of_vob_files = i; title_set_info->title_set[counter + 1].size_title = title_vob * 2048; title_set_info->title_set[counter + 1].pad_title = title_vob - DVDFileSize(vts_title_file); } else { title_set_info->title_set[counter + 1].number_of_vob_files = 0; title_set_info->title_set[counter + 1].realsize_vob[0] = 0; title_set_info->title_set[counter + 1].size_title = 0; title_set_info->title_set[counter + 1].pad_title = 0; title_vob = 0; } /* Find the actuall total size of VTS_XX_0.BUP */ if (title_sets - 1 > counter) { bup = sector_sets_array[counter+1] - sector_sets_array[counter] - title_vob - menu_vob - ifo; } else { bup = vts_ifo->vtsi_mat->vts_last_sector + 1 - title_vob - menu_vob - ifo; } /* Never trust the BUP use a copy of the IFO */ snprintf(temppoint, sizeof (temppoint), "%s/VIDEO_TS/VTS_%02i_0.IFO", mountpoint, counter + 1); if (stat(temppoint, &fileinfo) < 0) { #ifdef USE_LIBSCHILY errmsg("calc: Can't stat %s\n", temppoint); #else fprintf(stderr, "calc: Can't stat %s\n", temppoint); perror(""); #endif DVDFreeFileSetArrays(sector, title, title_sets_array, sector_sets_array); DVDFreeFileSet(title_set_info); return (0); } title_set_info->title_set[counter + 1].size_bup = bup * 2048; title_set_info->title_set[counter + 1].realsize_bup = fileinfo.st_size; title_set_info->title_set[counter + 1].pad_bup = bup - DVDFileSize(vts_ifo_file); /* Closing files */ if (vts_menu_file != 0) { DVDCloseFile(vts_menu_file); } if (vts_title_file != 0) { DVDCloseFile(vts_title_file); } if (vts_ifo_file != 0) { DVDCloseFile(vts_ifo_file); } ifoClose(vts_ifo); } } DVDFreeFileSetArrays(sector, title, title_sets_array, sector_sets_array); /* Close the VMG ifo file we got all the info we need */ ifoClose(vmg_ifo); /* Close the DVD */ DVDClose(_dvd); /* Return the actuall info*/ return (title_set_info); } int DVDGetFilePad(title_set_info_t *title_set_info, char *name) { char title_a[3]; char vob_a[2]; int title; int vob; title_a[0] = title_a[1] = title_a[2] = '\0'; vob_a[0] = vob_a[1] = '\0'; if (name[0] != 'V') { return (0); } if (memcmp(name, "VIDEO_TS", 8) == 0) { if (strstr(name, ".IFO") != 0) { return (title_set_info->title_set[0].pad_ifo); } else if (strstr(name, ".VOB") != 0) { return (title_set_info->title_set[0].pad_menu); } else if (strstr(name, ".BUP") != 0) { return (title_set_info->title_set[0].pad_bup); } else { return (0); } } else if (memcmp(name, "VTS_", 4) == 0) { title_a[0] = name[4]; title_a[1] = name[5]; title_a[2] = '\0'; vob_a[0] = name[7]; vob_a[1] = '\0'; title = atoi(title_a); vob = atoi(vob_a); if (title > title_set_info->num_titles) { return (0); } else { if (strstr(name, ".IFO") != 0) { return (title_set_info->title_set[title].pad_ifo); } else if (strstr(name, ".BUP") != 0) { return (title_set_info->title_set[title].pad_bup); } else if (vob == 0) { return (title_set_info->title_set[title].pad_menu); } else if (vob == title_set_info->title_set[title].number_of_vob_files) { return (title_set_info->title_set[title].pad_title); } else { return (0); } } } else { return (0); } } #endif /*DVD_VIDEO*/