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 <string.h>
36 
37 #include <glib.h>
38 
39 #include "brasero-media.h"
40 #include "brasero-media-private.h"
41 
42 #include "burn-caps.h"
43 #include "burn-debug.h"
44 
45 #include "brasero-plugin-private.h"
46 #include "brasero-plugin-information.h"
47 
48 #define SUBSTRACT(a, b)		((a) &= ~((b)&(a)))
49 
50 /**
51  * the following functions are used to register new caps
52  */
53 
54 static BraseroCapsLink *
brasero_caps_find_link_for_input(BraseroCaps * caps,BraseroCaps * input)55 brasero_caps_find_link_for_input (BraseroCaps *caps,
56 				  BraseroCaps *input)
57 {
58 	GSList *links;
59 
60 	for (links = caps->links; links; links = links->next) {
61 		BraseroCapsLink *link;
62 
63 		link = links->data;
64 		if (link->caps == input)
65 			return link;
66 	}
67 
68 	return NULL;
69 }
70 
71 static gint
brasero_burn_caps_sort(gconstpointer a,gconstpointer b)72 brasero_burn_caps_sort (gconstpointer a, gconstpointer b)
73 {
74 	const BraseroCaps *caps_a = a;
75 	const BraseroCaps *caps_b = b;
76 	gint result;
77 
78 	/* First put DISC (the most used caps) then AUDIO then IMAGE type; these
79 	 * two types are the ones that most often searched. At the end of the
80 	 * list we put DATA.
81 	 * Another (sub)rule is that for DATA, DISC, AUDIO we put a caps that is
82 	 * encompassed by another before.
83 	 */
84 
85 	result = caps_b->type.type - caps_a->type.type;
86 	if (result)
87 		return result;
88 
89 	switch (caps_a->type.type) {
90 	case BRASERO_TRACK_TYPE_DISC:
91 		if (BRASERO_MEDIUM_TYPE (caps_a->type.subtype.media) !=
92 		    BRASERO_MEDIUM_TYPE (caps_b->type.subtype.media))
93 			return ((gint32) BRASERO_MEDIUM_TYPE (caps_a->type.subtype.media) -
94 			        (gint32) BRASERO_MEDIUM_TYPE (caps_b->type.subtype.media));
95 
96 		if ((caps_a->type.subtype.media & BRASERO_MEDIUM_DVD)
97 		&&  BRASERO_MEDIUM_SUBTYPE (caps_a->type.subtype.media) !=
98 		    BRASERO_MEDIUM_SUBTYPE (caps_b->type.subtype.media))
99 			return ((gint32) BRASERO_MEDIUM_SUBTYPE (caps_a->type.subtype.media) -
100 			        (gint32) BRASERO_MEDIUM_SUBTYPE (caps_b->type.subtype.media));
101 
102 		if (BRASERO_MEDIUM_ATTR (caps_a->type.subtype.media) !=
103 		    BRASERO_MEDIUM_ATTR (caps_b->type.subtype.media))
104 			return BRASERO_MEDIUM_ATTR (caps_a->type.subtype.media) -
105 			       BRASERO_MEDIUM_ATTR (caps_b->type.subtype.media);
106 
107 		if (BRASERO_MEDIUM_STATUS (caps_a->type.subtype.media) !=
108 		    BRASERO_MEDIUM_STATUS (caps_b->type.subtype.media))
109 			return BRASERO_MEDIUM_STATUS (caps_a->type.subtype.media) -
110 			       BRASERO_MEDIUM_STATUS (caps_b->type.subtype.media);
111 
112 		return (BRASERO_MEDIUM_INFO (caps_a->type.subtype.media) -
113 			BRASERO_MEDIUM_INFO (caps_b->type.subtype.media));
114 
115 	case BRASERO_TRACK_TYPE_IMAGE:
116 		/* This way BIN subtype is always sorted at the end */
117 		return caps_a->type.subtype.img_format - caps_b->type.subtype.img_format;
118 
119 	case BRASERO_TRACK_TYPE_STREAM:
120 		if (caps_a->type.subtype.stream_format != caps_b->type.subtype.stream_format) {
121 			result = (caps_a->type.subtype.stream_format & caps_b->type.subtype.stream_format);
122 			if (result == caps_a->type.subtype.stream_format)
123 				return -1;
124 			else if (result == caps_b->type.subtype.stream_format)
125 				return 1;
126 
127 			return  (gint32) caps_a->type.subtype.stream_format -
128 				(gint32) caps_b->type.subtype.stream_format;
129 		}
130 		break;
131 
132 	case BRASERO_TRACK_TYPE_DATA:
133 		result = (caps_a->type.subtype.fs_type & caps_b->type.subtype.fs_type);
134 		if (result == caps_a->type.subtype.fs_type)
135 			return -1;
136 		else if (result == caps_b->type.subtype.fs_type)
137 			return 1;
138 
139 		return (caps_a->type.subtype.fs_type - caps_b->type.subtype.fs_type);
140 
141 	default:
142 		break;
143 	}
144 
145 	return 0;
146 }
147 
148 static BraseroCapsLink *
brasero_caps_link_copy(BraseroCapsLink * link)149 brasero_caps_link_copy (BraseroCapsLink *link)
150 {
151 	BraseroCapsLink *retval;
152 
153 	retval = g_new0 (BraseroCapsLink, 1);
154 	retval->plugins = g_slist_copy (link->plugins);
155 	retval->caps = link->caps;
156 
157 	return retval;
158 }
159 
160 static void
brasero_caps_link_list_duplicate(BraseroCaps * dest,BraseroCaps * src)161 brasero_caps_link_list_duplicate (BraseroCaps *dest, BraseroCaps *src)
162 {
163 	GSList *iter;
164 
165 	for (iter = src->links; iter; iter = iter->next) {
166 		BraseroCapsLink *link;
167 
168 		link = iter->data;
169 		dest->links = g_slist_prepend (dest->links, brasero_caps_link_copy (link));
170 	}
171 }
172 
173 static BraseroCaps *
brasero_caps_duplicate(BraseroCaps * caps)174 brasero_caps_duplicate (BraseroCaps *caps)
175 {
176 	BraseroCaps *retval;
177 
178 	retval = g_new0 (BraseroCaps, 1);
179 	retval->flags = caps->flags;
180 	memcpy (&retval->type, &caps->type, sizeof (BraseroTrackType));
181 	retval->modifiers = g_slist_copy (caps->modifiers);
182 
183 	return retval;
184 }
185 
186 static void
brasero_caps_replicate_modifiers(BraseroCaps * dest,BraseroCaps * src)187 brasero_caps_replicate_modifiers (BraseroCaps *dest, BraseroCaps *src)
188 {
189 	GSList *iter;
190 
191 	for (iter = src->modifiers; iter; iter = iter->next) {
192 		BraseroPlugin *plugin;
193 
194 		plugin = iter->data;
195 
196 		if (g_slist_find (dest->modifiers, plugin))
197 			continue;
198 
199 		dest->modifiers = g_slist_prepend (dest->modifiers, plugin);
200 	}
201 }
202 
203 static void
brasero_caps_replicate_links(BraseroBurnCaps * self,BraseroCaps * dest,BraseroCaps * src)204 brasero_caps_replicate_links (BraseroBurnCaps *self,
205 			      BraseroCaps *dest,
206 			      BraseroCaps *src)
207 {
208 	GSList *iter;
209 
210 	brasero_caps_link_list_duplicate (dest, src);
211 
212 	for (iter = self->priv->caps_list; iter; iter = iter->next) {
213 		BraseroCaps *iter_caps;
214 		GSList *links;
215 
216 		iter_caps = iter->data;
217 		if (iter_caps == src)
218 			continue;
219 
220 		for (links = iter_caps->links; links; links = links->next) {
221 			BraseroCapsLink *link;
222 
223 			link = links->data;
224 			if (link->caps == src) {
225 				BraseroCapsLink *copy;
226 
227 				copy = brasero_caps_link_copy (link);
228 				copy->caps = dest;
229 				iter_caps->links = g_slist_prepend (iter_caps->links, copy);
230 			}
231 		}
232 	}
233 }
234 
235 static void
brasero_caps_replicate_tests(BraseroBurnCaps * self,BraseroCaps * dest,BraseroCaps * src)236 brasero_caps_replicate_tests (BraseroBurnCaps *self,
237 			      BraseroCaps *dest,
238 			      BraseroCaps *src)
239 {
240 	GSList *iter;
241 
242 	for (iter = self->priv->tests; iter; iter = iter->next) {
243 		BraseroCapsTest *test;
244 		GSList *links;
245 
246 		test = iter->data;
247 		for (links = test->links; links; links = links->next) {
248 			BraseroCapsLink *link;
249 
250 			link = links->data;
251 			if (link->caps == src) {
252 				BraseroCapsLink *copy;
253 
254 				copy = brasero_caps_link_copy (link);
255 				copy->caps = dest;
256 				test->links = g_slist_prepend (test->links, copy);
257 			}
258 		}
259 	}
260 }
261 
262 static void
brasero_caps_copy_deep(BraseroBurnCaps * self,BraseroCaps * dest,BraseroCaps * src)263 brasero_caps_copy_deep (BraseroBurnCaps *self,
264 			BraseroCaps *dest,
265 			BraseroCaps *src)
266 {
267 	brasero_caps_replicate_links (self, dest, src);
268 	brasero_caps_replicate_tests (self, dest, src);
269 	brasero_caps_replicate_modifiers (dest,src);
270 }
271 
272 static BraseroCaps *
brasero_caps_duplicate_deep(BraseroBurnCaps * self,BraseroCaps * caps)273 brasero_caps_duplicate_deep (BraseroBurnCaps *self,
274 			     BraseroCaps *caps)
275 {
276 	BraseroCaps *retval;
277 
278 	retval = brasero_caps_duplicate (caps);
279 	brasero_caps_copy_deep (self, retval, caps);
280 	return retval;
281 }
282 
283 static GSList *
brasero_caps_list_check_io(BraseroBurnCaps * self,GSList * list,BraseroPluginIOFlag flags)284 brasero_caps_list_check_io (BraseroBurnCaps *self,
285 			    GSList *list,
286 			    BraseroPluginIOFlag flags)
287 {
288 	GSList *iter;
289 
290 	/* in this function we create the caps with the missing IO. All in the
291 	 * list have something in common with flags. */
292 	for (iter = list; iter; iter = iter->next) {
293 		BraseroCaps *caps;
294 		BraseroPluginIOFlag common;
295 
296 		caps = iter->data;
297 		common = caps->flags & flags;
298 		if (common != caps->flags) {
299 			BraseroCaps *new_caps;
300 
301 			/* (common == flags) && common != caps->flags
302 			 * caps->flags encompasses flags: Split the caps in two
303 			 * and only keep the interesting part */
304 			caps->flags &= ~common;
305 
306 			/* this caps has changed and needs to be sorted again */
307 			self->priv->caps_list = g_slist_sort (self->priv->caps_list,
308 							      brasero_burn_caps_sort);
309 
310 			new_caps = brasero_caps_duplicate_deep (self, caps);
311 			new_caps->flags = common;
312 
313 			self->priv->caps_list = g_slist_insert_sorted (self->priv->caps_list,
314 								       new_caps,
315 								       brasero_burn_caps_sort);
316 
317 			list = g_slist_prepend (list, new_caps);
318 		}
319 		else if (common != flags) {
320 			GSList *node, *next;
321 			BraseroPluginIOFlag complement = flags;
322 
323 			complement &= ~common;
324 			for (node = list; node; node = next) {
325 				BraseroCaps *tmp;
326 
327 				tmp = node->data;
328 				next = node->next;
329 
330 				if (node == iter)
331 					continue;
332 
333 				if (caps->type.type != tmp->type.type
334 				||  caps->type.subtype.media != tmp->type.subtype.media)
335 					continue;
336 
337 				/* substract the flags and relocate them at the
338 				 * head of the list since we don't need to look
339 				 * them up again */
340 				complement &= ~(tmp->flags);
341 				list = g_slist_remove (list, tmp);
342 				list = g_slist_prepend (list, tmp);
343 			}
344 
345 			if (complement != BRASERO_PLUGIN_IO_NONE) {
346 				BraseroCaps *new_caps;
347 
348 				/* common == caps->flags && common != flags.
349 				 * Flags encompasses caps->flags. So we need to
350 				 * create a new caps for this type with the
351 				 * substraction of flags if the other part isn't
352 				 * in the list */
353 				new_caps = brasero_caps_duplicate (caps);
354 				new_caps->flags = flags & (~common);
355 				self->priv->caps_list = g_slist_insert_sorted (self->priv->caps_list,
356 									       new_caps,
357 									       brasero_burn_caps_sort);
358 
359 				list = g_slist_prepend (list, new_caps);
360 			}
361 		}
362 	}
363 
364 	return list;
365 }
366 
367 GSList *
brasero_caps_image_new(BraseroPluginIOFlag flags,BraseroImageFormat format)368 brasero_caps_image_new (BraseroPluginIOFlag flags,
369 			BraseroImageFormat format)
370 {
371 	BraseroImageFormat remaining_format;
372 	BraseroBurnCaps *self;
373 	GSList *retval = NULL;
374 	GSList *iter;
375 
376 	BRASERO_BURN_LOG_WITH_FULL_TYPE (BRASERO_TRACK_TYPE_IMAGE,
377 					 format,
378 					 flags,
379 					 "New caps required");
380 
381 	self = brasero_burn_caps_get_default ();
382 
383 	remaining_format = format;
384 
385 	/* We have to search all caps with or related to the format */
386 	for (iter = self->priv->caps_list; iter; iter = iter->next) {
387 		BraseroCaps *caps;
388 		BraseroImageFormat common;
389 		BraseroPluginIOFlag common_io;
390 
391 		caps = iter->data;
392 		if (caps->type.type != BRASERO_TRACK_TYPE_IMAGE)
393 			continue;
394 
395 		common_io = caps->flags & flags;
396 		if (common_io == BRASERO_PLUGIN_IO_NONE)
397 			continue;
398 
399 		common = (caps->type.subtype.img_format & format);
400 		if (common == BRASERO_IMAGE_FORMAT_NONE)
401 			continue;
402 
403 		if (common != caps->type.subtype.img_format) {
404 			/* img_format encompasses format. Split it in two and
405 			 * keep caps with common format */
406 			SUBSTRACT (caps->type.subtype.img_format, common);
407 			self->priv->caps_list = g_slist_sort (self->priv->caps_list,
408 							      brasero_burn_caps_sort);
409 
410 			caps = brasero_caps_duplicate_deep (self, caps);
411 			caps->type.subtype.img_format = common;
412 
413 			self->priv->caps_list = g_slist_insert_sorted (self->priv->caps_list,
414 								       caps,
415 								       brasero_burn_caps_sort);
416 		}
417 
418 		retval = g_slist_prepend (retval, caps);
419 		remaining_format &= ~common;
420 	}
421 
422 	/* Now we make sure that all these new or already
423 	 * existing caps have the proper IO Flags */
424 	retval = brasero_caps_list_check_io (self, retval, flags);
425 
426 	if (remaining_format != BRASERO_IMAGE_FORMAT_NONE) {
427 		BraseroCaps *caps;
428 
429 		caps = g_new0 (BraseroCaps, 1);
430 		caps->flags = flags;
431 		caps->type.subtype.img_format = remaining_format;
432 		caps->type.type = BRASERO_TRACK_TYPE_IMAGE;
433 
434 		self->priv->caps_list = g_slist_insert_sorted (self->priv->caps_list,
435 							       caps,
436 							       brasero_burn_caps_sort);
437 		retval = g_slist_prepend (retval, caps);
438 
439 		BRASERO_BURN_LOG_TYPE (&caps->type, "Created new caps");
440 	}
441 
442 	g_object_unref (self);
443 	return retval;
444 }
445 
446 GSList *
brasero_caps_audio_new(BraseroPluginIOFlag flags,BraseroStreamFormat format)447 brasero_caps_audio_new (BraseroPluginIOFlag flags,
448 			BraseroStreamFormat format)
449 {
450 	GSList *iter;
451 	GSList *retval = NULL;
452 	BraseroBurnCaps *self;
453 	GSList *encompassing = NULL;
454 	gboolean have_the_one = FALSE;
455 
456 	BRASERO_BURN_LOG_WITH_FULL_TYPE (BRASERO_TRACK_TYPE_STREAM,
457 					 format,
458 					 flags,
459 					 "New caps required");
460 
461 	self = brasero_burn_caps_get_default ();
462 
463 	for (iter = self->priv->caps_list; iter; iter = iter->next) {
464 		BraseroCaps *caps;
465 		BraseroStreamFormat common;
466 		BraseroPluginIOFlag common_io;
467 		BraseroStreamFormat common_audio;
468 		BraseroStreamFormat common_video;
469 
470 		caps = iter->data;
471 
472 		if (caps->type.type != BRASERO_TRACK_TYPE_STREAM)
473 			continue;
474 
475 		common_io = (flags & caps->flags);
476 		if (common_io == BRASERO_PLUGIN_IO_NONE)
477 			continue;
478 
479 		if (caps->type.subtype.stream_format == format) {
480 			/* that's the perfect fit */
481 			have_the_one = TRUE;
482 			retval = g_slist_prepend (retval, caps);
483 			continue;
484 		}
485 
486 		/* Search caps strictly encompassed or encompassing our format
487 		 * NOTE: make sure that if there is a VIDEO stream in one of
488 		 * them, the other does have a VIDEO stream too. */
489 		common_audio = BRASERO_STREAM_FORMAT_AUDIO (caps->type.subtype.stream_format) &
490 			       BRASERO_STREAM_FORMAT_AUDIO (format);
491 		if (common_audio == BRASERO_AUDIO_FORMAT_NONE
492 		&& (BRASERO_STREAM_FORMAT_AUDIO (caps->type.subtype.stream_format)
493 		||  BRASERO_STREAM_FORMAT_AUDIO (format)))
494 			continue;
495 
496 		common_video = BRASERO_STREAM_FORMAT_VIDEO (caps->type.subtype.stream_format) &
497 			       BRASERO_STREAM_FORMAT_VIDEO (format);
498 
499 		if (common_video == BRASERO_AUDIO_FORMAT_NONE
500 		&& (BRASERO_STREAM_FORMAT_VIDEO (caps->type.subtype.stream_format)
501 		||  BRASERO_STREAM_FORMAT_VIDEO (format)))
502 			continue;
503 
504 		/* Likewise... that must be common */
505 		if ((caps->type.subtype.stream_format & BRASERO_METADATA_INFO) != (format & BRASERO_METADATA_INFO))
506 			continue;
507 
508 		common = common_audio|common_video|(format & BRASERO_METADATA_INFO);
509 
510 		/* encompassed caps just add it to retval */
511 		if (caps->type.subtype.stream_format == common)
512 			retval = g_slist_prepend (retval, caps);
513 
514 		/* encompassing caps keep it if we need to create perfect fit */
515 		if (format == common)
516 			encompassing = g_slist_prepend (encompassing, caps);
517 	}
518 
519 	/* Now we make sure that all these new or already
520 	 * existing caps have the proper IO Flags */
521 	retval = brasero_caps_list_check_io (self, retval, flags);
522 
523 	if (!have_the_one) {
524 		BraseroCaps *caps;
525 
526 		caps = g_new0 (BraseroCaps, 1);
527 		caps->flags = flags;
528 		caps->type.subtype.stream_format = format;
529 		caps->type.type = BRASERO_TRACK_TYPE_STREAM;
530 
531 		if (encompassing) {
532 			for (iter = encompassing; iter; iter = iter->next) {
533 				BraseroCaps *iter_caps;
534 
535 				iter_caps = iter->data;
536 				brasero_caps_copy_deep (self, caps, iter_caps);
537 			}
538 		}
539 
540 		self->priv->caps_list = g_slist_insert_sorted (self->priv->caps_list,
541 							       caps,
542 							       brasero_burn_caps_sort);
543 		retval = g_slist_prepend (retval, caps);
544 
545 		BRASERO_BURN_LOG_TYPE (&caps->type, "Created new caps");
546 	}
547 
548 	g_slist_free (encompassing);
549 
550 	g_object_unref (self);
551 
552 	return retval;
553 }
554 
555 GSList *
brasero_caps_data_new(BraseroImageFS fs_type)556 brasero_caps_data_new (BraseroImageFS fs_type)
557 {
558 	GSList *iter;
559 	GSList *retval = NULL;
560 	BraseroBurnCaps *self;
561 	GSList *encompassing = NULL;
562 	gboolean have_the_one = FALSE;
563 
564 	BRASERO_BURN_LOG_WITH_FULL_TYPE (BRASERO_TRACK_TYPE_DATA,
565 					 fs_type,
566 					 BRASERO_PLUGIN_IO_NONE,
567 					 "New caps required");
568 
569 	self = brasero_burn_caps_get_default ();
570 
571 	for (iter = self->priv->caps_list; iter; iter = iter->next) {
572 		BraseroCaps *caps;
573 		BraseroImageFS common;
574 
575 		caps = iter->data;
576 
577 		if (caps->type.type != BRASERO_TRACK_TYPE_DATA)
578 			continue;
579 
580 		if (caps->type.subtype.fs_type == fs_type) {
581 			/* that's the perfect fit */
582 			have_the_one = TRUE;
583 			retval = g_slist_prepend (retval, caps);
584 			continue;
585 		}
586 
587 		/* search caps strictly encompassing our format ... */
588 		common = caps->type.subtype.fs_type & fs_type;
589 		if (common == BRASERO_IMAGE_FS_NONE)
590 			continue;
591 
592 		/* encompassed caps just add it to retval */
593 		if (caps->type.subtype.fs_type == common)
594 			retval = g_slist_prepend (retval, caps);
595 
596 		/* encompassing caps keep it if we need to create perfect fit */
597 		if (fs_type == common)
598 			encompassing = g_slist_prepend (encompassing, caps);
599 	}
600 
601 	if (!have_the_one) {
602 		BraseroCaps *caps;
603 
604 		caps = g_new0 (BraseroCaps, 1);
605 		caps->flags = BRASERO_PLUGIN_IO_ACCEPT_FILE;
606 		caps->type.type = BRASERO_TRACK_TYPE_DATA;
607 		caps->type.subtype.fs_type = fs_type;
608 
609 		if (encompassing) {
610 			for (iter = encompassing; iter; iter = iter->next) {
611 				BraseroCaps *iter_caps;
612 
613 				iter_caps = iter->data;
614 				brasero_caps_copy_deep (self, caps, iter_caps);
615 			}
616 		}
617 
618 		self->priv->caps_list = g_slist_insert_sorted (self->priv->caps_list,
619 							       caps,
620 							       brasero_burn_caps_sort);
621 		retval = g_slist_prepend (retval, caps);
622 	}
623 
624 	g_slist_free (encompassing);
625 
626 	g_object_unref (self);
627 
628 	return retval;
629 }
630 
631 static GSList *
brasero_caps_disc_lookup_or_create(BraseroBurnCaps * self,GSList * retval,BraseroMedia media)632 brasero_caps_disc_lookup_or_create (BraseroBurnCaps *self,
633 				    GSList *retval,
634 				    BraseroMedia media)
635 {
636 	GSList *iter;
637 	BraseroCaps *caps;
638 
639 	for (iter = self->priv->caps_list; iter; iter = iter->next) {
640 		caps = iter->data;
641 
642 		if (caps->type.type != BRASERO_TRACK_TYPE_DISC)
643 			continue;
644 
645 		if (caps->type.subtype.media == media) {
646 			BRASERO_BURN_LOG_WITH_TYPE (&caps->type,
647 						    caps->flags,
648 						    "Retrieved");
649 			return g_slist_prepend (retval, caps);
650 		}
651 	}
652 
653 	caps = g_new0 (BraseroCaps, 1);
654 	caps->flags = BRASERO_PLUGIN_IO_ACCEPT_FILE;
655 	caps->type.type = BRASERO_TRACK_TYPE_DISC;
656 	caps->type.subtype.media = media;
657 
658 	BRASERO_BURN_LOG_WITH_TYPE (&caps->type,
659 				    caps->flags,
660 				    "Created");
661 
662 	self->priv->caps_list = g_slist_prepend (self->priv->caps_list, caps);
663 
664 	return g_slist_prepend (retval, caps);
665 }
666 
667 GSList *
brasero_caps_disc_new(BraseroMedia type)668 brasero_caps_disc_new (BraseroMedia type)
669 {
670 	BraseroBurnCaps *self;
671 	GSList *retval = NULL;
672 	GSList *list;
673 	GSList *iter;
674 
675 	self = brasero_burn_caps_get_default ();
676 
677 	list = brasero_media_get_all_list (type);
678 	for (iter = list; iter; iter = iter->next) {
679 		BraseroMedia medium;
680 
681 		medium = GPOINTER_TO_INT (iter->data);
682 		retval = brasero_caps_disc_lookup_or_create (self, retval, medium);
683 	}
684 	g_slist_free (list);
685 
686 	g_object_unref (self);
687 	return retval;
688 }
689 
690 /**
691  * these functions are to create links
692  */
693 
694 static void
brasero_caps_create_links(BraseroCaps * output,GSList * inputs,BraseroPlugin * plugin)695 brasero_caps_create_links (BraseroCaps *output,
696 	 		   GSList *inputs,
697 	 		   BraseroPlugin *plugin)
698 {
699 	for (; inputs; inputs = inputs->next) {
700 		BraseroCaps *input;
701 		BraseroCapsLink *link;
702 
703 		input = inputs->data;
704 
705 		if (output == input) {
706 			BRASERO_BURN_LOG ("Same input and output for link. Dropping");
707 			continue;
708 		}
709 
710 		if (input->flags == output->flags
711 		&&  input->type.type == output->type.type
712 		&&  input->type.subtype.media == output->type.subtype.media)
713 			BRASERO_BURN_LOG ("Recursive link");
714 
715 		link = brasero_caps_find_link_for_input (output, input);
716 
717 #if 0
718 
719 		/* Mainly for extra debugging */
720 		BRASERO_BURN_LOG_TYPE (&output->type, "Linking");
721 		BRASERO_BURN_LOG_TYPE (&input->type, "to");
722 		BRASERO_BURN_LOG ("with %s", brasero_plugin_get_name (plugin));
723 
724 #endif
725 
726 		if (!link) {
727 			link = g_new0 (BraseroCapsLink, 1);
728 			link->caps = input;
729 			link->plugins = g_slist_prepend (NULL, plugin);
730 
731 			output->links = g_slist_prepend (output->links, link);
732 		}
733 		else
734 			link->plugins = g_slist_prepend (link->plugins, plugin);
735 	}
736 }
737 
738 void
brasero_plugin_link_caps(BraseroPlugin * plugin,GSList * outputs,GSList * inputs)739 brasero_plugin_link_caps (BraseroPlugin *plugin,
740 			  GSList *outputs,
741 			  GSList *inputs)
742 {
743 	/* we make sure the caps exists and if not we create them */
744 	for (; outputs; outputs = outputs->next) {
745 		BraseroCaps *output;
746 
747 		output = outputs->data;
748 		brasero_caps_create_links (output, inputs, plugin);
749 	}
750 }
751 
752 void
brasero_plugin_blank_caps(BraseroPlugin * plugin,GSList * caps_list)753 brasero_plugin_blank_caps (BraseroPlugin *plugin,
754 			   GSList *caps_list)
755 {
756 	for (; caps_list; caps_list = caps_list->next) {
757 		BraseroCaps *caps;
758 		BraseroCapsLink *link;
759 
760 		caps = caps_list->data;
761 
762 		if (caps->type.type != BRASERO_TRACK_TYPE_DISC)
763 			continue;
764 
765 		BRASERO_BURN_LOG_WITH_TYPE (&caps->type,
766 					    caps->flags,
767 					    "Adding blank caps for");
768 
769 		/* we need to find the link whose caps is NULL */
770 		link = brasero_caps_find_link_for_input (caps, NULL);
771 		if (!link) {
772 			link = g_new0 (BraseroCapsLink, 1);
773 			link->caps = NULL;
774 			link->plugins = g_slist_prepend (NULL, plugin);
775 
776 			caps->links = g_slist_prepend (caps->links, link);
777 		}
778 		else
779 			link->plugins = g_slist_prepend (link->plugins, plugin);
780 	}
781 }
782 
783 void
brasero_plugin_process_caps(BraseroPlugin * plugin,GSList * caps_list)784 brasero_plugin_process_caps (BraseroPlugin *plugin,
785 			     GSList *caps_list)
786 {
787 	for (; caps_list; caps_list = caps_list->next) {
788 		BraseroCaps *caps;
789 
790 		caps = caps_list->data;
791 		caps->modifiers = g_slist_prepend (caps->modifiers, plugin);
792 	}
793 }
794 
795 void
brasero_plugin_check_caps(BraseroPlugin * plugin,BraseroChecksumType type,GSList * caps_list)796 brasero_plugin_check_caps (BraseroPlugin *plugin,
797 			   BraseroChecksumType type,
798 			   GSList *caps_list)
799 {
800 	BraseroCapsTest *test = NULL;
801 	BraseroBurnCaps *self;
802 	GSList *iter;
803 
804 	/* Find the the BraseroCapsTest for this type; if none create it */
805 	self = brasero_burn_caps_get_default ();
806 
807 	for (iter = self->priv->tests; iter; iter = iter->next) {
808 		BraseroCapsTest *tmp;
809 
810 		tmp = iter->data;
811 		if (tmp->type == type) {
812 			test = tmp;
813 			break;
814 		}
815 	}
816 
817 	if (!test) {
818 		test = g_new0 (BraseroCapsTest, 1);
819 		test->type = type;
820 		self->priv->tests = g_slist_prepend (self->priv->tests, test);
821 	}
822 
823 	g_object_unref (self);
824 
825 	for (; caps_list; caps_list = caps_list->next) {
826 		GSList *links;
827 		BraseroCaps *caps;
828 		BraseroCapsLink *link;
829 
830 		caps = caps_list->data;
831 
832 		/* try to find a link for the above caps, if none create one */
833 		link = NULL;
834 		for (links = test->links; links; links = links->next) {
835 			BraseroCapsLink *tmp;
836 
837 			tmp = links->data;
838 			if (tmp->caps == caps) {
839 				link = tmp;
840 				break;
841 			}
842 		}
843 
844 		if (!link) {
845 			link = g_new0 (BraseroCapsLink, 1);
846 			link->caps = caps;
847 			test->links = g_slist_prepend (test->links, link);
848 		}
849 
850 		link->plugins = g_slist_prepend (link->plugins, plugin);
851 	}
852 }
853 
854 void
brasero_plugin_register_group(BraseroPlugin * plugin,const gchar * name)855 brasero_plugin_register_group (BraseroPlugin *plugin,
856 			       const gchar *name)
857 {
858 	guint retval;
859 	BraseroBurnCaps *self;
860 
861 	if (!name) {
862 		brasero_plugin_set_group (plugin, 0);
863 		return;
864 	}
865 
866 	self = brasero_burn_caps_get_default ();
867 
868 	if (!self->priv->groups)
869 		self->priv->groups = g_hash_table_new_full (g_str_hash,
870 							    g_str_equal,
871 							    g_free,
872 							    NULL);
873 
874 	retval = GPOINTER_TO_INT (g_hash_table_lookup (self->priv->groups, name));
875 	if (retval) {
876 		brasero_plugin_set_group (plugin, retval);
877 		g_object_unref (self);
878 		return;
879 	}
880 
881 	g_hash_table_insert (self->priv->groups,
882 			     g_strdup (name),
883 			     GINT_TO_POINTER (g_hash_table_size (self->priv->groups) + 1));
884 
885 	/* see if we have a group id now */
886 	if (!self->priv->group_id
887 	&&   self->priv->group_str
888 	&&  !strcmp (name, self->priv->group_str))
889 		self->priv->group_id = g_hash_table_size (self->priv->groups) + 1;
890 
891 	brasero_plugin_set_group (plugin, g_hash_table_size (self->priv->groups) + 1);
892 
893 	g_object_unref (self);
894 }
895 
896 /**
897  * This is to find out what are the capacities of a plugin
898  * Declared in brasero-plugin-private.h
899  */
900 
901 BraseroBurnResult
brasero_plugin_can_burn(BraseroPlugin * plugin)902 brasero_plugin_can_burn (BraseroPlugin *plugin)
903 {
904 	GSList *iter;
905 	BraseroBurnCaps *self;
906 
907 	self = brasero_burn_caps_get_default ();
908 
909 	for (iter = self->priv->caps_list; iter; iter = iter->next) {
910 		BraseroCaps *caps;
911 		GSList *links;
912 
913 		caps = iter->data;
914 		if (caps->type.type != BRASERO_TRACK_TYPE_DISC)
915 			continue;
916 
917 		for (links = caps->links; links; links = links->next) {
918 			BraseroCapsLink *link;
919 			GSList *plugins;
920 
921 			link = links->data;
922 
923 			/* see if the plugin is in the link by going through the list */
924 			for (plugins = link->plugins; plugins; plugins = plugins->next) {
925 				BraseroPlugin *tmp;
926 
927 				tmp = plugins->data;
928 				if (tmp == plugin) {
929 					g_object_unref (self);
930 					return BRASERO_BURN_OK;
931 				}
932 			}
933 		}
934 	}
935 
936 	g_object_unref (self);
937 	return BRASERO_BURN_NOT_SUPPORTED;
938 }
939 
940 BraseroBurnResult
brasero_plugin_can_image(BraseroPlugin * plugin)941 brasero_plugin_can_image (BraseroPlugin *plugin)
942 {
943 	GSList *iter;
944 	BraseroBurnCaps *self;
945 
946 	self = brasero_burn_caps_get_default ();
947 	for (iter = self->priv->caps_list; iter; iter = iter->next) {
948 		BraseroTrackDataType destination;
949 		BraseroCaps *caps;
950 		GSList *links;
951 
952 		caps = iter->data;
953 		if (caps->type.type != BRASERO_TRACK_TYPE_IMAGE
954 		&&  caps->type.type != BRASERO_TRACK_TYPE_STREAM
955 		&&  caps->type.type != BRASERO_TRACK_TYPE_DATA)
956 			continue;
957 
958 		destination = caps->type.type;
959 		for (links = caps->links; links; links = links->next) {
960 			BraseroCapsLink *link;
961 			GSList *plugins;
962 
963 			link = links->data;
964 			if (!link->caps
965 			||   link->caps->type.type == destination)
966 				continue;
967 
968 			/* see if the plugin is in the link by going through the list */
969 			for (plugins = link->plugins; plugins; plugins = plugins->next) {
970 				BraseroPlugin *tmp;
971 
972 				tmp = plugins->data;
973 				if (tmp == plugin) {
974 					g_object_unref (self);
975 					return BRASERO_BURN_OK;
976 				}
977 			}
978 		}
979 	}
980 
981 	g_object_unref (self);
982 	return BRASERO_BURN_NOT_SUPPORTED;
983 }
984 
985 BraseroBurnResult
brasero_plugin_can_convert(BraseroPlugin * plugin)986 brasero_plugin_can_convert (BraseroPlugin *plugin)
987 {
988 	GSList *iter;
989 	BraseroBurnCaps *self;
990 
991 	self = brasero_burn_caps_get_default ();
992 
993 	for (iter = self->priv->caps_list; iter; iter = iter->next) {
994 		BraseroTrackDataType destination;
995 		BraseroCaps *caps;
996 		GSList *links;
997 
998 		caps = iter->data;
999 		if (caps->type.type != BRASERO_TRACK_TYPE_IMAGE
1000 		&&  caps->type.type != BRASERO_TRACK_TYPE_STREAM)
1001 			continue;
1002 
1003 		destination = caps->type.type;
1004 		for (links = caps->links; links; links = links->next) {
1005 			BraseroCapsLink *link;
1006 			GSList *plugins;
1007 
1008 			link = links->data;
1009 			if (!link->caps
1010 			||   link->caps->type.type != destination)
1011 				continue;
1012 
1013 			/* see if the plugin is in the link by going through the list */
1014 			for (plugins = link->plugins; plugins; plugins = plugins->next) {
1015 				BraseroPlugin *tmp;
1016 
1017 				tmp = plugins->data;
1018 				if (tmp == plugin) {
1019 					g_object_unref (self);
1020 					return BRASERO_BURN_OK;
1021 				}
1022 			}
1023 		}
1024 	}
1025 
1026 	g_object_unref (self);
1027 
1028 	return BRASERO_BURN_NOT_SUPPORTED;
1029 }
1030 
1031