1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /*
3  * Libbrasero-burn
4  * Copyright (C) Philippe Rouquier 2005-2009 <bonfire-app@wanadoo.fr>
5  *
6  * Libbrasero-burn is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * The Libbrasero-burn authors hereby grant permission for non-GPL compatible
12  * GStreamer plugins to be used and distributed together with GStreamer
13  * and Libbrasero-burn. This permission is above and beyond the permissions granted
14  * by the GPL license by which Libbrasero-burn is covered. If you modify this code
15  * you may extend this exception to your version of the code, but you are not
16  * obligated to do so. If you do not wish to do so, delete this exception
17  * statement from your version.
18  *
19  * Libbrasero-burn is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU Library General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to:
26  * 	The Free Software Foundation, Inc.,
27  * 	51 Franklin Street, Fifth Floor
28  * 	Boston, MA  02110-1301, USA.
29  */
30 
31 #ifdef HAVE_CONFIG_H
32 #  include <config.h>
33 #endif
34 
35 #include <errno.h>
36 #include <string.h>
37 #include <ctype.h>
38 #include <stdlib.h>
39 #include <sys/param.h>
40 
41 #include <glib.h>
42 #include <glib/gstdio.h>
43 #include <glib/gi18n-lib.h>
44 
45 #include "burn-basics.h"
46 #include "burn-debug.h"
47 #include "burn-image-format.h"
48 
49 static const gchar *
brasero_image_format_read_path(const gchar * ptr,gchar ** path)50 brasero_image_format_read_path (const gchar *ptr,
51 				gchar **path)
52 {
53 	const gchar *start, *end;
54 
55 	/* make sure there is a white space */
56 	if (!isspace (*ptr))
57 		return NULL;
58 
59 	/* jump over the white spaces */
60 	while (isspace (*ptr)) ptr ++;
61 
62 	/* seek the first '"' if any */
63 	start = g_utf8_strchr (ptr, -1, '"');
64 	if (start) {
65 		start ++;
66 
67 		/* seek the last '"' */
68 		end = g_utf8_strchr (start, -1, '"');
69 		if (!end)
70 			return NULL;
71 
72 		ptr = end + 1;
73 	}
74 	else {
75 		/* there is no starting '"' seek last space */
76 		start = ptr;
77 		end = ptr;
78 		while (!isspace (*end)) end ++;
79 
80 		ptr = end;
81 		if (isspace (*end))
82 			end --;
83 	}
84 
85 	if (path)
86 		*path = g_strndup (start, end-start);
87 
88 	return ptr;
89 }
90 
91 static gchar *
brasero_image_format_get_cue_file_complement(const gchar * path)92 brasero_image_format_get_cue_file_complement (const gchar *path)
93 {
94 	FILE *file;
95 	gchar *ptr;
96 	gchar *complement = NULL;
97 	/* a path can't be over MAXPATHLEN then buffer doesn't need to be over
98 	 * this value + 4 + white space + commas */
99 	gchar buffer [MAXPATHLEN+8+3];
100 
101 	file = fopen (path, "r");
102 	if (!file) {
103 		if (g_str_has_suffix (path, ".cue"))
104 			return g_strdup_printf ("%.*sbin",
105 						(int) strlen (path) - 3,
106 						path);
107 
108 		return g_strdup_printf ("%s.bin", path);
109 	}
110 
111 	while (fgets (buffer, sizeof (buffer), file)) {
112 		ptr = strstr (buffer, "FILE");
113 		if (ptr) {
114 			ptr += 4;
115 			if (brasero_image_format_read_path (ptr, &complement))
116 				break;
117 		}
118 	}
119 	fclose (file);
120 
121 	/* check if the path is relative, if so then add the root path */
122 	if (complement && !g_path_is_absolute (complement)) {
123 		gchar *directory;
124 		gchar *tmp;
125 
126 		directory = g_path_get_dirname (path);
127 
128 		tmp = complement;
129 		complement = g_build_path (G_DIR_SEPARATOR_S,
130 					   directory,
131 					   complement,
132 					   NULL);
133 		g_free (tmp);
134 	}
135 
136 	return complement;
137 }
138 
139 static gchar *
brasero_image_format_get_toc_file_complement(const gchar * path)140 brasero_image_format_get_toc_file_complement (const gchar *path)
141 {
142 	FILE *file;
143 	gchar *ptr;
144 	gchar *complement = NULL;
145 	/* a path can't be over MAXPATHLEN then buffer doesn't need to be over
146 	 * this value + keyword size + white space + commas */
147 	gchar buffer [MAXPATHLEN+8+3];
148 
149 	/* NOTE: the problem here is that cdrdao files can have references to
150 	 * multiple files. Which is great but not for us ... */
151 	file = fopen (path, "r");
152 	if (!file) {
153 		if (g_str_has_suffix (path, ".cue"))
154 			return g_strdup_printf ("%.*sbin",
155 						(int) strlen (path) - 3,
156 						path);
157 
158 		return g_strdup_printf ("%s.bin", path);
159 	}
160 
161 	while (fgets (buffer, sizeof (buffer), file)) {
162 		ptr = strstr (buffer, "DATAFILE");
163 		if (ptr) {
164 			ptr += 8;
165 			if (brasero_image_format_read_path (ptr, &complement))
166 				break;
167 		}
168 
169 		ptr = strstr (buffer, "FILE");
170 		if (ptr) {
171 			ptr += 4;
172 			if (brasero_image_format_read_path (ptr, &complement))
173 				break;
174 		}
175 	}
176 	fclose (file);
177 
178 	/* check if the path is relative, if so then add the root path */
179 	if (complement && !g_path_is_absolute (complement)) {
180 		gchar *directory;
181 		gchar *tmp;
182 
183 		directory = g_path_get_dirname (path);
184 
185 		tmp = complement;
186 		complement = g_build_path (G_DIR_SEPARATOR_S,
187 					   directory,
188 					   complement,
189 					   NULL);
190 		g_free (tmp);
191 	}
192 
193 	return complement;
194 }
195 
196 /* FIXME this function is flawed at the moment. A cue file or toc file can
197  * hold different paths */
198 gchar *
brasero_image_format_get_complement(BraseroImageFormat format,const gchar * path)199 brasero_image_format_get_complement (BraseroImageFormat format,
200 				     const gchar *path)
201 {
202 	gchar *retval = NULL;
203 
204 	if (format == BRASERO_IMAGE_FORMAT_CLONE) {
205 		/* These are set rules no need to parse:
206 		 * the toc file has to end with .toc suffix */
207 		if (g_str_has_suffix (path, ".toc"))
208 			retval = g_strndup (path, strlen (path) - 4);
209 	}
210 	else if (format == BRASERO_IMAGE_FORMAT_CUE) {
211 		/* need to parse */
212 		retval = brasero_image_format_get_cue_file_complement (path);
213 	}
214 	else if (format == BRASERO_IMAGE_FORMAT_CDRDAO) {
215 		/* need to parse */
216 		retval = brasero_image_format_get_toc_file_complement (path);
217 	}
218 	else
219 		retval = NULL;
220 
221 	return retval;
222 }
223 
224 static gchar *
brasero_image_format_get_MSF_address(const gchar * ptr,gint64 * block)225 brasero_image_format_get_MSF_address (const gchar *ptr,
226 				      gint64 *block)
227 {
228 	gchar *next;
229 	gint64 address = 0;
230 
231 	address = strtoll (ptr, &next, 10);
232 	if (isspace (*next)) {
233 		*block = address;
234 		return next;
235 	}
236 
237 	if (*next != ':')
238 		return NULL;
239 
240 	next ++;
241 	ptr = next;
242 	address *= 60;
243 	address += strtoll (ptr, &next, 10);
244 	if (ptr == next)
245 		return NULL;
246 
247 	if (*next != ':')
248 		return NULL;
249 
250 	next ++;
251 	ptr = next;
252 	address *= 75;
253 	address += strtoll (ptr, &next, 10);
254 	if (ptr == next)
255 		return NULL;
256 
257 	if (block)
258 		*block = address;
259 
260 	return next;
261 }
262 
263 static gboolean
brasero_image_format_get_DATAFILE_info(const gchar * ptr,GFile * parent,gint64 * size_file,GError ** error)264 brasero_image_format_get_DATAFILE_info (const gchar *ptr,
265 					GFile *parent,
266 					gint64 *size_file,
267 					GError **error)
268 {
269 	gchar *path = NULL;
270 	GFileInfo *info;
271 	GFile *file;
272 
273 	/* get the path. NOTE: no need to check if it's relative since that's
274 	 * just to skip it. */
275 	ptr = brasero_image_format_read_path (ptr, &path);
276 	if (!ptr)
277 		return FALSE;
278 
279 	/* skip white spaces */
280 	while (isspace (*ptr)) ptr++;
281 
282 	if (ptr [0] == '\0'
283 	|| (ptr [0] == '/' && ptr [1] == '/'))
284 		goto stat_end;
285 
286 	if (!brasero_image_format_get_MSF_address (ptr, size_file)) {
287 		g_free (path);
288 		return FALSE;
289 	}
290 
291 	g_free (path);
292 	return TRUE;
293 
294 stat_end:
295 
296 	/* check if the path is relative, if so then add the root path */
297 	if (path && !g_path_is_absolute (path))
298 		file = g_file_resolve_relative_path (parent, path);
299 	else if (path) {
300 		gchar *img_uri;
301 		gchar *scheme;
302 
303 		scheme = g_file_get_uri_scheme (parent);
304 		img_uri = g_strconcat (scheme, "://", path, NULL);
305 		g_free (scheme);
306 
307 		file = g_file_new_for_commandline_arg (img_uri);
308 		g_free (img_uri);
309 	}
310 	else
311 		return FALSE;
312 
313 	g_free (path);
314 
315 	/* NOTE: follow symlink if any */
316 	info = g_file_query_info (file,
317 				  G_FILE_ATTRIBUTE_STANDARD_SIZE,
318 				  G_FILE_QUERY_INFO_NONE,
319 				  NULL,
320 				  error);
321 	g_object_unref (file);
322 	if (!info)
323 		return FALSE;
324 
325 	if (size_file)
326 		*size_file = BRASERO_BYTES_TO_SECTORS (g_file_info_get_size (info), 2352);
327 
328 	g_object_unref (info);
329 
330 	return TRUE;
331 }
332 
333 static gboolean
brasero_image_format_get_FILE_info(const gchar * ptr,GFile * parent,gint64 * size_img,GError ** error)334 brasero_image_format_get_FILE_info (const gchar *ptr,
335 				    GFile *parent,
336 				    gint64 *size_img,
337 				    GError **error)
338 {
339 	gchar *path = NULL;
340 	gint64 start = 0;
341 	GFileInfo *info;
342 	GFile *file = NULL;
343 	gchar *tmp;
344 
345 	/* get the path and skip it */
346 	ptr = brasero_image_format_read_path (ptr, &path);
347 	if (!ptr)
348 		return FALSE;
349 
350 	/* skip white spaces */
351 	while (isspace (*ptr)) ptr++;
352 
353 	/* skip a possible #.... (offset in bytes) */
354 	tmp = g_utf8_strchr (ptr, -1, '#');
355 	if (tmp) {
356 		tmp ++;
357 		while (isdigit (*tmp)) tmp ++;
358 		while (isspace (*tmp)) tmp++;
359 		ptr = tmp;
360 	}
361 
362 	/* get the start */
363 	ptr = brasero_image_format_get_MSF_address (ptr, &start);
364 	if (!ptr) {
365 		g_free (path);
366 		return FALSE;
367 	}
368 
369 	/* skip white spaces */
370 	while (isspace (*ptr)) ptr++;
371 
372 	if (ptr [0] == '\0'
373 	|| (ptr [0] == '/' && ptr [1] == '/'))
374 		goto stat_end;
375 
376 	/* get the size */
377 	if (!brasero_image_format_get_MSF_address (ptr, size_img)) {
378 		g_free (path);
379 		return FALSE;
380 	}
381 
382 	g_free (path);
383 	return TRUE;
384 
385 stat_end:
386 
387 	/* check if the path is relative, if so then add the root path */
388 	if (path && !g_path_is_absolute (path))
389 		file = g_file_resolve_relative_path (parent, path);
390 	else if (path) {
391 		gchar *img_uri;
392 		gchar *scheme;
393 
394 		scheme = g_file_get_uri_scheme (parent);
395 		img_uri = g_strconcat (scheme, "://", path, NULL);
396 		g_free (scheme);
397 
398 		file = g_file_new_for_commandline_arg (img_uri);
399 		g_free (img_uri);
400 	}
401 	else
402 		return FALSE;
403 
404 	g_free (path);
405 
406 	/* NOTE: follow symlink if any */
407 	info = g_file_query_info (file,
408 				  G_FILE_ATTRIBUTE_STANDARD_SIZE,
409 				  G_FILE_QUERY_INFO_NONE,
410 				  NULL,
411 				  error);
412 	g_object_unref (file);
413 	if (!info)
414 		return FALSE;
415 
416 	if (size_img)
417 		*size_img = BRASERO_BYTES_TO_SECTORS (g_file_info_get_size (info), 2352) - start;
418 
419 	g_object_unref (info);
420 
421 	return TRUE;
422 }
423 
424 gboolean
brasero_image_format_get_cdrdao_size(gchar * uri,guint64 * sectors,guint64 * size_img,GCancellable * cancel,GError ** error)425 brasero_image_format_get_cdrdao_size (gchar *uri,
426 				      guint64 *sectors,
427 				      guint64 *size_img,
428 				      GCancellable *cancel,
429 				      GError **error)
430 {
431 	GFile *file;
432 	gchar *line;
433 	GFile *parent;
434 	gint64 cue_size = 0;
435 	GFileInputStream *input;
436 	GDataInputStream *stream;
437 
438 	file = g_file_new_for_uri (uri);
439 	input = g_file_read (file, cancel, error);
440 
441 	if (!input) {
442 		g_object_unref (file);
443 		return FALSE;
444 	}
445 
446 	stream = g_data_input_stream_new (G_INPUT_STREAM (input));
447 	g_object_unref (input);
448 
449 	parent = g_file_get_parent (file);
450 	while ((line = g_data_input_stream_read_line (stream, NULL, cancel, error))) {
451 		gchar *ptr;
452 
453 		if ((ptr = strstr (line, "DATAFILE"))) {
454 			gint64 size_file;
455 
456 			ptr += 8;
457 			if (brasero_image_format_get_DATAFILE_info (ptr, parent, &size_file, error))
458 				cue_size += size_file;
459 		}
460 		else if ((ptr = strstr (line, "FILE"))) {
461 			gint64 size_file;
462 
463 			ptr += 4;
464 			/* first number is the position, the second the size,
465 			 * number after '#' is the offset (in bytes). */
466 			if (brasero_image_format_get_FILE_info (ptr, parent, &size_file, error))
467 				cue_size += size_file;
468 		}
469 		else if ((ptr = strstr (line, "AUDIOFILE"))) {
470 			gint64 size_file;
471 
472 			ptr += 4;
473 			/* first number is the position, the second the size,
474 			 * number after '#' is the offset (in bytes). */
475 			if (brasero_image_format_get_FILE_info (ptr, parent, &size_file, error))
476 				cue_size += size_file;
477 		}
478 		else if ((ptr = strstr (line, "SILENCE"))) {
479 			gint64 size_silence;
480 
481 			ptr += 7;
482 			if (isspace (*ptr)
483 			&&  brasero_image_format_get_MSF_address (ptr, &size_silence))
484 				cue_size += size_silence;
485 		}
486 		else if ((ptr = strstr (line, "PREGAP"))) {
487 			gint64 size_pregap;
488 
489 			ptr += 6;
490 			if (isspace (*ptr)
491 			&&  brasero_image_format_get_MSF_address (ptr, &size_pregap))
492 				cue_size += size_pregap;
493 		}
494 		else if ((ptr = strstr (line, "ZERO"))) {
495 			gint64 size_zero;
496 
497 			ptr += 4;
498 			if (isspace (*ptr)
499 			&&  brasero_image_format_get_MSF_address (ptr, &size_zero))
500 				cue_size += size_zero;
501 		}
502 
503 		g_free (line);
504 	}
505 	g_object_unref (parent);
506 
507 	g_object_unref (stream);
508 	g_object_unref (file);
509 
510 	if (sectors)
511 		*sectors = cue_size;
512 
513 	if (size_img)
514 		*size_img = cue_size * 2352;
515 
516 	return TRUE;
517 }
518 
519 gboolean
brasero_image_format_cue_bin_byte_swap(gchar * uri,GCancellable * cancel,GError ** error)520 brasero_image_format_cue_bin_byte_swap (gchar *uri,
521 					GCancellable *cancel,
522 					GError **error)
523 {
524 	GFile *file;
525 	gchar *line;
526 	GFileInputStream *input;
527 	GDataInputStream *stream;
528 	gboolean is_audio = FALSE;
529 	gboolean is_binary = FALSE;
530 
531 	file = g_file_new_for_uri (uri);
532 	input = g_file_read (file, cancel, error);
533 
534 	if (!input) {
535 		g_object_unref (file);
536 		return FALSE;
537 	}
538 
539 	stream = g_data_input_stream_new (G_INPUT_STREAM (input));
540 	g_object_unref (input);
541 
542 	while ((line = g_data_input_stream_read_line (stream, NULL, cancel, error))) {
543 		const gchar *ptr;
544 
545 		if ((ptr = strstr (line, "FILE"))) {
546 			if (strstr (ptr, "BINARY"))
547 				is_binary = TRUE;
548 		}
549 		else if ((ptr = strstr (line, "TRACK"))) {
550 			if (strstr (ptr, "AUDIO"))
551 				is_audio = TRUE;
552 		}
553 		g_free (line);
554 	}
555 
556 	g_object_unref (stream);
557 	g_object_unref (file);
558 
559 	return is_binary && is_audio;
560 }
561 
562 /**
563  * .cue can use various data files but have to use them ALL. So we don't need
564  * to care about a start/size address. We just go through the whole file and
565  * stat every time we catch a FILE keyword.
566  */
567 
568 gboolean
brasero_image_format_get_cue_size(gchar * uri,guint64 * blocks,guint64 * size_img,GCancellable * cancel,GError ** error)569 brasero_image_format_get_cue_size (gchar *uri,
570 				   guint64 *blocks,
571 				   guint64 *size_img,
572 				   GCancellable *cancel,
573 				   GError **error)
574 {
575 	GFile *file;
576 	gchar *line;
577 	gint64 cue_size = 0;
578 	GFileInputStream *input;
579 	GDataInputStream *stream;
580 
581 	file = g_file_new_for_uri (uri);
582 	input = g_file_read (file, cancel, error);
583 
584 	if (!input) {
585 		g_object_unref (file);
586 		return FALSE;
587 	}
588 
589 	stream = g_data_input_stream_new (G_INPUT_STREAM (input));
590 	g_object_unref (input);
591 
592 	while ((line = g_data_input_stream_read_line (stream, NULL, cancel, error))) {
593 		const gchar *ptr;
594 
595 		if ((ptr = strstr (line, "FILE"))) {
596 			GFileInfo *info;
597 			gchar *file_path;
598 			GFile *file_img = NULL;
599 
600 			ptr += 4;
601 
602 			/* get the path (NOTE: if ptr is NULL file_path as well) */
603 			ptr = brasero_image_format_read_path (ptr, &file_path);
604 			if (!ptr) {
605 				g_object_unref (stream);
606 				g_object_unref (file);
607 				g_free (line);
608 				return FALSE;
609 			}
610 
611 			/* check if the path is relative, if so then add the root path */
612 			if (file_path && !g_path_is_absolute (file_path)) {
613 				GFile *parent;
614 
615 				parent = g_file_get_parent (file);
616 				file_img = g_file_resolve_relative_path (parent, file_path);
617 				g_object_unref (parent);
618 			}
619 			else if (file_path) {
620 				gchar *img_uri;
621 				gchar *scheme;
622 
623 				scheme = g_file_get_uri_scheme (file);
624 				img_uri = g_strconcat (scheme, "://", file_path, NULL);
625 				g_free (scheme);
626 
627 				file_img = g_file_new_for_commandline_arg (img_uri);
628 				g_free (img_uri);
629 			}
630 
631 			g_free (file_path);
632 
633 			/* NOTE: follow symlink if any */
634 			info = g_file_query_info (file_img,
635 						  G_FILE_ATTRIBUTE_STANDARD_SIZE,
636 						  G_FILE_QUERY_INFO_NONE,
637 						  NULL,
638 						  error);
639 			g_object_unref (file_img);
640 
641 			if (!info) {
642 				g_free (line);
643 				g_object_unref (file);
644 				g_object_unref (stream);
645 				return FALSE;
646 			}
647 
648 			cue_size += g_file_info_get_size (info);
649 			g_object_unref (info);
650 		}
651 		else if ((ptr = strstr (line, "PREGAP"))) {
652 			ptr += 6;
653 			if (isspace (*ptr)) {
654 				gint64 size_pregap;
655 
656 				ptr ++;
657 				ptr = brasero_image_format_get_MSF_address (ptr, &size_pregap);
658 				if (ptr)
659 					cue_size += size_pregap * 2352;
660 			}
661 		}
662 		else if ((ptr = strstr (line, "POSTGAP"))) {
663 			ptr += 7;
664 			if (isspace (*ptr)) {
665 				gint64 size_postgap;
666 
667 				ptr ++;
668 				ptr = brasero_image_format_get_MSF_address (ptr, &size_postgap);
669 				if (ptr)
670 					cue_size += size_postgap * 2352;
671 			}
672 		}
673 
674 		g_free (line);
675 	}
676 
677 	g_object_unref (stream);
678 	g_object_unref (file);
679 
680 	if (size_img)
681 		*size_img = cue_size;
682 	if (blocks)
683 		*blocks = BRASERO_BYTES_TO_SECTORS (cue_size, 2352);
684 
685 	return TRUE;
686 }
687 
688 BraseroImageFormat
brasero_image_format_identify_cuesheet(const gchar * uri,GCancellable * cancel,GError ** error)689 brasero_image_format_identify_cuesheet (const gchar *uri,
690 					GCancellable *cancel,
691 					GError **error)
692 {
693 	GFile *file;
694 	gchar *line;
695 	GFileInputStream *input;
696 	GDataInputStream *stream;
697 	BraseroImageFormat format;
698 
699 	file = g_file_new_for_uri (uri);
700 	input = g_file_read (file, cancel, error);
701 	if (!input) {
702 		g_object_unref (file);
703 		return FALSE;
704 	}
705 
706 	stream = g_data_input_stream_new (G_INPUT_STREAM (input));
707 	g_object_unref (input);
708 
709 	format = BRASERO_IMAGE_FORMAT_NONE;
710 	while ((line = g_data_input_stream_read_line (stream, NULL, cancel, error))) {
711 		/* Keywords for cdrdao cuesheets */
712 		if (strstr (line, "CD_ROM_XA")
713 		||  strstr (line, "CD_ROM")
714 		||  strstr (line, "CD_DA")
715 		||  strstr (line, "CD_TEXT")) {
716 			format = BRASERO_IMAGE_FORMAT_CDRDAO;
717 			g_free (line);
718 			break;
719 		}
720 		else if (strstr (line, "TRACK")) {
721 			/* NOTE: there is also "AUDIO" but it's common to both */
722 
723 			/* CDRDAO */
724 			if (strstr (line, "MODE1")
725 			||  strstr (line, "MODE1_RAW")
726 			||  strstr (line, "MODE2_FORM1")
727 			||  strstr (line, "MODE2_FORM2")
728 			||  strstr (line, "MODE_2_RAW")
729 			||  strstr (line, "MODE2_FORM_MIX")
730 			||  strstr (line, "MODE2")) {
731 				format = BRASERO_IMAGE_FORMAT_CDRDAO;
732 				g_free (line);
733 				break;
734 			}
735 
736 			/* .CUE file */
737 			else if (strstr (line, "CDG")
738 			     ||  strstr (line, "MODE1/2048")
739 			     ||  strstr (line, "MODE1/2352")
740 			     ||  strstr (line, "MODE2/2336")
741 			     ||  strstr (line, "MODE2/2352")
742 			     ||  strstr (line, "CDI/2336")
743 			     ||  strstr (line, "CDI/2352")) {
744 				format = BRASERO_IMAGE_FORMAT_CUE;
745 				g_free (line);
746 				break;
747 			}
748 		}
749 		else if (strstr (line, "FILE")) {
750 			if (strstr (line, "MOTOROLA")
751 			||  strstr (line, "BINARY")
752 			||  strstr (line, "AIFF")
753 			||  strstr (line, "WAVE")
754 			||  strstr (line, "MP3")) {
755 				format = BRASERO_IMAGE_FORMAT_CUE;
756 				g_free (line);
757 				break;
758 			}
759 		}
760 		g_free (line);
761 		line = NULL;
762 	}
763 
764 	g_object_unref (stream);
765 	g_object_unref (file);
766 
767 	BRASERO_BURN_LOG_WITH_FULL_TYPE (BRASERO_TRACK_TYPE_IMAGE,
768 					 format,
769 					 BRASERO_BURN_FLAG_NONE,
770 					 "Detected");
771 	return format;
772 }
773 
774 gboolean
brasero_image_format_get_iso_size(gchar * uri,guint64 * blocks,guint64 * size_img,GCancellable * cancel,GError ** error)775 brasero_image_format_get_iso_size (gchar *uri,
776 				   guint64 *blocks,
777 				   guint64 *size_img,
778 				   GCancellable *cancel,
779 				   GError **error)
780 {
781 	GFileInfo *info;
782 	GFile *file;
783 
784 	if (!uri)
785 		return FALSE;
786 
787 	/* NOTE: follow symlink if any */
788 	file = g_file_new_for_uri (uri);
789 	info = g_file_query_info (file,
790 				  G_FILE_ATTRIBUTE_STANDARD_SIZE,
791 				  G_FILE_QUERY_INFO_NONE,
792 				  cancel,
793 				  error);
794 	g_object_unref (file);
795 	if (!info)
796 		return FALSE;
797 
798 	if (size_img)
799 		*size_img = g_file_info_get_size (info);
800 
801 	if (blocks)
802 		*blocks = BRASERO_BYTES_TO_SECTORS (g_file_info_get_size (info), 2048);
803 
804 	g_object_unref (info);
805 	return TRUE;
806 }
807 
808 gboolean
brasero_image_format_get_clone_size(gchar * uri,guint64 * blocks,guint64 * size_img,GCancellable * cancel,GError ** error)809 brasero_image_format_get_clone_size (gchar *uri,
810 				     guint64 *blocks,
811 				     guint64 *size_img,
812 				     GCancellable *cancel,
813 				     GError **error)
814 {
815 	GFileInfo *info;
816 	GFile *file;
817 
818 	if (!uri)
819 		return FALSE;
820 
821 	/* NOTE: follow symlink if any */
822 	file = g_file_new_for_uri (uri);
823 	info = g_file_query_info (file,
824 				  G_FILE_ATTRIBUTE_STANDARD_SIZE,
825 				  G_FILE_QUERY_INFO_NONE,
826 				  cancel,
827 				  error);
828 	g_object_unref (file);
829 
830 	if (!info)
831 		return FALSE;
832 
833 	if (size_img)
834 		*size_img = g_file_info_get_size (info);
835 
836 	if (blocks)
837 		*blocks = BRASERO_BYTES_TO_SECTORS (g_file_info_get_size (info), 2448);
838 
839 	g_object_unref (info);
840 
841 	return TRUE;
842 }
843 
844 gchar *
brasero_image_format_get_default_path(BraseroImageFormat format,const gchar * name)845 brasero_image_format_get_default_path (BraseroImageFormat format,
846 				       const gchar *name)
847 {
848 	const gchar *suffixes [] = {".iso",
849 				    ".toc",
850 				    ".cue",
851 				    ".toc",
852 				    NULL };
853 	const gchar *suffix = NULL;
854 	gchar *path;
855 	gint i = 0;
856 
857 	if (format & BRASERO_IMAGE_FORMAT_BIN)
858 		suffix = suffixes [0];
859 	else if (format & BRASERO_IMAGE_FORMAT_CLONE)
860 		suffix = suffixes [1];
861 	else if (format & BRASERO_IMAGE_FORMAT_CUE)
862 		suffix = suffixes [2];
863 	else if (format & BRASERO_IMAGE_FORMAT_CDRDAO)
864 		suffix = suffixes [3];
865 
866 	path = g_strdup_printf ("%s/%s%s",
867 				g_get_home_dir (),
868 				name? name:"brasero",
869 				suffix);
870 
871 	while (g_file_test (path, G_FILE_TEST_EXISTS)) {
872 		g_free (path);
873 
874 		path = g_strdup_printf ("%s/%s-%i%s",
875 					g_get_home_dir (),
876 					name? name:"brasero",
877 					i,
878 					suffix);
879 		i ++;
880 	}
881 
882 	return path;
883 }
884 
885 gchar *
brasero_image_format_fix_path_extension(BraseroImageFormat format,gboolean check_existence,const gchar * path)886 brasero_image_format_fix_path_extension (BraseroImageFormat format,
887 					 gboolean check_existence,
888 					 const gchar *path)
889 {
890 	gchar *dot;
891 	guint i = 0;
892 	gchar *retval = NULL;
893 	const gchar *suffix = NULL;;
894 	const gchar *suffixes [] = {".iso",
895 				    ".toc",
896 				    ".cue",
897 				    ".toc",
898 				    NULL };
899 
900 	/* search the last dot to check extension */
901 	dot = g_utf8_strrchr (path, -1, '.');
902 	if (dot && strlen (dot) < 5 && strlen (dot) > 1) {
903 		if (format & BRASERO_IMAGE_FORMAT_BIN
904 		&&  strcmp (suffixes [0], dot))
905 			*dot = '\0';
906 		else if (format & BRASERO_IMAGE_FORMAT_CLONE
907 		     &&  strcmp (suffixes [1], dot))
908 			*dot = '\0';
909 		else if (format & BRASERO_IMAGE_FORMAT_CUE
910 		     &&  strcmp (suffixes [2], dot))
911 			*dot = '\0';
912 		else if (format & BRASERO_IMAGE_FORMAT_CDRDAO
913 		     &&  strcmp (suffixes [3], dot))
914 			*dot = '\0';
915 		else
916 			return g_strdup (path);
917 	}
918 
919 	/* determine the proper suffix */
920 	if (format & BRASERO_IMAGE_FORMAT_BIN)
921 		suffix = suffixes [0];
922 	else if (format & BRASERO_IMAGE_FORMAT_CLONE)
923 		suffix = suffixes [1];
924 	else if (format & BRASERO_IMAGE_FORMAT_CUE)
925 		suffix = suffixes [2];
926 	else if (format & BRASERO_IMAGE_FORMAT_CDRDAO)
927 		suffix = suffixes [3];
928 	else
929 		return g_strdup (path);
930 
931 	/* make sure the file doesn't exist */
932 	retval = g_strdup_printf ("%s%s", path, suffix);
933 	if (!check_existence)
934 		return retval;
935 
936 	while (g_file_test (retval, G_FILE_TEST_EXISTS)) {
937 		g_free (retval);
938 		retval = g_strdup_printf ("%s-%i%s", path, i, suffix);
939 		i ++;
940 	}
941 
942 	return retval;
943 }
944