1 /*
2  * dvdbackup - tool to rip DVDs from the command line
3  *
4  * Copyright (C) 2002  Olaf Beck <olaf_sc@yahoo.com>
5  * Copyright (C) 2008-2012  Benjamin Drung <benjamin.drung@gmail.com>
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include <config.h>
22 #include "dvdbackup.h"
23 
24 /* internationalisation */
25 #include "gettext.h"
26 #define _(String) gettext(String)
27 
28 /* C standard libraries */
29 #include <ctype.h>
30 #include <limits.h>
31 #include <stdint.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 
35 /* C POSIX library */
36 #include <fcntl.h>
37 #include <sys/stat.h>
38 #include <unistd.h>
39 
40 /* libdvdread */
41 #include <dvdread/dvd_reader.h>
42 #include <dvdread/ifo_read.h>
43 
44 
45 #define MAXNAME 256
46 
47 /**
48  * Buffer size in DVD logical blocks (2 KiB).
49  * Currently set to 1 MiB.
50  */
51 #define BUFFER_SIZE 512
52 
53 /**
54  * The maximum size of a VOB file is 1 GiB or 524288 in Video DVD logical block
55  * respectively.
56  */
57 #define MAX_VOB_SIZE 524288
58 
59 #define DVD_SEC_SIZ 2048
60 
61 /* Flag for verbose mode */
62 int verbose = 0;
63 int aspect;
64 int progress = 0;
65 char progressText[MAXNAME] = "n/a";
66 
67 /* Structs to keep title set information in */
68 
69 typedef struct {
70 	off_t size_ifo;
71 	off_t size_menu;
72 	int number_of_vob_files;
73 	off_t size_vob[10];
74 } title_set_t;
75 
76 typedef struct {
77 	int number_of_title_sets;
78 	title_set_t* title_set;
79 } title_set_info_t;
80 
81 
82 typedef struct {
83 	int title;
84 	int title_set;
85 	int vts_title;
86 	int chapters;
87 	int aspect_ratio;
88 	int angles;
89 	int audio_tracks;
90 	int audio_channels;
91 	int sub_pictures;
92 } titles_t;
93 
94 typedef struct {
95 	int main_title_set;
96 	int number_of_titles;
97 	titles_t* titles;
98 } titles_info_t;
99 
100 
101 static void bsort_max_to_min(int sector[], int title[], int size);
102 
103 
CheckSizeArray(const int size_array[],int reference,int target)104 static int CheckSizeArray(const int size_array[], int reference, int target) {
105 	if(size_array[target] && (size_array[reference]/size_array[target] == 1) &&
106 			((size_array[reference] * 2 - size_array[target])/ size_array[target] == 1) &&
107 			((size_array[reference]%size_array[target] * 3) < size_array[reference]) ) {
108 		/* We have a dual DVD with two feature films - now let's see if they have the same amount of chapters*/
109 		return(1);
110 	} else {
111 		return(0);
112 	}
113 }
114 
115 
CheckAudioSubChannels(int audio_audio_array[],int title_set_audio_array[],int subpicture_sub_array[],int title_set_sub_array[],int channels_channel_array[],int title_set_channel_array[],int reference,int candidate,int title_sets)116 static int CheckAudioSubChannels(int audio_audio_array[], int title_set_audio_array[],
117 		int subpicture_sub_array[], int title_set_sub_array[],
118 		int channels_channel_array[],int title_set_channel_array[],
119 		int reference, int candidate, int title_sets) {
120 
121 	int temp, i, found_audio, found_sub, found_channels;
122 
123 	found_audio=0;
124 	temp = audio_audio_array[reference];
125 	for (i=0 ; i < title_sets ; i++ ) {
126 		if ( audio_audio_array[i] < temp ) {
127 			break;
128 		}
129 		if ( candidate == title_set_audio_array[i] ) {
130 			found_audio=1;
131 			break;
132 		}
133 
134 	}
135 
136 	found_sub=0;
137 	temp = subpicture_sub_array[reference];
138 	for (i=0 ; i < title_sets ; i++ ) {
139 		if ( subpicture_sub_array[i] < temp ) {
140 			break;
141 		}
142 		if ( candidate == title_set_sub_array[i] ) {
143 			found_sub=1;
144 			break;
145 		}
146 
147 	}
148 
149 
150 	found_channels=0;
151 	temp = channels_channel_array[reference];
152 	for (i=0 ; i < title_sets ; i++ ) {
153 		if ( channels_channel_array[i] < temp ) {
154 			break;
155 		}
156 		if ( candidate == title_set_channel_array[i] ) {
157 			found_channels=1;
158 			break;
159 		}
160 
161 	}
162 
163 
164 	return(found_audio + found_sub + found_channels);
165 }
166 
167 
168 
169 
DVDWriteCells(dvd_reader_t * dvd,int cell_start_sector[],int cell_end_sector[],int length,int titles,title_set_info_t * title_set_info,titles_info_t * titles_info,char * targetdir,char * title_name)170 static int DVDWriteCells(dvd_reader_t * dvd, int cell_start_sector[],
171 		int cell_end_sector[], int length, int titles,
172 		title_set_info_t * title_set_info, titles_info_t * titles_info,
173 		char * targetdir,char * title_name) {
174 
175 	/* Loop variables */
176 	int i;
177 
178 	/* Vob control */
179 	int vob = 1;
180 
181 	/* Temp filename,dirname */
182 	char targetname[PATH_MAX];
183 
184 	/* Write buffer */
185 
186 	unsigned char * buffer=NULL;
187 
188 	/* File Handler */
189 	int streamout;
190 
191 	int size;
192 	int left;
193 
194 	int to_read;
195 	int have_read;
196 
197 	/* Offsets */
198 	int soffset;
199 
200 
201 	/* DVD handler */
202 	dvd_file_t* dvd_file = NULL;
203 
204 	int title_set;
205 
206 #ifdef DEBUG
207 	int number_of_vob_files;
208 
209 	fprintf(stderr,"DVDWriteCells: length is %d\n", length);
210 #endif
211 
212 
213 	title_set = titles_info->titles[titles - 1].title_set;
214 #ifdef DEBUG
215 	number_of_vob_files = title_set_info->title_set[title_set].number_of_vob_files;
216 	fprintf(stderr,"DVDWriteCells: title set is %d\n", title_set);
217 	fprintf(stderr,"DVDWriteCells: vob files are %d\n", number_of_vob_files);
218 #endif
219 
220 	/* Remove all old files silently if they exists */
221 
222 	for ( i = 0 ; i < 10 ; i++ ) {
223 		sprintf(targetname,"%s/%s/VIDEO_TS/VTS_%02i_%i.VOB",targetdir, title_name, title_set, i + 1);
224 #ifdef DEBUG
225 		fprintf(stderr,"DVDWriteCells: file is %s\n", targetname);
226 #endif
227 		unlink( targetname);
228 	}
229 
230 
231 #ifdef DEBUG
232 	for (i = 0; i < number_of_vob_files ; i++) {
233 		fprintf(stderr,"vob %i size: %lld\n", i + 1, title_set_info->title_set[title_set].size_vob[i]);
234 	}
235 #endif
236 
237 	/* Create VTS_XX_X.VOB */
238 	if (title_set == 0) {
239 		fprintf(stderr,_("Do not try to copy chapters from the VMG domain; there are none.\n"));
240 		return(1);
241 	} else {
242 		sprintf(targetname,"%s/%s/VIDEO_TS/VTS_%02i_%i.VOB",targetdir, title_name, title_set, vob);
243 	}
244 
245 #ifdef DEBUG
246 	fprintf(stderr,"DVDWriteCells: 1\n");
247 #endif
248 
249 	if ((buffer = (unsigned char *)malloc(BUFFER_SIZE * DVD_VIDEO_LB_LEN * sizeof(unsigned char))) == NULL) {
250 		fprintf(stderr, _("Out of memory copying %s\n"), targetname);
251 		return(1);
252 	}
253 
254 #ifdef DEBUG
255 	fprintf(stderr,"DVDWriteCells: 2\n");
256 #endif
257 
258 
259 	if ((streamout = open(targetname, O_WRONLY | O_CREAT | O_APPEND, 0666)) == -1) {
260 		fprintf(stderr, _("Error creating %s\n"), targetname);
261 		perror(PACKAGE);
262 		return(1);
263 	}
264 
265 #ifdef DEBUG
266 	fprintf(stderr,"DVDWriteCells: 3\n");
267 #endif
268 
269 
270 	if ((dvd_file = DVDOpenFile(dvd, title_set, DVD_READ_TITLE_VOBS))== 0) {
271 		fprintf(stderr, _("Failed opening TITLE VOB\n"));
272 		free(buffer);
273 		close(streamout);
274 		return(1);
275 	}
276 
277 	size = 0;
278 
279 	for (i=0; i<length; i++) {
280 		left = cell_end_sector[i] - cell_start_sector[i];
281 		soffset = cell_start_sector[i];
282 
283 		while(left > 0) {
284 			to_read = left;
285 			if (to_read + size > MAX_VOB_SIZE) {
286 				to_read = MAX_VOB_SIZE - size;
287 			}
288 			if (to_read > BUFFER_SIZE) {
289 				to_read = BUFFER_SIZE;
290 			}
291 
292 			if ((have_read = DVDReadBlocks(dvd_file,soffset, to_read, buffer)) < 0) {
293 				fprintf(stderr, _("Error reading MENU VOB: %d != %d\n"), have_read, to_read);
294 				free(buffer);
295 				DVDCloseFile(dvd_file);
296 				close(streamout);
297 				return(1);
298 			}
299 			if (have_read < to_read) {
300 				fprintf(stderr, _("DVDReadBlocks read %d blocks of %d blocks\n"), have_read, to_read);
301 			}
302 			if (write(streamout, buffer, have_read * DVD_VIDEO_LB_LEN) != have_read * DVD_VIDEO_LB_LEN) {
303 				fprintf(stderr, _("Error writing TITLE VOB\n"));
304 				free(buffer);
305 				close(streamout);
306 				return(1);
307 			}
308 #ifdef DEBUG
309 			fprintf(stderr,"Current soffset changed from %i to ",soffset);
310 #endif
311 			soffset = soffset + have_read;
312 #ifdef DEBUG
313 			fprintf(stderr,"%i\n",soffset);
314 #endif
315 			left = left - have_read;
316 			size = size + have_read;
317 			if ((size >= MAX_VOB_SIZE) && (left > 0)) {
318 #ifdef DEBUG
319 				fprintf(stderr,"size: %i, MAX_VOB_SIZE: %i\n ",size, MAX_VOB_SIZE);
320 #endif
321 				close(streamout);
322 				vob = vob + 1;
323 				size = 0;
324 				sprintf(targetname,"%s/%s/VIDEO_TS/VTS_%02i_%i.VOB",targetdir, title_name, title_set, vob);
325 				if ((streamout = open(targetname, O_WRONLY | O_CREAT | O_APPEND, 0666)) == -1) {
326 					fprintf(stderr, _("Error creating %s\n"), targetname);
327 					perror(PACKAGE);
328 					return(1);
329 				}
330 			}
331 		}
332 	}
333 
334 	DVDCloseFile(dvd_file);
335 	free(buffer);
336 	close(streamout);
337 
338 	return(0);
339 }
340 
341 
342 
FreeSortArrays(int chapter_chapter_array[],int title_set_chapter_array[],int angle_angle_array[],int title_set_angle_array[],int subpicture_sub_array[],int title_set_sub_array[],int audio_audio_array[],int title_set_audio_array[],int size_size_array[],int title_set_size_array[],int channels_channel_array[],int title_set_channel_array[])343 static void FreeSortArrays( int chapter_chapter_array[], int title_set_chapter_array[],
344 		int angle_angle_array[], int title_set_angle_array[],
345 		int subpicture_sub_array[], int title_set_sub_array[],
346 		int audio_audio_array[], int title_set_audio_array[],
347 		int size_size_array[], int title_set_size_array[],
348 		int channels_channel_array[], int title_set_channel_array[]) {
349 
350 
351 	free(chapter_chapter_array);
352 	free(title_set_chapter_array);
353 
354 	free(angle_angle_array);
355 	free(title_set_angle_array);
356 
357 	free(subpicture_sub_array);
358 	free(title_set_sub_array);
359 
360 	free(audio_audio_array);
361 	free(title_set_audio_array);
362 
363 	free(size_size_array);
364 	free(title_set_size_array);
365 
366 	free(channels_channel_array);
367 	free(title_set_channel_array);
368 }
369 
370 
DVDGetInfo(dvd_reader_t * _dvd)371 static titles_info_t * DVDGetInfo(dvd_reader_t * _dvd) {
372 
373 	/* title interation */
374 	int counter, i, f;
375 
376 	/* Our guess */
377 	int candidate;
378 	int multi = 0;
379 	int dual = 0;
380 
381 
382 	int titles;
383 	int title_sets;
384 
385 	/* Arrays for chapter, angle, subpicture, audio, size, aspect, channels - file_set relationship */
386 
387 	/* Size == number_of_titles */
388 	int * chapter_chapter_array;
389 	int * title_set_chapter_array;
390 
391 	int * angle_angle_array;
392 	int * title_set_angle_array;
393 
394 	/* Size == number_of_title_sets */
395 
396 	int * subpicture_sub_array;
397 	int * title_set_sub_array;
398 
399 	int * audio_audio_array;
400 	int * title_set_audio_array;
401 
402 	int * size_size_array;
403 	int * title_set_size_array;
404 
405 	int * channels_channel_array;
406 	int * title_set_channel_array;
407 
408 	/* Temp helpers */
409 	int channels;
410 	int found;
411 	int chapters_1;
412 	int chapters_2;
413 	int found_chapter;
414 	int number_of_multi;
415 
416 
417 	/* DVD handlers */
418 	ifo_handle_t* vmg_ifo = NULL;
419 	dvd_file_t* vts_title_file = NULL;
420 
421 	titles_info_t* titles_info = NULL;
422 
423 	/* Open main info file */
424 	vmg_ifo = ifoOpen( _dvd, 0 );
425 	if(!vmg_ifo) {
426 		fprintf( stderr, _("Cannot open VMG info.\n"));
427 		return (0);
428 	}
429 
430 	titles = vmg_ifo->tt_srpt->nr_of_srpts;
431 	title_sets = vmg_ifo->vmgi_mat->vmg_nr_of_title_sets;
432 
433 	if ((vmg_ifo->tt_srpt == 0) || (vmg_ifo->vts_atrt == 0)) {
434 		ifoClose(vmg_ifo);
435 		return(0);
436 	}
437 
438 
439 	if((titles_info = (titles_info_t *)malloc(sizeof(titles_info_t))) == NULL) {
440 		fprintf(stderr, _("Out of memory creating titles info structure\n"));
441 		return NULL;
442 	}
443 
444 	titles_info->titles = (titles_t *)malloc((titles)* sizeof(titles_t));
445 	titles_info->number_of_titles = titles;
446 
447 
448 	chapter_chapter_array = malloc(titles * sizeof(int));
449 	title_set_chapter_array = malloc(titles * sizeof(int));
450 
451 	/*currently not used in the guessing */
452 	angle_angle_array = malloc(titles * sizeof(int));
453 	title_set_angle_array = malloc(titles * sizeof(int));
454 
455 
456 	subpicture_sub_array = malloc(title_sets * sizeof(int));
457 	title_set_sub_array = malloc(title_sets * sizeof(int));
458 
459 	audio_audio_array = malloc(title_sets * sizeof(int));
460 	title_set_audio_array = malloc(title_sets * sizeof(int));
461 
462 	size_size_array = malloc(title_sets * sizeof(int));
463 	title_set_size_array = malloc(title_sets * sizeof(int));
464 
465 	channels_channel_array = malloc(title_sets * sizeof(int));
466 	title_set_channel_array = malloc(title_sets * sizeof(int));
467 
468 	/* Check mallocs */
469 	if(!titles_info->titles || !chapter_chapter_array || !title_set_chapter_array ||
470 			!angle_angle_array || !title_set_angle_array || !subpicture_sub_array ||
471 			!title_set_sub_array || !audio_audio_array || !title_set_audio_array ||
472 			!size_size_array || !title_set_size_array || !channels_channel_array ||
473 			!title_set_channel_array) {
474 		fprintf(stderr, _("Out of memory creating arrays for titles info\n"));
475 		free(titles_info);
476 		FreeSortArrays( chapter_chapter_array, title_set_chapter_array,
477 						angle_angle_array, title_set_angle_array,
478 						subpicture_sub_array, title_set_sub_array,
479 						audio_audio_array, title_set_audio_array,
480 						size_size_array, title_set_size_array,
481 						channels_channel_array, title_set_channel_array);
482 		return NULL;
483 	}
484 
485 	/* Interate over the titles nr_of_srpts */
486 	for(counter = 0; counter < titles; counter++) {
487 		/* For titles_info */
488 		titles_info->titles[counter].title = counter + 1;
489 		titles_info->titles[counter].title_set = vmg_ifo->tt_srpt->title[counter].title_set_nr;
490 		titles_info->titles[counter].vts_title = vmg_ifo->tt_srpt->title[counter].vts_ttn;
491 		titles_info->titles[counter].chapters = vmg_ifo->tt_srpt->title[counter].nr_of_ptts;
492 		titles_info->titles[counter].angles = vmg_ifo->tt_srpt->title[counter].nr_of_angles;
493 
494 		/* For main title*/
495 		chapter_chapter_array[counter] = vmg_ifo->tt_srpt->title[counter].nr_of_ptts;
496 		title_set_chapter_array[counter] = vmg_ifo->tt_srpt->title[counter].title_set_nr;
497 		angle_angle_array[counter] = vmg_ifo->tt_srpt->title[counter].nr_of_angles;
498 		title_set_angle_array[counter] = vmg_ifo->tt_srpt->title[counter].title_set_nr;
499 	}
500 
501 	/* Interate over vmg_nr_of_title_sets */
502 
503 	for(counter = 0; counter < title_sets; counter++) {
504 
505 		/* Picture*/
506 		subpicture_sub_array[counter] = vmg_ifo->vts_atrt->vts[counter].nr_of_vtstt_subp_streams;
507 		title_set_sub_array[counter] = counter + 1;
508 
509 
510 		/* Audio */
511 		audio_audio_array[counter] = vmg_ifo->vts_atrt->vts[counter].nr_of_vtstt_audio_streams;
512 		title_set_audio_array[counter] = counter + 1;
513 
514 		channels=0;
515 		for(i = 0; i < audio_audio_array[counter]; i++) {
516 			if ( channels < vmg_ifo->vts_atrt->vts[counter].vtstt_audio_attr[i].channels + 1) {
517 				channels = vmg_ifo->vts_atrt->vts[counter].vtstt_audio_attr[i].channels + 1;
518 			}
519 
520 		}
521 		channels_channel_array[counter] = channels;
522 		title_set_channel_array[counter] = counter + 1;
523 
524 		/* For titles_info */
525 		for (f=0; f < titles_info->number_of_titles ; f++ ) {
526 			if ( titles_info->titles[f].title_set == counter + 1 ) {
527 				titles_info->titles[f].aspect_ratio = vmg_ifo->vts_atrt->vts[counter].vtstt_vobs_video_attr.display_aspect_ratio;
528 				titles_info->titles[f].sub_pictures = vmg_ifo->vts_atrt->vts[counter].nr_of_vtstt_subp_streams;
529 				titles_info->titles[f].audio_tracks = vmg_ifo->vts_atrt->vts[counter].nr_of_vtstt_audio_streams;
530 				titles_info->titles[f].audio_channels = channels;
531 			}
532 		}
533 
534 	}
535 
536 
537 
538 
539 	for (counter=0; counter < title_sets; counter++ ) {
540 
541 		vts_title_file = DVDOpenFile(_dvd, counter + 1, DVD_READ_TITLE_VOBS);
542 
543 		if(vts_title_file != 0) {
544 			size_size_array[counter] = DVDFileSize(vts_title_file);
545 			DVDCloseFile(vts_title_file);
546 		} else {
547 			size_size_array[counter] = 0;
548 		}
549 
550 		title_set_size_array[counter] = counter + 1;
551 
552 
553 	}
554 
555 
556 	/* Sort all arrays max to min */
557 
558 	bsort_max_to_min(chapter_chapter_array, title_set_chapter_array, titles);
559 	bsort_max_to_min(angle_angle_array, title_set_angle_array, titles);
560 	bsort_max_to_min(subpicture_sub_array, title_set_sub_array, title_sets);
561 	bsort_max_to_min(audio_audio_array, title_set_audio_array, title_sets);
562 	bsort_max_to_min(size_size_array, title_set_size_array, title_sets);
563 	bsort_max_to_min(channels_channel_array, title_set_channel_array, title_sets);
564 
565 
566 	/* Check if the second biggest one actually can be a feature title */
567 	/* Here we will take do biggest/second and if that is bigger than one it's not a feauture title */
568 	/* Now this is simply not enough since we have to check that the diff between the two of them is small enough
569 	 to consider the second one a feature title we are doing two checks (biggest + biggest - second) /second == 1
570 	 and biggest%second * 3 < biggest */
571 
572 	if ( title_sets > 1 && CheckSizeArray(size_size_array, 0, 1) == 1 ) {
573 		/* We have a dual DVD with two feature films - now let's see if they have the same amount of chapters*/
574 
575 		chapters_1 = 0;
576 		for (i=0 ; i < titles ; i++ ) {
577 			if (titles_info->titles[i].title_set == title_set_size_array[0] ) {
578 				if ( chapters_1 < titles_info->titles[i].chapters){
579 					chapters_1 = titles_info->titles[i].chapters;
580 				}
581 			}
582 		}
583 
584 		chapters_2 = 0;
585 		for (i=0 ; i < titles ; i++ ) {
586 			if (titles_info->titles[i].title_set == title_set_size_array[1] ) {
587 				if ( chapters_2 < titles_info->titles[i].chapters){
588 					chapters_2 = titles_info->titles[i].chapters;
589 				}
590 			}
591 		}
592 
593 		if(vmg_ifo->vts_atrt->vts[title_set_size_array[0] - 1].vtstt_vobs_video_attr.display_aspect_ratio ==
594 			vmg_ifo->vts_atrt->vts[title_set_size_array[1] - 1].vtstt_vobs_video_attr.display_aspect_ratio) {
595 			/* In this case it's most likely so that we have a dual film but with different context
596 			They are with in the same size range and have the same aspect ratio
597 			I would guess that such a case is e.g. a DVD containing several episodes of a TV serie*/
598 			candidate = title_set_size_array[0];
599 			multi = 1;
600 		} else if ( chapters_1 == chapters_2 && vmg_ifo->vts_atrt->vts[title_set_size_array[0] - 1].vtstt_vobs_video_attr.display_aspect_ratio !=
601 			vmg_ifo->vts_atrt->vts[title_set_size_array[1] - 1].vtstt_vobs_video_attr.display_aspect_ratio){
602 			/* In this case we have (guess only) the same context - they have the same number of chapters but different aspect ratio and are in the same size range*/
603 			if ( vmg_ifo->vts_atrt->vts[title_set_size_array[0] - 1].vtstt_vobs_video_attr.display_aspect_ratio == aspect) {
604 				candidate = title_set_size_array[0];
605 			} else if ( vmg_ifo->vts_atrt->vts[title_set_size_array[1] - 1].vtstt_vobs_video_attr.display_aspect_ratio == aspect) {
606 				candidate = title_set_size_array[1];
607 			} else {
608 				/* Okay we didn't have the prefered aspect ratio - just make the biggest one a candidate */
609 				/* please send report if this happens*/
610 				fprintf(stderr, _("You have encountered a very special DVD; please send a bug report along with all IFO files from this title\n"));
611 				candidate = title_set_size_array[0];
612 			}
613 			dual = 1;
614 		} else {
615 			/* Can this case ever happen? */
616 			candidate = title_set_size_array[0];
617 		}
618 	} else {
619 		candidate = title_set_size_array[0];
620 	}
621 
622 
623 	/* Lets start checking audio,sub pictures and channels my guess is namly that a special suburb will put titles with a lot of
624 	 chapters just to make our backup hard */
625 
626 
627 	found = CheckAudioSubChannels(audio_audio_array, title_set_audio_array,
628 			subpicture_sub_array, title_set_sub_array,
629 			channels_channel_array, title_set_channel_array,
630 			0 , candidate, title_sets);
631 
632 
633 	/* Now let's see if we can find our candidate among the top most chapters */
634 	found_chapter=6;
635 	for (i=0 ; (i < titles) && (i < 4) ; i++ ) {
636 		if ( candidate == title_set_chapter_array[i] ) {
637 			found_chapter=i+1;
638 			break;
639 		}
640 	}
641 
642 	/* Close the VMG ifo file we got all the info we need */
643 	ifoClose(vmg_ifo);
644 
645 
646 	if (((found == 3) && (found_chapter == 1) && (dual == 0) && (multi == 0)) || ((found == 3) && (found_chapter < 3 ) && (dual == 1))) {
647 
648 		FreeSortArrays( chapter_chapter_array, title_set_chapter_array,
649 				angle_angle_array, title_set_angle_array,
650 				subpicture_sub_array, title_set_sub_array,
651 				audio_audio_array, title_set_audio_array,
652 				size_size_array, title_set_size_array,
653 				channels_channel_array, title_set_channel_array);
654 		titles_info->main_title_set = candidate;
655 		return(titles_info);
656 
657 	}
658 
659 	if (multi == 1) {
660 		for (i=0 ; i < title_sets ; ++i) {
661 			if (CheckSizeArray(size_size_array, 0, i + 1) == 0) {
662 				break;
663 			}
664 		}
665 		number_of_multi = i;
666 		for (i = 0; i < number_of_multi; i++ ) {
667 			if (title_set_chapter_array[0] == i + 1) {
668 				candidate = title_set_chapter_array[0];
669 			}
670 		}
671 
672 		found = CheckAudioSubChannels(audio_audio_array, title_set_audio_array,
673 				subpicture_sub_array, title_set_sub_array,
674 				channels_channel_array, title_set_channel_array,
675 				0 , candidate, title_sets);
676 
677 		if (found == 3) {
678 			FreeSortArrays( chapter_chapter_array, title_set_chapter_array,
679 					angle_angle_array, title_set_angle_array,
680 					subpicture_sub_array, title_set_sub_array,
681 					audio_audio_array, title_set_audio_array,
682 					size_size_array, title_set_size_array,
683 					channels_channel_array, title_set_channel_array);
684 			titles_info->main_title_set = candidate;
685 			return(titles_info);
686 		}
687 	}
688 
689 	/* We have now come to that state that we more or less have given up :( giving you a good guess of the main feature film*/
690 	/*No matter what we will more or less only return the biggest VOB*/
691 	/* Lets see if we can find our biggest one - then we return that one */
692 	candidate = title_set_size_array[0];
693 
694 	found = CheckAudioSubChannels(audio_audio_array, title_set_audio_array,
695 			subpicture_sub_array, title_set_sub_array,
696 			channels_channel_array, title_set_channel_array,
697 			0 , candidate, title_sets);
698 
699 	/* Now let's see if we can find our candidate among the top most chapters */
700 
701 	found_chapter=5;
702 	for (i=0 ; (i < titles) && (i < 4) ; i++ ) {
703 		if ( candidate == title_set_chapter_array[i] ) {
704 			found_chapter=i+1;
705 			break;
706 		}
707 
708 	}
709 
710 	/* Here we take chapters in to consideration*/
711 	if (found == 3) {
712 		FreeSortArrays( chapter_chapter_array, title_set_chapter_array,
713 				angle_angle_array, title_set_angle_array,
714 				subpicture_sub_array, title_set_sub_array,
715 				audio_audio_array, title_set_audio_array,
716 				size_size_array, title_set_size_array,
717 				channels_channel_array, title_set_channel_array);
718 		titles_info->main_title_set = candidate;
719 		return(titles_info);
720 	}
721 
722 	/* Here we do but we lower the treshold for audio, sub and channels */
723 
724 	if ((found > 1 ) && (found_chapter <= 4)) {
725 		FreeSortArrays( chapter_chapter_array, title_set_chapter_array,
726 				angle_angle_array, title_set_angle_array,
727 				subpicture_sub_array, title_set_sub_array,
728 				audio_audio_array, title_set_audio_array,
729 				size_size_array, title_set_size_array,
730 				channels_channel_array, title_set_channel_array);
731 		titles_info->main_title_set = candidate;
732 		return(titles_info);
733 
734 		/* return it */
735 	} else {
736 		/* Here we give up and just return the biggest one :(*/
737 		/* Just return the biggest badest one*/
738 		FreeSortArrays( chapter_chapter_array, title_set_chapter_array,
739 				angle_angle_array, title_set_angle_array,
740 				subpicture_sub_array, title_set_sub_array,
741 				audio_audio_array, title_set_audio_array,
742 				size_size_array, title_set_size_array,
743 				channels_channel_array, title_set_channel_array);
744 		titles_info->main_title_set = candidate;
745 		return(titles_info);
746 	}
747 
748 
749 	/* Some radom thoughts about DVD guessing */
750 	/* We will now gather as much data about the DVD-Video as we can and
751 	then make a educated guess which one is the main feature film of it*/
752 
753 
754 	/* Make a tripple array with chapters, angles and title sets
755 	 - sort out dual title sets with a low number of chapters. Tradtionaly
756 	 the title set with most chapters is the main film. Number of angles is
757 	 keept as a reference point of low value*/
758 
759 	/* Make a dual array with number of audio streams, sub picture streams
760 	 and title sets. Tradtionaly the main film has many audio streams
761 	 since it's supposed be synchronised e.g. a English film synchronised/dubbed
762 	 in German. We are also keeping track of sub titles since it's also indication
763 	 of the main film*/
764 
765 	/* Which title set is the biggest one - dual array with title sets and size
766 	 The biggest one is usally the main film*/
767 
768 	/* Which title set is belonging to title 1 and how many chapters has it. Once
769 	 again tradtionaly title one is belonging to the main film*/
770 
771 	/* Yes a lot of rant - but it helps me think - some sketch on paper or in the mind
772 	 I sketch in the comments - beside it will help you understand the code*/
773 
774 	/* Okay let's see if the biggest one has most chapters, it also has more subtitles
775 	 and audio tracks than the second one and it's title one.
776 	 Done it must be the main film
777 
778 	 Hmm the biggest one doesn't have the most chapters?
779 
780 	 See if the second one has the same amount of chapters and is the biggest one
781 	 If so we probably have a 4:3 and 16:9 versions of film on the same disk
782 
783 	 Now we fetch the 16:9 by default unless the forced to do 4:3
784 	 First check which one is which.
785 	 If the 16:9 is the biggest one and has the same or more subtitle, audio streams
786 	 then we are happy unless we are in force 4:3 mode :(
787 	 The same goes in reverse if we are in force 4:3 mode
788 
789 
790 	 Hmm, in force 4:3 mode - now we check how much smaller than the biggest one it is
791 	 (or the reverse if we are in 16:9 mode)
792 
793 	 Generally a reverse division should render in 1 and with a small modulo - like wise
794 	 a normal modulo should give us a high modulo
795 
796 	 If we get more than one it's of cource a fake however if we get just one we still need to check
797 	 if we subtract the smaller one from the bigger one we should end up with a small number - hence we
798 	 need to multiply it more than 4 times to get it bigger than the biggest one. Now we know that the
799 	 two biggest once are really big and possibly carry the same film in differnet formats.
800 
801 	 We will now return the prefered one either 16:9 or 4:3 but we will first check that the one
802 	 we return at lest has two or more audio tracks. We don't want it if the other one has a lot
803 	 more sound (we may end up with a film that only has 2ch Dolby Digital so we want to check for
804 	 6ch DTS or Dolby Digital. If the prefered one doesn't have those features but the other once has
805 	 we will return the other one.
806 	 */
807 
808 }
809 
810 
DVDCopyBlocks(dvd_file_t * dvd_file,int destination,int offset,int size,char * filename,read_error_strategy_t errorstrat)811 static int DVDCopyBlocks(dvd_file_t* dvd_file, int destination, int offset, int size, char* filename, read_error_strategy_t errorstrat) {
812 	int i;
813 
814 	/* all sizes are in DVD logical blocks */
815 	int remaining = size;
816 	int total = size; // total size in blocks
817 	float totalMiB = (float)(total) / 512.0f; // total size in [MiB]
818 	int to_read = BUFFER_SIZE;
819 	int act_read; /* number of buffers actually read */
820 
821 	/* Write buffer */
822 	unsigned char buffer[BUFFER_SIZE * DVD_VIDEO_LB_LEN];
823 	unsigned char buffer_zero[BUFFER_SIZE * DVD_VIDEO_LB_LEN];
824 
825 	for(i = 0; i < BUFFER_SIZE * DVD_VIDEO_LB_LEN; i++) {
826 		buffer_zero[i] = '\0';
827 	}
828 
829 	while( remaining > 0 ) {
830 
831 		if (to_read > remaining) {
832 			to_read = remaining;
833 		}
834 
835 		/* Reading blocks */
836 		act_read = DVDReadBlocks(dvd_file, offset, to_read, buffer);
837 
838 		if(act_read != to_read) {
839 			if(progress) {
840 				fprintf(stdout, "\n");
841 			}
842 			if(act_read >= 0) {
843 				fprintf(stderr, _("Error reading %s at block %d\n"), filename, offset+act_read);
844 			} else {
845 				fprintf(stderr, _("Error reading %s at block %d, read error returned\n"), filename, offset);
846 			}
847 		}
848 
849 		if(act_read > 0) {
850 			/* Writing blocks */
851 			if(write(destination, buffer, act_read * DVD_VIDEO_LB_LEN) != act_read * DVD_VIDEO_LB_LEN) {
852 				if(progress) {
853 					fprintf(stdout, "\n");
854 				}
855 				fprintf(stderr, _("Error writing %s.\n"), filename);
856 				return(1);
857 			}
858 
859 			offset += act_read;
860 			remaining -= act_read;
861 		}
862 
863 		if(act_read != to_read) {
864 			int numBlanks = 0;
865 
866 			if(progress) {
867 				fprintf(stdout, "\n");
868 			}
869 
870 			if (act_read < 0) {
871 				act_read = 0;
872 			}
873 
874 			switch (errorstrat) {
875 			case STRATEGY_ABORT:
876 				fprintf(stderr, _("aborting\n"));
877 				return 1;
878 
879 			case STRATEGY_SKIP_BLOCK:
880 				numBlanks = 1;
881 				fprintf(stderr, _("padding single block\n"));
882 				break;
883 
884 			case STRATEGY_SKIP_MULTIBLOCK:
885 				numBlanks = to_read - act_read;
886 				fprintf(stderr, _("padding %d blocks\n"), numBlanks);
887 				break;
888 			}
889 
890 			if (write(destination, buffer_zero, numBlanks * DVD_VIDEO_LB_LEN) != numBlanks * DVD_VIDEO_LB_LEN) {
891 				fprintf(stderr, _("Error writing %s (padding)\n"), filename);
892 				return 1;
893 			}
894 
895 			/* pretend we read what we padded */
896 			offset += numBlanks;
897 			remaining -= numBlanks;
898 		}
899 
900 		if(progress) {
901 			int done = total - remaining; // blocks done
902 			if(remaining < BUFFER_SIZE || (done % BUFFER_SIZE) == 0) { // don't print too often
903 				float doneMiB = (float)(done) / 512.0f; // [MiB] done
904 				fprintf(stdout, "\r");
905 				fprintf(stdout, _("Copying %s: %.0f%% done (%.0f/%.0f MiB)"),
906 						progressText, doneMiB / totalMiB * 100.0f, doneMiB, totalMiB);
907 				fflush(stdout);
908 			}
909 		}
910 
911 	}
912 
913 	if(progress) {
914 		fprintf(stdout, "\n");
915 	}
916 
917 	return 0;
918 }
919 
920 
921 
DVDCopyTitleVobX(dvd_reader_t * dvd,title_set_info_t * title_set_info,int title_set,int vob,char * targetdir,char * title_name,read_error_strategy_t errorstrat)922 static int DVDCopyTitleVobX(dvd_reader_t * dvd, title_set_info_t * title_set_info, int title_set, int vob, char * targetdir,char * title_name, read_error_strategy_t errorstrat) {
923 
924 	/* Loop variable */
925 	int i;
926 
927 	/* Temp filename,dirname */
928 	char filename[PATH_MAX] = "VIDEO_TS.VOB";
929 	char targetname[PATH_MAX];
930 	struct stat fileinfo;
931 
932 	/* File Handler */
933 	int streamout;
934 
935 	int size;
936 
937 	int offset = 0;
938 	int tsize;
939 
940 	/* DVD handler */
941 	dvd_file_t* dvd_file=NULL;
942 
943 	/* Return value */
944 	int result;
945 
946 	/* create filename VIDEO_TS.VOB or VTS_XX_X.VOB */
947 	if(title_set > 0) {
948 		sprintf(filename, "VTS_%02i_%i.VOB", title_set, vob);
949 	}
950 
951 	if (title_set_info->number_of_title_sets + 1 < title_set) {
952 		fprintf(stderr,_("Failed num title test\n"));
953 		return(1);
954 	}
955 
956 	if (title_set_info->title_set[title_set].number_of_vob_files < vob ) {
957 		fprintf(stderr,_("Failed vob test\n"));
958 		return(1);
959 	}
960 
961 	if (title_set_info->title_set[title_set].size_vob[0] == 0 ) {
962 		fprintf(stderr,_("Failed vob 1 size test\n"));
963 		return(0);
964 	} else if (title_set_info->title_set[title_set].size_vob[vob - 1] == 0 ) {
965 		fprintf(stderr,_("Failed vob %d test\n"), vob);
966 		return(0);
967 	} else {
968 		size = title_set_info->title_set[title_set].size_vob[vob - 1]/DVD_VIDEO_LB_LEN;
969 		if (title_set_info->title_set[title_set].size_vob[vob - 1]%DVD_VIDEO_LB_LEN != 0) {
970 			fprintf(stderr, _("The Title VOB number %d of title set %d does not have a valid DVD size\n"), vob, title_set);
971 			return(1);
972 		}
973 	}
974 #ifdef DEBUG
975 	fprintf(stderr,"After we check the vob it self %d\n", vob);
976 #endif
977 
978 	/* Create VTS_XX_X.VOB */
979 	if (title_set == 0) {
980 		fprintf(stderr,_("Do not try to copy a Title VOB from the VMG domain; there are none.\n"));
981 		return(1);
982 	} else {
983 		sprintf(targetname,"%s/%s/VIDEO_TS/VTS_%02i_%i.VOB",targetdir, title_name, title_set, vob);
984 	}
985 
986 
987 
988 	/* Now figure out the offset we will start at also check that the previus files are of valid DVD size */
989 	for ( i = 0; i < vob - 1; i++ ) {
990 		tsize = title_set_info->title_set[title_set].size_vob[i];
991 		if (tsize%DVD_VIDEO_LB_LEN != 0) {
992 			fprintf(stderr, _("The Title VOB number %d of title set %d does not have a valid DVD size\n"), i + 1, title_set);
993 			return(1);
994 		} else {
995 			offset = offset + tsize/DVD_VIDEO_LB_LEN;
996 		}
997 	}
998 #ifdef DEBUG
999 	fprintf(stderr,"The offset for vob %d is %d\n", vob, offset);
1000 #endif
1001 
1002 
1003 	if (stat(targetname, &fileinfo) == 0) {
1004 		/* TRANSLATORS: The sentence starts with "The title file %s exists[...]" */
1005 		fprintf(stderr, _("The %s %s exists; will try to overwrite it.\n"), _("title file"), targetname);
1006 		if (! S_ISREG(fileinfo.st_mode)) {
1007 			/* TRANSLATORS: The sentence starts with "The title file %s is not valid[...]" */
1008 			fprintf(stderr,_("The %s %s is not valid, it may be a directory.\n"), _("title file"), targetname);
1009 			return(1);
1010 		} else {
1011 			if ((streamout = open(targetname, O_WRONLY | O_TRUNC, 0666)) == -1) {
1012 				fprintf(stderr, _("Error opening %s\n"), targetname);
1013 				perror(PACKAGE);
1014 				return(1);
1015 			}
1016 		}
1017 	} else {
1018 		if ((streamout = open(targetname, O_WRONLY | O_CREAT, 0666)) == -1) {
1019 			fprintf(stderr, _("Error creating %s\n"), targetname);
1020 			perror(PACKAGE);
1021 			return(1);
1022 		}
1023 	}
1024 
1025 	if ((dvd_file = DVDOpenFile(dvd, title_set, DVD_READ_TITLE_VOBS))== 0) {
1026 		fprintf(stderr, _("Failed opening TITLE VOB\n"));
1027 		close(streamout);
1028 		return(1);
1029 	}
1030 
1031 	result = DVDCopyBlocks(dvd_file, streamout, offset, size, filename, errorstrat);
1032 
1033 	DVDCloseFile(dvd_file);
1034 	close(streamout);
1035 	return result;
1036 }
1037 
1038 
DVDCopyMenu(dvd_reader_t * dvd,title_set_info_t * title_set_info,int title_set,char * targetdir,char * title_name,read_error_strategy_t errorstrat)1039 static int DVDCopyMenu(dvd_reader_t * dvd, title_set_info_t * title_set_info, int title_set, char * targetdir,char * title_name, read_error_strategy_t errorstrat) {
1040 
1041 	/* Temp filename,dirname */
1042 	char filename[PATH_MAX] = "VIDEO_TS.VOB";
1043 	char targetname[PATH_MAX];
1044 	struct stat fileinfo;
1045 
1046 	/* File Handler */
1047 	int streamout;
1048 
1049 	int size;
1050 
1051 	/* return value */
1052 	int result;
1053 
1054 	/* DVD handler */
1055 	dvd_file_t* dvd_file = NULL;
1056 
1057 	/* create filename VIDEO_TS.VOB or VTS_XX_0.VOB */
1058 	if(title_set > 0) {
1059 		sprintf(filename, "VTS_%02i_0.VOB", title_set);
1060 	}
1061 
1062 	if (title_set_info->number_of_title_sets + 1 < title_set) {
1063 		return(1);
1064 	}
1065 
1066 	if (title_set_info->title_set[title_set].size_menu == 0 ) {
1067 		return(0);
1068 	} else {
1069 		size = title_set_info->title_set[title_set].size_menu/DVD_VIDEO_LB_LEN;
1070 		if (title_set_info->title_set[title_set].size_menu%DVD_VIDEO_LB_LEN != 0) {
1071 			fprintf(stderr, _("Warning: The Menu VOB of title set %d (%s) does not have a valid DVD size.\n"), title_set, filename);
1072 		}
1073 	}
1074 
1075 	if ((dvd_file = DVDOpenFile(dvd, title_set, DVD_READ_MENU_VOBS))== 0) {
1076 		fprintf(stderr, _("Failed opening %s\n"), filename);
1077 		return(1);
1078 	}
1079 
1080 	/* Create VIDEO_TS.VOB or VTS_XX_0.VOB */
1081 	sprintf(targetname,"%s/%s/VIDEO_TS/%s",targetdir, title_name, filename);
1082 
1083 	if (stat(targetname, &fileinfo) == 0) {
1084 		/* TRANSLATORS: The sentence starts with "The menu file %s exists[...]" */
1085 		fprintf(stderr, _("The %s %s exists; will try to overwrite it.\n"), _("menu file"), targetname);
1086 		if (! S_ISREG(fileinfo.st_mode)) {
1087 			/* TRANSLATORS: The sentence starts with "The menu file %s is not valid[...]" */
1088 			fprintf(stderr,_("The %s %s is not valid, it may be a directory.\n"), _("menu file"), targetname);
1089 			DVDCloseFile(dvd_file);
1090 			return(1);
1091 		} else {
1092 			if ((streamout = open(targetname, O_WRONLY | O_TRUNC, 0666)) == -1) {
1093 				fprintf(stderr, _("Error opening %s\n"), targetname);
1094 				perror(PACKAGE);
1095 				DVDCloseFile(dvd_file);
1096 				return(1);
1097 			}
1098 		}
1099 	} else {
1100 		if ((streamout = open(targetname, O_WRONLY | O_CREAT, 0666)) == -1) {
1101 			fprintf(stderr, _("Error creating %s\n"), targetname);
1102 			perror(PACKAGE);
1103 			DVDCloseFile(dvd_file);
1104 			return(1);
1105 		}
1106 	}
1107 
1108 	if(progress) {
1109 		strncpy(progressText, _("menu"), MAXNAME);
1110 	}
1111 
1112 	result = DVDCopyBlocks(dvd_file, streamout, 0, size, filename, errorstrat);
1113 
1114 	DVDCloseFile(dvd_file);
1115 	close(streamout);
1116 	return result;
1117 
1118 }
1119 
1120 
DVDCopyIfoBup(dvd_reader_t * dvd,title_set_info_t * title_set_info,int title_set,char * targetdir,char * title_name)1121 static int DVDCopyIfoBup(dvd_reader_t* dvd, title_set_info_t* title_set_info, int title_set, char* targetdir, char* title_name) {
1122 	/* Temp filename, dirname */
1123 	char targetname_ifo[PATH_MAX], targetname_bup[PATH_MAX];
1124 	struct stat fileinfo;
1125 
1126 	/* Write buffer */
1127 	unsigned char* buffer = NULL;
1128 
1129 	/* File Handler */
1130 	int streamout_ifo = -1, streamout_bup = -1;
1131 
1132 	int size;
1133 
1134 	/* DVD handler */
1135 	dvd_file_t* ifo_file = NULL;
1136 
1137 
1138 	if (title_set_info->number_of_title_sets + 1 < title_set) {
1139 		return(1);
1140 	}
1141 
1142 	if (title_set_info->title_set[title_set].size_ifo == 0 ) {
1143 		return(0);
1144 	} else {
1145 		if (title_set_info->title_set[title_set].size_ifo%DVD_VIDEO_LB_LEN != 0) {
1146 			fprintf(stderr, _("The IFO of title set %d does not have a valid DVD size\n"), title_set);
1147 			return(1);
1148 		}
1149 	}
1150 
1151 	/* Create VIDEO_TS.IFO or VTS_XX_0.IFO */
1152 
1153 	if (title_set == 0) {
1154 		sprintf(targetname_ifo,"%s/%s/VIDEO_TS/VIDEO_TS.IFO",targetdir, title_name);
1155 		sprintf(targetname_bup,"%s/%s/VIDEO_TS/VIDEO_TS.BUP",targetdir, title_name);
1156 	} else {
1157 		sprintf(targetname_ifo,"%s/%s/VIDEO_TS/VTS_%02i_0.IFO",targetdir, title_name, title_set);
1158 		sprintf(targetname_bup,"%s/%s/VIDEO_TS/VTS_%02i_0.BUP",targetdir, title_name, title_set);
1159 	}
1160 
1161 	if (stat(targetname_ifo, &fileinfo) == 0) {
1162 		/* TRANSLATORS: The sentence starts with "The IFO file %s exists[...]" */
1163 		fprintf(stderr, _("The %s %s exists; will try to overwrite it.\n"), _("IFO file"), targetname_ifo);
1164 		if (! S_ISREG(fileinfo.st_mode)) {
1165 			/* TRANSLATORS: The sentence starts with "The IFO file %s is not valid[...]" */
1166 			fprintf(stderr,_("The %s %s is not valid, it may be a directory.\n"), _("IFO file"), targetname_ifo);
1167 			return(1);
1168 		}
1169 	}
1170 
1171 	if (stat(targetname_bup, &fileinfo) == 0) {
1172 		/* TRANSLATORS: The sentence starts with "The BUP file %s exists[...]" */
1173 		fprintf(stderr, _("The %s %s exists; will try to overwrite it.\n"), _("BUP file"), targetname_bup);
1174 		if (! S_ISREG(fileinfo.st_mode)) {
1175 			/* TRANSLATORS: The sentence starts with "The BUP file %s is not valid[...]" */
1176 			fprintf(stderr,_("The %s %s is not valid, it may be a directory.\n"), _("BUP file"), targetname_bup);
1177 			return(1);
1178 		}
1179 	}
1180 
1181 	if ((streamout_ifo = open(targetname_ifo, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) {
1182 		fprintf(stderr, _("Error creating %s\n"), targetname_ifo);
1183 		perror(PACKAGE);
1184 		DVDCloseFile(ifo_file);
1185 		free(buffer);
1186 		close(streamout_ifo);
1187 		close(streamout_bup);
1188 		return 1;
1189 	}
1190 
1191 	if ((streamout_bup = open(targetname_bup, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) {
1192 		fprintf(stderr, _("Error creating %s\n"), targetname_bup);
1193 		perror(PACKAGE);
1194 		DVDCloseFile(ifo_file);
1195 		free(buffer);
1196 		close(streamout_ifo);
1197 		close(streamout_bup);
1198 		return 1;
1199 	}
1200 
1201 	/* Copy VIDEO_TS.IFO, since it's a small file try to copy it in one shot */
1202 
1203 	if ((ifo_file = DVDOpenFile(dvd, title_set, DVD_READ_INFO_FILE))== 0) {
1204 		fprintf(stderr, _("Failed opening IFO for title set %d\n"), title_set);
1205 		DVDCloseFile(ifo_file);
1206 		free(buffer);
1207 		close(streamout_ifo);
1208 		close(streamout_bup);
1209 		return 1;
1210 	}
1211 
1212 	size = DVDFileSize(ifo_file) * DVD_VIDEO_LB_LEN;
1213 
1214 	if ((buffer = (unsigned char *)malloc(size * sizeof(unsigned char))) == NULL) {
1215 		perror(PACKAGE);
1216 		DVDCloseFile(ifo_file);
1217 		free(buffer);
1218 		close(streamout_ifo);
1219 		close(streamout_bup);
1220 		return 1;
1221 	}
1222 
1223 	DVDFileSeek(ifo_file, 0);
1224 
1225 	if (DVDReadBytes(ifo_file,buffer,size) != size) {
1226 		fprintf(stderr, _("Error reading IFO for title set %d\n"), title_set);
1227 		DVDCloseFile(ifo_file);
1228 		free(buffer);
1229 		close(streamout_ifo);
1230 		close(streamout_bup);
1231 		return 1;
1232 	}
1233 
1234 
1235 	if (write(streamout_ifo,buffer,size) != size) {
1236 		fprintf(stderr, _("Error writing %s\n"),targetname_ifo);
1237 		DVDCloseFile(ifo_file);
1238 		free(buffer);
1239 		close(streamout_ifo);
1240 		close(streamout_bup);
1241 		return 1;
1242 	}
1243 
1244 	if (write(streamout_bup,buffer,size) != size) {
1245 		fprintf(stderr, _("Error writing %s\n"),targetname_bup);
1246 		DVDCloseFile(ifo_file);
1247 		free(buffer);
1248 		close(streamout_ifo);
1249 		close(streamout_bup);
1250 		return 1;
1251 	}
1252 
1253 	return 0;
1254 }
1255 
1256 
DVDMirrorTitleX(dvd_reader_t * dvd,title_set_info_t * title_set_info,int title_set,char * targetdir,char * title_name,read_error_strategy_t errorstrat)1257 static int DVDMirrorTitleX(dvd_reader_t* dvd, title_set_info_t* title_set_info,
1258 		int title_set, char* targetdir, char* title_name,
1259 		read_error_strategy_t errorstrat) {
1260 
1261 	/* Loop through the vobs */
1262 	int i;
1263 	int n;
1264 
1265 	if ( DVDCopyIfoBup(dvd, title_set_info, title_set, targetdir, title_name) != 0 ) {
1266 		return(1);
1267 	}
1268 
1269 	if ( DVDCopyMenu(dvd, title_set_info, title_set, targetdir, title_name, errorstrat) != 0 ) {
1270 		return(1);
1271 	}
1272 
1273 	n = title_set_info->title_set[title_set].number_of_vob_files;
1274 	for (i = 0; i < n; i++) {
1275 #ifdef DEBUG
1276 		fprintf(stderr,"In the VOB copy loop for %d\n", i);
1277 #endif
1278 		if(progress) {
1279 			snprintf(progressText, MAXNAME, _("Title, part %i/%i"), i+1, n);
1280 		}
1281 
1282 		if ( DVDCopyTitleVobX(dvd, title_set_info, title_set, i + 1, targetdir, title_name, errorstrat) != 0 ) {
1283 		return(1);
1284 		}
1285 	}
1286 
1287 
1288 	return(0);
1289 }
1290 
DVDGetTitleName(const char * device,char * title)1291 int DVDGetTitleName(const char *device, char *title)
1292 {
1293 	/* Variables for filehandel and title string interaction */
1294 
1295 	char tempBuf[DVD_SEC_SIZ];
1296 	int filehandle, i;
1297 	int length = 32;
1298 	int word_length = 0;
1299 
1300 	/* Open DVD device */
1301 
1302 	if ( !(filehandle = open(device, O_RDONLY)) ) {
1303 		fprintf(stderr, _("Cannot open specified device %s - check your DVD device\n"), device);
1304 		return(1);
1305 	}
1306 
1307 	/* Seek to title of first track, which is at (track_no * 32768) + 40 */
1308 
1309 	if(lseek(filehandle, 32768, SEEK_SET) != 32768) {
1310 		close(filehandle);
1311 		fprintf(stderr, _("Cannot seek DVD device %s - check your DVD device\n"), device);
1312 		return(1);
1313 	}
1314 
1315 	/* Read the DVD-Video title */
1316 	if(DVD_SEC_SIZ != read(filehandle, tempBuf, DVD_SEC_SIZ)) {
1317 		close(filehandle);
1318 		fprintf(stderr, _("Cannot read title from DVD device %s\n"), device);
1319 		return(1);
1320 	}
1321 	snprintf(title, length + 1, "%s", tempBuf + 40);
1322 
1323 	/* Remove trailing white space */
1324 	while(title[length-1] == ' ') {
1325 		title[length-1] = '\0';
1326 		length--;
1327 	}
1328 
1329 	/* convert title to lower case and replace underscores with spaces */
1330 	for(i = 0; i < length; i++) {
1331 		word_length++;
1332 		if(word_length == 1) {
1333 			title[i] = toupper(title[i]);
1334 		} else {
1335 			title[i] = tolower(title[i]);
1336 		}
1337 		if(title[i] == '_') {
1338 			title[i] = ' ';
1339 		}
1340 		if(title[i] == ' ') {
1341 			word_length = 0;
1342 		}
1343 	}
1344 
1345 	return(0);
1346 }
1347 
1348 
1349 
bsort_min_to_max(int sector[],int title[],int size)1350 static void bsort_min_to_max(int sector[], int title[], int size){
1351 
1352 	int temp_title, temp_sector, i, j;
1353 
1354 	for ( i=0; i < size ; i++ ) {
1355 		for ( j=0; j < size ; j++ ) {
1356 			if (sector[i] < sector[j]) {
1357 				temp_sector = sector[i];
1358 				temp_title = title[i];
1359 				sector[i] = sector[j];
1360 				title[i] = title[j];
1361 				sector[j] = temp_sector;
1362 				title[j] = temp_title;
1363 			}
1364 		}
1365 	}
1366 }
1367 
bsort_max_to_min(int sector[],int title[],int size)1368 static void bsort_max_to_min(int sector[], int title[], int size){
1369 
1370 	int temp_title, temp_sector, i, j;
1371 
1372 	for ( i=0; i < size ; i++ ) {
1373 		for ( j=0; j < size ; j++ ) {
1374 			if (sector[i] > sector[j]) {
1375 				temp_sector = sector[i];
1376 				temp_title = title[i];
1377 				sector[i] = sector[j];
1378 				title[i] = title[j];
1379 				sector[j] = temp_sector;
1380 				title[j] = temp_title;
1381 			}
1382 		}
1383 	}
1384 }
1385 
1386 
align_end_sector(int cell_start_sector[],int cell_end_sector[],int size)1387 static void align_end_sector(int cell_start_sector[],int cell_end_sector[], int size) {
1388 
1389 	int i;
1390 
1391 	for (i = 0; i < size - 1 ; i++) {
1392 		if ( cell_end_sector[i] >= cell_start_sector[i + 1] ) {
1393 			cell_end_sector[i] = cell_start_sector[i + 1] - 1;
1394 		}
1395 	}
1396 }
1397 
1398 
DVDFreeTitleSetInfo(title_set_info_t * title_set_info)1399 static void DVDFreeTitleSetInfo(title_set_info_t * title_set_info) {
1400 	free(title_set_info->title_set);
1401 	free(title_set_info);
1402 }
1403 
1404 
DVDFreeTitlesInfo(titles_info_t * titles_info)1405 static void DVDFreeTitlesInfo(titles_info_t * titles_info) {
1406 	free(titles_info->titles);
1407 	free(titles_info);
1408 }
1409 
1410 
DVDGetFileSet(dvd_reader_t * dvd)1411 static title_set_info_t* DVDGetFileSet(dvd_reader_t* dvd) {
1412 
1413 	/* title interation */
1414 	int title_sets, counter, i;
1415 
1416 	/* DVD Video files */
1417 	dvd_stat_t statbuf;
1418 
1419 	/* DVD IFO handler */
1420 	ifo_handle_t* vmg_ifo = NULL;
1421 
1422 	/* The Title Set Info struct */
1423 	title_set_info_t* title_set_info;
1424 
1425 	/* Open main info file */
1426 	vmg_ifo = ifoOpen(dvd, 0);
1427 	if(vmg_ifo == NULL) {
1428 		fprintf( stderr, _("Cannot open Video Manager (VMG) info.\n"));
1429 		return NULL;
1430 	}
1431 
1432 	title_sets = vmg_ifo->vmgi_mat->vmg_nr_of_title_sets;
1433 
1434 	/* Close the VMG IFO file we got all the info we need */
1435 	ifoClose(vmg_ifo);
1436 
1437 	title_set_info = (title_set_info_t*)malloc(sizeof(title_set_info_t));
1438 	if(title_set_info == NULL) {
1439 		perror(PACKAGE);
1440 		return NULL;
1441 	}
1442 
1443 	title_set_info->title_set = (title_set_t*)malloc((title_sets + 1) * sizeof(title_set_t));
1444 	if(title_set_info->title_set == NULL) {
1445 		perror(PACKAGE);
1446 		free(title_set_info);
1447 		return NULL;
1448 	}
1449 
1450 	title_set_info->number_of_title_sets = title_sets;
1451 
1452 
1453 	/* Find VIDEO_TS.IFO is present - must be present since we did a ifo open 0 */
1454 
1455 	if (DVDFileStat(dvd, 0, DVD_READ_INFO_FILE, &statbuf) != -1) {
1456 		title_set_info->title_set[0].size_ifo = statbuf.size;
1457 	} else {
1458 		DVDFreeTitleSetInfo(title_set_info);
1459 		return NULL;
1460 	}
1461 
1462 	/* Find VIDEO_TS.VOB if present*/
1463 
1464 	if(DVDFileStat(dvd, 0, DVD_READ_MENU_VOBS, &statbuf) != -1) {
1465 		title_set_info->title_set[0].size_menu = statbuf.size;
1466 	} else {
1467 		title_set_info->title_set[0].size_menu = 0 ;
1468 	}
1469 
1470 	/* Take care of the titles which we don't have in VMG */
1471 
1472 	title_set_info->title_set[0].number_of_vob_files = 0;
1473 	title_set_info->title_set[0].size_vob[0] = 0;
1474 
1475 	if ( verbose > 0 ){
1476 		fprintf(stderr,_("\n\n\nFile sizes for Title set 0 VIDEO_TS.XXX\n"));
1477 		fprintf(stderr,_("IFO = %jd, MENU_VOB = %jd\n"),(intmax_t)title_set_info->title_set[0].size_ifo, (intmax_t)title_set_info->title_set[0].size_menu);
1478 	}
1479 
1480 	for(counter = 0; counter < title_sets; counter++) {
1481 
1482 		if(verbose > 1) {
1483 			fprintf(stderr,_("At top of loop\n"));
1484 		}
1485 
1486 
1487 		if(DVDFileStat(dvd, counter + 1, DVD_READ_INFO_FILE, &statbuf) != -1) {
1488 			title_set_info->title_set[counter+1].size_ifo = statbuf.size;
1489 		} else {
1490 			DVDFreeTitleSetInfo(title_set_info);
1491 			return NULL;
1492 		}
1493 
1494 		if(verbose > 1) {
1495 			fprintf(stderr,_("After opening files\n"));
1496 		}
1497 
1498 		/* Find VTS_XX_0.VOB if present */
1499 
1500 		if(DVDFileStat(dvd, counter + 1, DVD_READ_MENU_VOBS, &statbuf) != -1) {
1501 			title_set_info->title_set[counter + 1].size_menu = statbuf.size;
1502 		} else {
1503 			title_set_info->title_set[counter + 1].size_menu = 0 ;
1504 		}
1505 
1506 		if(verbose > 1) {
1507 			fprintf(stderr,_("After Menu VOB check\n"));
1508 		}
1509 
1510 		/* Find all VTS_XX_[1 to 9].VOB files if they are present */
1511 
1512 		i = 0;
1513 		if(DVDFileStat(dvd, counter + 1, DVD_READ_TITLE_VOBS, &statbuf) != -1) {
1514 			for(i = 0; i < statbuf.nr_parts; ++i) {
1515 				title_set_info->title_set[counter + 1].size_vob[i] = statbuf.parts_size[i];
1516 			}
1517 		}
1518 		title_set_info->title_set[counter + 1].number_of_vob_files = i;
1519 
1520 		if(verbose > 1) {
1521 			fprintf(stderr,_("After Menu Title VOB check\n"));
1522 		}
1523 
1524 		if(verbose > 0) {
1525 			fprintf(stderr,_("\n\n\nFile sizes for Title set %d i.e. VTS_%02d_X.XXX\n"), counter + 1, counter + 1);
1526 			fprintf(stderr,_("IFO: %jd, MENU: %jd\n"), (intmax_t)title_set_info->title_set[counter +1].size_ifo, (intmax_t)title_set_info->title_set[counter +1].size_menu);
1527 			for (i = 0; i < title_set_info->title_set[counter + 1].number_of_vob_files ; i++) {
1528 				fprintf(stderr, _("VOB %d is %jd\n"), i + 1, (intmax_t)title_set_info->title_set[counter + 1].size_vob[i]);
1529 			}
1530 		}
1531 
1532 		if(verbose > 1) {
1533 			fprintf(stderr,_("Bottom of loop\n"));
1534 		}
1535 	}
1536 
1537 	/* Return the info */
1538 	return title_set_info;
1539 }
1540 
1541 
DVDMirror(dvd_reader_t * _dvd,char * targetdir,char * title_name,read_error_strategy_t errorstrat)1542 int DVDMirror(dvd_reader_t * _dvd, char * targetdir,char * title_name, read_error_strategy_t errorstrat) {
1543 
1544 	int i;
1545 	title_set_info_t * title_set_info=NULL;
1546 
1547 	title_set_info = DVDGetFileSet(_dvd);
1548 	if (!title_set_info) {
1549 		return(1);
1550 	}
1551 
1552 	for ( i=0; i <= title_set_info->number_of_title_sets; i++) {
1553 		if ( DVDMirrorTitleX(_dvd, title_set_info, i, targetdir, title_name, errorstrat) != 0 ) {
1554 			fprintf(stderr,_("Mirror of Title set %d failed\n"), i);
1555 			DVDFreeTitleSetInfo(title_set_info);
1556 			return(1);
1557 		}
1558 	}
1559 	return(0);
1560 }
1561 
1562 
DVDMirrorTitleSet(dvd_reader_t * _dvd,char * targetdir,char * title_name,int title_set,read_error_strategy_t errorstrat)1563 int DVDMirrorTitleSet(dvd_reader_t * _dvd, char * targetdir,char * title_name, int title_set, read_error_strategy_t errorstrat) {
1564 
1565 	title_set_info_t * title_set_info=NULL;
1566 
1567 
1568 #ifdef DEBUG
1569 	fprintf(stderr,"In DVDMirrorTitleSet\n");
1570 #endif
1571 
1572 	title_set_info = DVDGetFileSet(_dvd);
1573 
1574 	if (!title_set_info) {
1575 		return(1);
1576 	}
1577 
1578 	if ( title_set > title_set_info->number_of_title_sets ) {
1579 		fprintf(stderr, _("Cannot copy title_set %d there is only %d title_sets present on this DVD\n"), title_set, title_set_info->number_of_title_sets);
1580 		DVDFreeTitleSetInfo(title_set_info);
1581 		return(1);
1582 	}
1583 
1584 	if ( DVDMirrorTitleX(_dvd, title_set_info, title_set, targetdir, title_name, errorstrat) != 0 ) {
1585 		fprintf(stderr,_("Mirror of Title set %d failed\n"), title_set);
1586 		DVDFreeTitleSetInfo(title_set_info);
1587 		return(1);
1588 	}
1589 
1590 	DVDFreeTitleSetInfo(title_set_info);
1591 	return(0);
1592 }
1593 
1594 
DVDMirrorMainFeature(dvd_reader_t * _dvd,char * targetdir,char * title_name,read_error_strategy_t errorstrat)1595 int DVDMirrorMainFeature(dvd_reader_t * _dvd, char * targetdir,char * title_name, read_error_strategy_t errorstrat) {
1596 
1597 	title_set_info_t * title_set_info=NULL;
1598 	titles_info_t * titles_info=NULL;
1599 
1600 
1601 	titles_info = DVDGetInfo(_dvd);
1602 	if (!titles_info) {
1603 		fprintf(stderr, _("Guesswork of main feature film failed.\n"));
1604 		return(1);
1605 	}
1606 
1607 	title_set_info = DVDGetFileSet(_dvd);
1608 	if (!title_set_info) {
1609 		DVDFreeTitlesInfo(titles_info);
1610 		return(1);
1611 	}
1612 
1613 	if ( DVDMirrorTitleX(_dvd, title_set_info, titles_info->main_title_set, targetdir, title_name, errorstrat) != 0 ) {
1614 		fprintf(stderr,_("Mirror of main feature file which is title set %d failed\n"), titles_info->main_title_set);
1615 		DVDFreeTitleSetInfo(title_set_info);
1616 		return(1);
1617 	}
1618 
1619 	DVDFreeTitlesInfo(titles_info);
1620 	DVDFreeTitleSetInfo(title_set_info);
1621 	return(0);
1622 }
1623 
1624 
DVDMirrorChapters(dvd_reader_t * _dvd,char * targetdir,char * title_name,int start_chapter,int end_chapter,int titles)1625 int DVDMirrorChapters(dvd_reader_t * _dvd, char * targetdir,char * title_name, int start_chapter,int end_chapter, int titles) {
1626 
1627 
1628 	int result;
1629 	int chapters = 0;
1630 	int i, s;
1631 	int spg, epg;
1632 	int pgc;
1633 	int start_cell, end_cell;
1634 	int vts_title;
1635 
1636 	title_set_info_t * title_set_info=NULL;
1637 	titles_info_t * titles_info=NULL;
1638 	ifo_handle_t * vts_ifo_info=NULL;
1639 	int * cell_start_sector=NULL;
1640 	int * cell_end_sector=NULL;
1641 
1642 	titles_info = DVDGetInfo(_dvd);
1643 	if (!titles_info) {
1644 		fprintf(stderr, _("Failed to obtain titles information\n"));
1645 		return(1);
1646 	}
1647 
1648 	title_set_info = DVDGetFileSet(_dvd);
1649 	if (!title_set_info) {
1650 		DVDFreeTitlesInfo(titles_info);
1651 		return(1);
1652 	}
1653 
1654 	if(titles == 0) {
1655 		fprintf(stderr, _("No title specified for chapter extraction, will try to figure out main feature title\n"));
1656 		for (i=0; i < titles_info->number_of_titles ; i++ ) {
1657 			if ( titles_info->titles[i].title_set == titles_info->main_title_set ) {
1658 				if(chapters < titles_info->titles[i].chapters) {
1659 					chapters = titles_info->titles[i].chapters;
1660 					titles = i + 1;
1661 				}
1662 			}
1663 		}
1664 	}
1665 
1666 	vts_ifo_info = ifoOpen(_dvd, titles_info->titles[titles - 1].title_set);
1667 	if(!vts_ifo_info) {
1668 		fprintf(stderr, _("Could not open title_set %d IFO file\n"), titles_info->titles[titles - 1].title_set);
1669 		DVDFreeTitlesInfo(titles_info);
1670 		DVDFreeTitleSetInfo(title_set_info);
1671 		return(1);
1672 	}
1673 
1674 	vts_title = titles_info->titles[titles - 1].vts_title;
1675 
1676 	if (end_chapter > titles_info->titles[titles - 1].chapters) {
1677 		end_chapter = titles_info->titles[titles - 1].chapters;
1678 		fprintf(stderr, _("Truncated the end_chapter; only %d chapters in %d title\n"), end_chapter,titles);
1679 	}
1680 
1681 	if (start_chapter > titles_info->titles[titles - 1].chapters) {
1682 		start_chapter = titles_info->titles[titles - 1].chapters;
1683 		fprintf(stderr, _("Truncated the end_chapter; only %d chapters in %d title\n"), end_chapter,titles);
1684 	}
1685 
1686 
1687 
1688 	/* We assume the same PGC for the whole title - this is not true and need to be fixed later on */
1689 
1690 	pgc = vts_ifo_info->vts_ptt_srpt->title[vts_title - 1].ptt[start_chapter - 1].pgcn;
1691 
1692 
1693 	/* Lookup PG for start chapter */
1694 
1695 	spg = vts_ifo_info->vts_ptt_srpt->title[vts_title - 1].ptt[start_chapter - 1].pgn;
1696 
1697 	/* Look up start cell for this pgc/pg */
1698 
1699 	start_cell = vts_ifo_info->vts_pgcit->pgci_srp[pgc - 1].pgc->program_map[spg - 1];
1700 
1701 
1702 	/* Lookup end cell*/
1703 
1704 
1705 	if ( end_chapter < titles_info->titles[titles - 1].chapters ) {
1706 		epg = vts_ifo_info->vts_ptt_srpt->title[vts_title - 1].ptt[end_chapter].pgn;
1707 #ifdef DEBUG
1708 		fprintf(stderr,"DVDMirrorChapter: epg %d\n", epg);
1709 #endif
1710 
1711 		end_cell = vts_ifo_info->vts_pgcit->pgci_srp[pgc - 1].pgc->program_map[epg -1] - 1;
1712 #ifdef DEBUG
1713 		fprintf(stderr,"DVDMirrorChapter: end cell adjusted %d\n", end_cell);
1714 #endif
1715 
1716 	} else {
1717 
1718 		end_cell = vts_ifo_info->vts_pgcit->pgci_srp[pgc - 1].pgc->nr_of_cells;
1719 #ifdef DEBUG
1720 		fprintf(stderr,"DVDMirrorChapter: end cell adjusted 2 %d\n",end_cell);
1721 #endif
1722 
1723 	}
1724 
1725 #ifdef DEBUG
1726 	fprintf(stderr,"DVDMirrorChapter: star cell %d\n", start_cell);
1727 #endif
1728 
1729 
1730 	/* Put all the cells start and end sector in a dual array */
1731 
1732 	cell_start_sector = (int *)malloc( (end_cell - start_cell + 1) * sizeof(int));
1733 	if(!cell_start_sector) {
1734 		fprintf(stderr,_("Memory allocation error 1\n"));
1735 		DVDFreeTitlesInfo(titles_info);
1736 		DVDFreeTitleSetInfo(title_set_info);
1737 		ifoClose(vts_ifo_info);
1738 		return(1);
1739 	}
1740 	cell_end_sector = (int *)malloc( (end_cell - start_cell + 1) * sizeof(int));
1741 	if(!cell_end_sector) {
1742 		fprintf(stderr,_("Memory allocation error\n"));
1743 		DVDFreeTitlesInfo(titles_info);
1744 		DVDFreeTitleSetInfo(title_set_info);
1745 		ifoClose(vts_ifo_info);
1746 		free(cell_start_sector);
1747 		return(1);
1748 	}
1749 #ifdef DEBUG
1750 	fprintf(stderr,"DVDMirrorChapter: start cell is %d\n", start_cell);
1751 	fprintf(stderr,"DVDMirrorChapter: end cell is %d\n", end_cell);
1752 	fprintf(stderr,"DVDMirrorChapter: pgc is %d\n", pgc);
1753 #endif
1754 
1755 	for (i=0, s=start_cell; s < end_cell +1 ; i++, s++) {
1756 
1757 		cell_start_sector[i] = vts_ifo_info->vts_pgcit->pgci_srp[pgc - 1].pgc->cell_playback[s - 1].first_sector;
1758 		cell_end_sector[i] = vts_ifo_info->vts_pgcit->pgci_srp[pgc - 1].pgc->cell_playback[s - 1].last_sector;
1759 #ifdef DEBUG
1760 		fprintf(stderr,"DVDMirrorChapter: S is %d\n", s);
1761 		fprintf(stderr,"DVDMirrorChapter: start sector %d\n", vts_ifo_info->vts_pgcit->pgci_srp[pgc - 1].pgc->cell_playback[s - 1].first_sector);
1762 		fprintf(stderr,"DVDMirrorChapter: end sector %d\n", vts_ifo_info->vts_pgcit->pgci_srp[pgc - 1].pgc->cell_playback[s - 1].last_sector);
1763 #endif
1764 	}
1765 
1766 	bsort_min_to_max(cell_start_sector, cell_end_sector, end_cell - start_cell + 1);
1767 
1768 	align_end_sector(cell_start_sector, cell_end_sector,end_cell - start_cell + 1);
1769 
1770 #ifdef DEBUG
1771 	for (i=0 ; i < end_cell - start_cell + 1; i++) {
1772 		fprintf(stderr,"DVDMirrorChapter: Start sector is %d end sector is %d\n", cell_start_sector[i], cell_end_sector[i]);
1773 	}
1774 #endif
1775 
1776 	result = DVDWriteCells(_dvd, cell_start_sector, cell_end_sector , end_cell - start_cell + 1, titles, title_set_info, titles_info, targetdir, title_name);
1777 
1778 	DVDFreeTitlesInfo(titles_info);
1779 	DVDFreeTitleSetInfo(title_set_info);
1780 	ifoClose(vts_ifo_info);
1781 	free(cell_start_sector);
1782 	free(cell_end_sector);
1783 
1784 	if( result != 0) {
1785 		return(1);
1786 	} else {
1787 		return(0);
1788 	}
1789 }
1790 
1791 
DVDMirrorTitles(dvd_reader_t * _dvd,char * targetdir,char * title_name,int titles)1792 int DVDMirrorTitles(dvd_reader_t * _dvd, char * targetdir,char * title_name, int titles) {
1793 
1794 	int end_chapter;
1795 
1796 	titles_info_t * titles_info=NULL;
1797 
1798 #ifdef DEBUG
1799 	fprintf(stderr,"In DVDMirrorTitles\n");
1800 #endif
1801 
1802 
1803 
1804 	titles_info = DVDGetInfo(_dvd);
1805 	if (!titles_info) {
1806 		fprintf(stderr, _("Failed to obtain titles information\n"));
1807 		return(1);
1808 	}
1809 
1810 
1811 	end_chapter = titles_info->titles[titles - 1].chapters;
1812 #ifdef DEBUG
1813 	fprintf(stderr,"DVDMirrorTitles: end_chapter %d\n", end_chapter);
1814 #endif
1815 
1816 	if (DVDMirrorChapters( _dvd, targetdir, title_name, 1, end_chapter, titles) != 0 ) {
1817 		DVDFreeTitlesInfo(titles_info);
1818 		return(1);
1819 	}
1820 
1821 	DVDFreeTitlesInfo(titles_info);
1822 
1823 	return(0);
1824 }
1825 
1826 
1827 /**
1828  * Formats a filesize human readable. For example 25,05 KiB instead of
1829  * 25648 Bytes.
1830  */
format_filesize(off_t filesize,char * result)1831 static void format_filesize(off_t filesize, char* result) {
1832 	char* prefix = "";
1833 	double size = (double)filesize;
1834 	int prefix_count = 0;
1835 
1836 	while(size > 1024 && prefix_count < 6) {
1837 		size /= 1024;
1838 		prefix_count++;
1839 	}
1840 
1841 	if(prefix_count == 1) {
1842 		prefix = "Ki";
1843 	} else if(prefix_count == 2) {
1844 		prefix = "Mi";
1845 	} else if(prefix_count == 3) {
1846 		prefix = "Gi";
1847 	} else if(prefix_count == 4) {
1848 		prefix = "Ti";
1849 	} else if(prefix_count == 5) {
1850 		prefix = "Pi";
1851 	} else if(prefix_count == 6) {
1852 		prefix = "Ei";
1853 	}
1854 
1855 	sprintf(result, "%7.2f %sB", size, prefix);
1856 }
1857 
1858 
DVDDisplayInfo(dvd_reader_t * dvd,char * device)1859 int DVDDisplayInfo(dvd_reader_t* dvd, char* device) {
1860 	int i, f;
1861 	int chapters;
1862 	int channels;
1863 	int titles;
1864 	char title_name[33] = "";
1865 	char size[40] = "";
1866 	title_set_info_t* title_set_info = NULL;
1867 	titles_info_t* titles_info = NULL;
1868 
1869 	titles_info = DVDGetInfo(dvd);
1870 	if (!titles_info) {
1871 		fprintf(stderr, _("Guesswork of main feature film failed.\n"));
1872 		return(1);
1873 	}
1874 
1875 	title_set_info = DVDGetFileSet(dvd);
1876 	if (!title_set_info) {
1877 		DVDFreeTitlesInfo(titles_info);
1878 		return(1);
1879 	}
1880 
1881 	DVDGetTitleName(device, title_name);
1882 
1883 
1884 	printf(_("DVD-Video information of the DVD with title \"%s\"\n\n"), title_name);
1885 
1886 	/* Print file structure */
1887 
1888 	printf(_("File Structure DVD\n"));
1889 	printf("VIDEO_TS/\n");
1890 	format_filesize(title_set_info->title_set[0].size_ifo, size);
1891 	printf("\tVIDEO_TS.IFO\t%10jd\t%s\n", (intmax_t)title_set_info->title_set[0].size_ifo, size);
1892 
1893 	if (title_set_info->title_set[0].size_menu != 0 ) {
1894 		format_filesize(title_set_info->title_set[0].size_menu, size);
1895 		printf("\tVIDEO_TS.VOB\t%10jd\t%s\n", (intmax_t)title_set_info->title_set[0].size_menu, size);
1896 	}
1897 
1898 	for(i = 0 ; i <= title_set_info->number_of_title_sets; i++) {
1899 		format_filesize(title_set_info->title_set[i].size_ifo, size);
1900 		printf("\tVTS_%02i_0.IFO\t%10jd\t%s\n", i, (intmax_t)title_set_info->title_set[i].size_ifo, size);
1901 		if(title_set_info->title_set[i].size_menu != 0) {
1902 			format_filesize(title_set_info->title_set[i].size_menu, size);
1903 			printf("\tVTS_%02i_0.VOB\t%10jd\t%s\n", i, (intmax_t)title_set_info->title_set[i].size_menu, size);
1904 		}
1905 		if(title_set_info->title_set[i].number_of_vob_files != 0) {
1906 			for(f = 0; f < title_set_info->title_set[i].number_of_vob_files; f++) {
1907 				format_filesize(title_set_info->title_set[i].size_vob[f], size);
1908 				printf("\tVTS_%02i_%i.VOB\t%10jd\t%s\n", i, f + 1, (intmax_t)title_set_info->title_set[i].size_vob[f], size);
1909 			}
1910 		}
1911 	}
1912 
1913 	printf(_("\n\nMain feature:\n"));
1914 	printf(_("\tTitle set containing the main feature is %d\n"), titles_info->main_title_set);
1915 	for (i=0; i < titles_info->number_of_titles ; i++ ) {
1916 		if (titles_info->titles[i].title_set == titles_info->main_title_set) {
1917 			if(titles_info->titles[i].aspect_ratio == 3) {
1918 				printf(_("\tThe aspect ratio of the main feature is 16:9\n"));
1919 			} else if (titles_info->titles[i].aspect_ratio == 0) {
1920 				printf(_("\tThe aspect ratio of the main feature is 4:3\n"));
1921 			} else {
1922 				printf(_("\tThe aspect ratio of the main feature is unknown\n"));
1923 			}
1924 
1925 			printf(ngettext("\tThe main feature has %d angle\n",
1926 					"\tThe main feature has %d angles\n",
1927 					titles_info->titles[i].angles), titles_info->titles[i].angles);
1928 			printf(ngettext("\tThe main feature has %d audio track\n",
1929 					"\tThe main feature has %d audio tracks\n",
1930 					titles_info->titles[i].audio_tracks), titles_info->titles[i].audio_tracks);
1931 			printf(ngettext("\tThe main feature has %d subpicture channel\n",
1932 					"\tThe main feature has %d subpicture channels\n",
1933 					titles_info->titles[i].sub_pictures), titles_info->titles[i].sub_pictures);
1934 			chapters=0;
1935 			channels=0;
1936 
1937 			for (f=0; f < titles_info->number_of_titles ; f++ ) {
1938 				if ( titles_info->titles[i].title_set == titles_info->main_title_set ) {
1939 					if(chapters < titles_info->titles[f].chapters) {
1940 						chapters = titles_info->titles[f].chapters;
1941 					}
1942 					if(channels < titles_info->titles[f].audio_channels) {
1943 						channels = titles_info->titles[f].audio_channels;
1944 					}
1945 				}
1946 			}
1947 			printf(ngettext("\tThe main feature has a maximum of %d chapter in one of its titles\n",
1948 					"\tThe main feature has a maximum of %d chapters in one of its titles\n",
1949 					chapters), chapters);
1950 			printf(ngettext("\tThe main feature has a maximum of %d audio channel in one of its titles\n",
1951 					"\tThe main feature has a maximum of %d audio channels in one of its titles\n",
1952 					channels), channels);
1953 			break;
1954 		}
1955 	}
1956 
1957 	printf(_("\n\nTitle Sets:"));
1958 	for (f=0; f < title_set_info->number_of_title_sets ; f++ ) {
1959 		printf(_("\n\n\tTitle set %d\n"), f + 1);
1960 		for (i=0; i < titles_info->number_of_titles ; i++ ) {
1961 			if (titles_info->titles[i].title_set == f + 1) {
1962 				if(titles_info->titles[i].aspect_ratio == 3) {
1963 					printf(_("\t\tThe aspect ratio of title set %d is 16:9\n"), f + 1);
1964 				} else if (titles_info->titles[i].aspect_ratio == 0) {
1965 					printf(_("\t\tThe aspect ratio of title set %d is 4:3\n"), f + 1);
1966 				} else {
1967 					printf(_("\t\tThe aspect ratio of title set %d is unknown\n"), f + 1);
1968 				}
1969 				printf(ngettext("\t\tTitle set %d has %d angle\n",
1970 						"\t\tTitle set %d has %d angles\n",
1971 						titles_info->titles[i].angles), f + 1, titles_info->titles[i].angles);
1972 				printf(ngettext("\t\tTitle set %d has %d audio track\n",
1973 						"\t\tTitle set %d has %d audio tracks\n",
1974 						titles_info->titles[i].audio_tracks), f + 1, titles_info->titles[i].audio_tracks);
1975 				printf(ngettext("\t\tTitle set %d has %d subpicture channel\n",
1976 						"\t\tTitle set %d has %d subpicture channels\n",
1977 						titles_info->titles[i].sub_pictures), f + 1, titles_info->titles[i].sub_pictures);
1978 				break;
1979 			}
1980 		}
1981 
1982 		titles = 0;
1983 		for(i = 0; i < titles_info->number_of_titles; i++) {
1984 			if (titles_info->titles[i].title_set == f + 1) {
1985 				titles++;
1986 			}
1987 		}
1988 		printf(ngettext("\n\t\tTitle included in title set %d is\n",
1989 				"\n\t\tTitles included in title set %d are\n",
1990 				titles), f + 1);
1991 
1992 		for (i=0; i < titles_info->number_of_titles ; i++ ) {
1993 			if (titles_info->titles[i].title_set == f + 1) {
1994 				printf(_("\t\t\tTitle %d:\n"), i + 1);
1995 				printf(ngettext("\t\t\t\tTitle %d has %d chapter\n",
1996 						"\t\t\t\tTitle %d has %d chapters\n",
1997 						titles_info->titles[i].chapters), i + 1, titles_info->titles[i].chapters);
1998 				printf(ngettext("\t\t\t\tTitle %d has %d audio channel\n",
1999 						"\t\t\t\tTitle %d has %d audio channels\n",
2000 						titles_info->titles[i].audio_channels), i + 1, titles_info->titles[i].audio_channels);
2001 			}
2002 		}
2003 	}
2004 	DVDFreeTitlesInfo(titles_info);
2005 	DVDFreeTitleSetInfo(title_set_info);
2006 
2007 	return(0);
2008 }
2009