2 * This file has been modified for the cdrkit suite.
4 * The behaviour and appearence of the program code below can differ to a major
5 * extent from the version distributed by the original author(s).
7 * For details, see Changelog file distributed with the cdrkit package. If you
8 * received this file from another source then ask the distributing person for
9 * a log of modifications.
13 /* @(#)dvd_file.c 1.3 04/03/04 joerg */
16 * Copyright (c) 2002 Olaf Beck - olaf_sc@yahoo.com
17 * Jörg Schilling <schilling@fokus.gmd.de>
18 * (making the code portable)
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License version 2
23 * as published by the Free Software Foundation.
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
30 * You should have received a copy of the GNU General Public License along with
31 * this program; see the file COPYING. If not, write to the Free Software
32 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
38 #include "genisoimage.h"
40 #include "dvd_reader.h"
44 static void bsort(int sector[], int title[], int size);
45 static void uniq(int sector[], int title[], int title_sets_array[],
46 int sector_sets_array[], int titles);
47 static void DVDFreeFileSetArrays(int *sector, int *title,
48 int *title_sets_array,
49 int *sector_sets_array);
50 void DVDFreeFileSet(title_set_info_t *title_set_info);
51 title_set_info_t *DVDGetFileSet(char *dvd);
52 int DVDGetFilePad(title_set_info_t *title_set_info, char *name);
56 bsort(int sector[], int title[], int size)
63 /* this is not bubble sort, this is primitive selection sort. Replace with
64 * bubble sort later, maybe bidirectional, aka Coctail Sort */
65 for (i = 0; i < size; i++) {
66 for (j = 0; j < size; j++) {
67 if (sector[i] < sector[j]) {
68 temp_sector = sector[i];
69 temp_title = title[i];
70 sector[i] = sector[j];
72 sector[j] = temp_sector;
73 title[j] = temp_title;
81 uniq(int sector[], int title[], int title_sets_array[],
82 int sector_sets_array[], int titles)
88 for (i = 0, j = 0; j < titles; ) {
89 if (sector[j] != sector[j+1]) {
90 title_sets_array[i] = title[j];
91 sector_sets_array[i] = sector[j];
93 fprintf(stderr, "Sector offset is %d\n", sector_sets_array[i]);
102 } while (sector[j] == sector[j+1]);
110 DVDFreeFileSetArrays(int *sector, int *title, int *title_sets_array,
111 int *sector_sets_array)
115 free(title_sets_array);
116 free(sector_sets_array);
120 DVDFreeFileSet(title_set_info_t *title_set_info)
122 free(title_set_info->title_set);
123 free(title_set_info);
127 DVDGetFileSet(char *dvd)
130 * TODO Fix close of files if
132 * We also assume that all
133 * DVD files are of valid
134 * size i.e. file%2048 == 0
137 /* title interation */
143 /* DVD file structures */
144 dvd_reader_t * _dvd = NULL;
146 ifo_handle_t * vmg_ifo = NULL;
147 ifo_handle_t * vts_ifo = NULL;
149 dvd_file_t * vmg_vob_file = NULL;
150 dvd_file_t * vmg_ifo_file = NULL;
152 dvd_file_t * vts_ifo_file = NULL;
153 dvd_file_t * vts_menu_file = NULL;
154 dvd_file_t * vts_title_file = NULL;
156 /* The sizes it self of each file */
162 /* Arrays keeping the title - filset relationship */
165 int * title_sets_array;
166 int * sector_sets_array;
168 /* DVD Video files */
169 struct stat fileinfo;
170 char temppoint[PATH_MAX + 1];
172 /* The Title Set Info struct*/
173 title_set_info_t * title_set_info;
175 /* Temporary mount point - to be used later */
176 char mountpoint[PATH_MAX + 1];
178 strncpy(mountpoint, dvd, sizeof (mountpoint));
179 mountpoint[sizeof (mountpoint)-1] = '\0';
185 errmsgno(EX_BAD, "Can't open device '%s'\n", dvd);
187 fprintf(stderr, "Can't open device\n");
191 vmg_ifo = ifoOpen(_dvd, 0);
194 errmsgno(EX_BAD, "Can't open VMG info for '%s'.\n", dvd);
196 fprintf(stderr, "Can't open VMG info.\n");
201 /* Check mount point */
203 snprintf(temppoint, sizeof (temppoint),
204 "%s/VIDEO_TS/VIDEO_TS.IFO", mountpoint);
207 if (stat(temppoint, &fileinfo) < 0) {
208 /* If we can't stat the file, give up */
210 errmsg("Can't stat %s\n", temppoint);
212 fprintf(stderr, "Can't stat %s\n", temppoint);
220 title_sets = vmg_ifo->vmgi_mat->vmg_nr_of_title_sets;
221 titles = vmg_ifo->tt_srpt->nr_of_srpts;
223 sector = e_malloc(titles * sizeof (int));
224 memset(sector, 0, titles * sizeof (int));
225 title = e_malloc(titles * sizeof (int));
226 title_sets_array = e_malloc(title_sets * sizeof (int));
227 sector_sets_array = e_malloc(title_sets * sizeof (int));
228 title_set_info = (title_set_info_t *)e_malloc(sizeof (title_set_info_t));
229 title_set_info->title_set = (title_set_t *)e_malloc((title_sets + 1) *
230 sizeof (title_set_t));
232 title_set_info->num_titles = title_sets;
235 /* Fill and sort the arrays for titles*/
238 for (counter = 0; counter < titles; counter++) {
239 sector[counter] = vmg_ifo->tt_srpt->title[counter].title_set_sector;
240 title[counter] = counter + 1;
244 /* Yes, we should probably do a better sort than B - but what the heck*/
245 bsort(sector, title, titles);
249 * Since title sets and titles are not the same we will need to sort
253 uniq(sector, title, title_sets_array, sector_sets_array, titles);
256 /* Open VIDEO_TS.VOB is present */
258 vmg_vob_file = DVDOpenFile(_dvd, 0, DVD_READ_MENU_VOBS);
260 /* Check VIDEO_TS title set */
262 vmg_ifo_file = DVDOpenFile(_dvd, 0, DVD_READ_INFO_FILE);
264 if ((vmg_vob_file == 0) && vmg_ifo->vmgi_mat->vmg_last_sector + 1
265 < 2 * DVDFileSize(vmg_ifo_file)) {
267 errmsgno(EX_BAD, "IFO is not of correct size aborting\n");
269 fprintf(stderr, "IFO is not of correct size aborting\n");
271 DVDFreeFileSetArrays(sector, title, title_sets_array,
273 DVDFreeFileSet(title_set_info);
275 } else if ((vmg_vob_file != 0) && (vmg_ifo->vmgi_mat->vmg_last_sector
276 + 1 < 2 * DVDFileSize(vmg_ifo_file) +
277 DVDFileSize(vmg_vob_file))) {
279 errmsgno(EX_BAD, "Either VIDEO_TS.IFO or VIDEO_TS.VOB is not of correct size");
281 fprintf(stderr, "Either VIDEO_TS.IFO or VIDEO_TS.VOB is not of correct size");
283 DVDFreeFileSetArrays(sector, title, title_sets_array,
285 DVDFreeFileSet(title_set_info);
289 /* Find the actuall right size of VIDEO_TS.IFO */
290 if (vmg_vob_file == 0) {
291 if (vmg_ifo->vmgi_mat->vmg_last_sector + 1 > 2
292 * DVDFileSize(vmg_ifo_file)) {
293 ifo = vmg_ifo->vmgi_mat->vmg_last_sector
294 - DVDFileSize(vmg_ifo_file) + 1;
296 ifo = vmg_ifo->vmgi_mat->vmgi_last_sector + 1;
299 if (vmg_ifo->vmgi_mat->vmgi_last_sector + 1
300 < vmg_ifo->vmgi_mat->vmgm_vobs) {
301 ifo = vmg_ifo->vmgi_mat->vmgm_vobs;
303 ifo = vmg_ifo->vmgi_mat->vmgi_last_sector + 1;
307 title_set_info->title_set[0].size_ifo = ifo * 2048;
308 title_set_info->title_set[0].realsize_ifo = fileinfo.st_size;
309 title_set_info->title_set[0].pad_ifo = ifo - DVDFileSize(vmg_ifo_file);
311 /* Find the actuall right size of VIDEO_TS.VOB */
312 if (vmg_vob_file != 0) {
313 if (ifo + DVDFileSize(vmg_ifo_file) +
314 DVDFileSize(vmg_vob_file) - 1 <
315 vmg_ifo->vmgi_mat->vmg_last_sector) {
316 menu_vob = vmg_ifo->vmgi_mat->vmg_last_sector -
317 ifo - DVDFileSize(vmg_ifo_file) + 1;
319 menu_vob = vmg_ifo->vmgi_mat->vmg_last_sector
320 - ifo - DVDFileSize(vmg_ifo_file) + 1;
323 snprintf(temppoint, sizeof (temppoint),
324 "%s/VIDEO_TS/VIDEO_TS.VOB", mountpoint);
325 if (stat(temppoint, &fileinfo) < 0) {
327 errmsg("calc: Can't stat %s\n", temppoint);
329 fprintf(stderr, "calc: Can't stat %s\n", temppoint);
332 DVDFreeFileSetArrays(sector, title, title_sets_array,
334 DVDFreeFileSet(title_set_info);
338 title_set_info->title_set[0].realsize_menu = fileinfo.st_size;
339 title_set_info->title_set[0].pad_menu = menu_vob -
340 DVDFileSize(vmg_vob_file);
341 title_set_info->title_set[0].size_menu = menu_vob * 2048;
342 DVDCloseFile(vmg_vob_file);
344 title_set_info->title_set[0].size_menu = 0;
345 title_set_info->title_set[0].realsize_menu = 0;
346 title_set_info->title_set[0].pad_menu = 0;
351 /* Finding the actuall right size of VIDEO_TS.BUP */
352 if (title_sets >= 1) {
353 bup = sector_sets_array[0] - menu_vob - ifo;
355 /* Just in case we burn a DVD-Video without any title_sets */
356 bup = vmg_ifo->vmgi_mat->vmg_last_sector + 1 - menu_vob - ifo;
359 /* Never trust the BUP file - use a copy of the IFO */
360 snprintf(temppoint, sizeof (temppoint),
361 "%s/VIDEO_TS/VIDEO_TS.IFO", mountpoint);
363 if (stat(temppoint, &fileinfo) < 0) {
365 errmsg("calc: Can't stat %s\n", temppoint);
367 fprintf(stderr, "calc: Can't stat %s\n", temppoint);
370 DVDFreeFileSetArrays(sector, title, title_sets_array,
372 DVDFreeFileSet(title_set_info);
376 title_set_info->title_set[0].realsize_bup = fileinfo.st_size;
377 title_set_info->title_set[0].size_bup = bup * 2048;
378 title_set_info->title_set[0].pad_bup = bup - DVDFileSize(vmg_ifo_file);
380 /* Take care of the titles which we don't have in VMG */
382 title_set_info->title_set[0].number_of_vob_files = 0;
383 title_set_info->title_set[0].realsize_vob[0] = 0;
384 title_set_info->title_set[0].pad_title = 0;
386 DVDCloseFile(vmg_ifo_file);
388 if (title_sets >= 1) {
389 for (counter = 0; counter < title_sets; counter++) {
391 vts_ifo = ifoOpen(_dvd, counter + 1);
395 errmsgno(EX_BAD, "Can't open VTS info.\n");
397 fprintf(stderr, "Can't open VTS info.\n");
399 DVDFreeFileSetArrays(sector, title,
400 title_sets_array, sector_sets_array);
401 DVDFreeFileSet(title_set_info);
405 snprintf(temppoint, sizeof (temppoint),
406 "%s/VIDEO_TS/VTS_%02i_0.IFO",
407 mountpoint, counter + 1);
409 if (stat(temppoint, &fileinfo) < 0) {
411 errmsg("calc: Can't stat %s\n", temppoint);
413 fprintf(stderr, "calc: Can't stat %s\n",
417 DVDFreeFileSetArrays(sector, title,
418 title_sets_array, sector_sets_array);
419 DVDFreeFileSet(title_set_info);
424 /* Test if VTS_XX_0.VOB is present */
426 vts_menu_file = DVDOpenFile(_dvd, counter + 1,
429 /* Test if VTS_XX_X.VOB are present */
431 vts_title_file = DVDOpenFile(_dvd, counter + 1,
432 DVD_READ_TITLE_VOBS);
434 /* Check VIDEO_TS.IFO */
436 vts_ifo_file = DVDOpenFile(_dvd, counter + 1,
440 * Checking that title will fit in the
441 * space given by the ifo file
445 if (vts_ifo->vtsi_mat->vts_last_sector + 1
446 < 2 * DVDFileSize(vts_ifo_file)) {
448 errmsgno(EX_BAD, "IFO is not of correct size aborting.\n");
450 fprintf(stderr, "IFO is not of correct size aborting\n");
452 DVDFreeFileSetArrays(sector, title,
453 title_sets_array, sector_sets_array);
454 DVDFreeFileSet(title_set_info);
456 } else if ((vts_title_file != 0) &&
457 (vts_menu_file != 0) &&
458 (vts_ifo->vtsi_mat->vts_last_sector + 1
459 < 2 * DVDFileSize(vts_ifo_file) +
460 DVDFileSize(vts_title_file) +
461 DVDFileSize(vts_menu_file))) {
463 errmsgno(EX_BAD, "Either VIDEO_TS.IFO or VIDEO_TS.VOB is not of correct size.\n");
465 fprintf(stderr, "Either VIDEO_TS.IFO or VIDEO_TS.VOB is not of correct size");
467 DVDFreeFileSetArrays(sector, title,
468 title_sets_array, sector_sets_array);
469 DVDFreeFileSet(title_set_info);
471 } else if ((vts_title_file != 0) &&
472 (vts_menu_file == 0) &&
473 (vts_ifo->vtsi_mat->vts_last_sector + 1
474 < 2 * DVDFileSize(vts_ifo_file) +
475 DVDFileSize(vts_title_file))) {
477 errmsgno(EX_BAD, "Either VIDEO_TS.IFO or VIDEO_TS.VOB is not of correct size.\n");
479 fprintf(stderr, "Either VIDEO_TS.IFO or VIDEO_TS.VOB is not of correct size");
481 DVDFreeFileSetArrays(sector, title,
482 title_sets_array, sector_sets_array);
483 DVDFreeFileSet(title_set_info);
485 } else if ((vts_menu_file != 0) &&
486 (vts_title_file == 0) &&
487 (vts_ifo->vtsi_mat->vts_last_sector + 1
488 < 2 * DVDFileSize(vts_ifo_file) +
489 DVDFileSize(vts_menu_file))) {
491 errmsgno(EX_BAD, "Either VIDEO_TS.IFO or VIDEO_TS.VOB is not of correct size.\n");
493 fprintf(stderr, "Either VIDEO_TS.IFO or VIDEO_TS.VOB is not of correct size");
495 DVDFreeFileSetArrays(sector, title,
496 title_sets_array, sector_sets_array);
497 DVDFreeFileSet(title_set_info);
502 /* Find the actuall right size of VTS_XX_0.IFO */
503 if ((vts_title_file == 0) && (vts_menu_file == 0)) {
504 if (vts_ifo->vtsi_mat->vts_last_sector + 1 >
505 2 * DVDFileSize(vts_ifo_file)) {
506 ifo = vts_ifo->vtsi_mat->vts_last_sector
507 - DVDFileSize(vts_ifo_file) + 1;
509 ifo = vts_ifo->vtsi_mat->vts_last_sector
510 - DVDFileSize(vts_ifo_file) + 1;
512 } else if (vts_title_file == 0) {
513 if (vts_ifo->vtsi_mat->vtsi_last_sector + 1 <
514 vts_ifo->vtsi_mat->vtstt_vobs) {
515 ifo = vmg_ifo->vtsi_mat->vtstt_vobs;
517 ifo = vmg_ifo->vtsi_mat->vtstt_vobs;
520 if (vts_ifo->vtsi_mat->vtsi_last_sector + 1 <
521 vts_ifo->vtsi_mat->vtsm_vobs) {
522 ifo = vts_ifo->vtsi_mat->vtsm_vobs;
524 ifo = vts_ifo->vtsi_mat->vtsi_last_sector + 1;
527 title_set_info->title_set[counter + 1].size_ifo =
529 title_set_info->title_set[counter + 1].realsize_ifo =
531 title_set_info->title_set[counter + 1].pad_ifo =
532 ifo - DVDFileSize(vts_ifo_file);
535 /* Find the actuall right size of VTS_XX_0.VOB */
536 if (vts_menu_file != 0) {
537 if (vts_ifo->vtsi_mat->vtsm_vobs == 0) {
539 * Apparently start sector 0 means that
540 * VTS_XX_0.VOB is empty after all...
543 if (DVDFileSize(vts_menu_file) != 0) {
545 * Paranoia: we most likely never
550 "%s/VIDEO_TS/VTS_%02i_0.IFO appears to be corrupted.\n",
551 mountpoint, counter+1);
554 "%s/VIDEO_TS/VTS_%02i_0.IFO appears to be corrupted.\n",
555 mountpoint, counter+1);
559 } else if ((vts_title_file != 0) &&
560 (vts_ifo->vtsi_mat->vtstt_vobs -
561 vts_ifo->vtsi_mat->vtsm_vobs >
562 DVDFileSize(vts_menu_file))) {
563 menu_vob = vts_ifo->vtsi_mat->vtstt_vobs -
564 vts_ifo->vtsi_mat->vtsm_vobs;
565 } else if ((vts_title_file == 0) &&
566 (vts_ifo->vtsi_mat->vtsm_vobs +
567 DVDFileSize(vts_menu_file) +
568 DVDFileSize(vts_ifo_file) - 1 <
569 vts_ifo->vtsi_mat->vts_last_sector)) {
570 menu_vob = vts_ifo->vtsi_mat->vts_last_sector
571 - DVDFileSize(vts_ifo_file)
572 - vts_ifo->vtsi_mat->vtsm_vobs + 1;
574 menu_vob = vts_ifo->vtsi_mat->vtstt_vobs -
575 vts_ifo->vtsi_mat->vtsm_vobs;
578 snprintf(temppoint, sizeof (temppoint),
579 "%s/VIDEO_TS/VTS_%02i_0.VOB", mountpoint, counter + 1);
581 if (stat(temppoint, &fileinfo) < 0) {
583 errmsg("calc: Can't stat %s\n", temppoint);
585 fprintf(stderr, "calc: Can't stat %s\n",
589 DVDFreeFileSetArrays(sector, title,
590 title_sets_array, sector_sets_array);
591 DVDFreeFileSet(title_set_info);
595 title_set_info->title_set[counter + 1].realsize_menu = fileinfo.st_size;
596 title_set_info->title_set[counter + 1].size_menu = menu_vob * 2048;
597 title_set_info->title_set[counter + 1].pad_menu = menu_vob - DVDFileSize(vts_menu_file);
600 title_set_info->title_set[counter + 1].size_menu = 0;
601 title_set_info->title_set[counter + 1].realsize_menu = 0;
602 title_set_info->title_set[counter + 1].pad_menu = 0;
607 /* Find the actuall total size of VTS_XX_[1 to 9].VOB */
609 if (vts_title_file != 0) {
610 if (ifo + menu_vob + DVDFileSize(vts_ifo_file) -
611 1 < vts_ifo->vtsi_mat->vts_last_sector) {
612 title_vob = vts_ifo->vtsi_mat->vts_last_sector
613 + 1 - ifo - menu_vob -
614 DVDFileSize(vts_ifo_file);
616 title_vob = vts_ifo->vtsi_mat->vts_last_sector +
618 DVDFileSize(vts_ifo_file);
621 * Find out how many vob files
622 * and the size of them
624 for (i = 0; i < 9; ++i) {
625 snprintf(temppoint, sizeof (temppoint),
626 "%s/VIDEO_TS/VTS_%02i_%i.VOB",
627 mountpoint, counter + 1, i + 1);
628 if (stat(temppoint, &fileinfo) < 0) {
631 title_set_info->title_set[counter + 1].realsize_vob[i] = fileinfo.st_size;
633 title_set_info->title_set[counter + 1].number_of_vob_files = i;
634 title_set_info->title_set[counter + 1].size_title = title_vob * 2048;
635 title_set_info->title_set[counter + 1].pad_title = title_vob - DVDFileSize(vts_title_file);
637 title_set_info->title_set[counter + 1].number_of_vob_files = 0;
638 title_set_info->title_set[counter + 1].realsize_vob[0] = 0;
639 title_set_info->title_set[counter + 1].size_title = 0;
640 title_set_info->title_set[counter + 1].pad_title = 0;
646 /* Find the actuall total size of VTS_XX_0.BUP */
647 if (title_sets - 1 > counter) {
648 bup = sector_sets_array[counter+1]
649 - sector_sets_array[counter]
650 - title_vob - menu_vob - ifo;
652 bup = vts_ifo->vtsi_mat->vts_last_sector + 1
653 - title_vob - menu_vob - ifo;
656 /* Never trust the BUP use a copy of the IFO */
657 snprintf(temppoint, sizeof (temppoint),
658 "%s/VIDEO_TS/VTS_%02i_0.IFO",
659 mountpoint, counter + 1);
661 if (stat(temppoint, &fileinfo) < 0) {
663 errmsg("calc: Can't stat %s\n", temppoint);
665 fprintf(stderr, "calc: Can't stat %s\n",
669 DVDFreeFileSetArrays(sector, title,
670 title_sets_array, sector_sets_array);
671 DVDFreeFileSet(title_set_info);
675 title_set_info->title_set[counter + 1].size_bup =
677 title_set_info->title_set[counter + 1].realsize_bup =
679 title_set_info->title_set[counter + 1].pad_bup =
680 bup - DVDFileSize(vts_ifo_file);
685 if (vts_menu_file != 0) {
686 DVDCloseFile(vts_menu_file);
689 if (vts_title_file != 0) {
690 DVDCloseFile(vts_title_file);
694 if (vts_ifo_file != 0) {
695 DVDCloseFile(vts_ifo_file);
704 DVDFreeFileSetArrays(sector, title, title_sets_array, sector_sets_array);
706 /* Close the VMG ifo file we got all the info we need */
713 /* Return the actuall info*/
714 return (title_set_info);
720 DVDGetFilePad(title_set_info_t *title_set_info, char *name)
727 title_a[0] = title_a[1] = title_a[2] = '\0';
728 vob_a[0] = vob_a[1] = '\0';
730 if (name[0] != 'V') {
733 if (memcmp(name, "VIDEO_TS", 8) == 0) {
734 if (strstr(name, ".IFO") != 0) {
735 return (title_set_info->title_set[0].pad_ifo);
736 } else if (strstr(name, ".VOB") != 0) {
737 return (title_set_info->title_set[0].pad_menu);
738 } else if (strstr(name, ".BUP") != 0) {
739 return (title_set_info->title_set[0].pad_bup);
743 } else if (memcmp(name, "VTS_", 4) == 0) {
744 title_a[0] = name[4];
745 title_a[1] = name[5];
749 title = atoi(title_a);
751 if (title > title_set_info->num_titles) {
754 if (strstr(name, ".IFO") != 0) {
755 return (title_set_info->title_set[title].pad_ifo);
756 } else if (strstr(name, ".BUP") != 0) {
757 return (title_set_info->title_set[title].pad_bup);
758 } else if (vob == 0) {
759 return (title_set_info->title_set[title].pad_menu);
760 } else if (vob == title_set_info->title_set[title].number_of_vob_files) {
761 return (title_set_info->title_set[title].pad_title);