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-track.h"
40 
41 
42 typedef struct _BraseroTrackPrivate BraseroTrackPrivate;
43 struct _BraseroTrackPrivate
44 {
45 	GHashTable *tags;
46 
47 	gchar *checksum;
48 	BraseroChecksumType checksum_type;
49 };
50 
51 #define BRASERO_TRACK_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_TRACK, BraseroTrackPrivate))
52 
53 enum
54 {
55 	CHANGED,
56 
57 	LAST_SIGNAL
58 };
59 
60 
61 static guint track_signals[LAST_SIGNAL] = { 0 };
62 
63 G_DEFINE_TYPE (BraseroTrack, brasero_track, G_TYPE_OBJECT);
64 
65 /**
66  * brasero_track_get_track_type:
67  * @track: a #BraseroTrack
68  * @type: a #BraseroTrackType or NULL
69  *
70  * Sets @type to reflect the type of data contained in @track
71  *
72  * Return value: the #BraseroBurnResult of the track
73  **/
74 
75 BraseroBurnResult
brasero_track_get_track_type(BraseroTrack * track,BraseroTrackType * type)76 brasero_track_get_track_type (BraseroTrack *track,
77 			      BraseroTrackType *type)
78 {
79 	BraseroTrackClass *klass;
80 
81 	g_return_val_if_fail (BRASERO_IS_TRACK (track), BRASERO_BURN_ERR);
82 	g_return_val_if_fail (type != NULL, BRASERO_BURN_ERR);
83 
84 	klass = BRASERO_TRACK_GET_CLASS (track);
85 	if (!klass->get_type)
86 		return BRASERO_BURN_ERR;
87 
88 	return klass->get_type (track, type);
89 }
90 
91 /**
92  * brasero_track_get_size:
93  * @track: a #BraseroTrack
94  * @blocks: a #goffset or NULL
95  * @bytes: a #goffset or NULL
96  *
97  * Returns the size of the data contained by @track in bytes or in sectors
98  *
99  * Return value: a #BraseroBurnResult.
100  * BRASERO_BURN_OK if it was successful
101  * BRASERO_BURN_NOT_READY if @track needs more time for processing the size
102  * BRASERO_BURN_ERR if something is wrong or if it is empty
103  **/
104 
105 BraseroBurnResult
brasero_track_get_size(BraseroTrack * track,goffset * blocks,goffset * bytes)106 brasero_track_get_size (BraseroTrack *track,
107 			goffset *blocks,
108 			goffset *bytes)
109 {
110 	BraseroBurnResult res;
111 	BraseroTrackClass *klass;
112 	goffset blocks_local = 0;
113 	goffset block_size_local = 0;
114 
115 	g_return_val_if_fail (BRASERO_IS_TRACK (track), BRASERO_BURN_ERR);
116 
117 	klass = BRASERO_TRACK_GET_CLASS (track);
118 	if (!klass->get_size)
119 		return BRASERO_BURN_OK;
120 
121 	res = klass->get_size (track, &blocks_local, &block_size_local);
122 	if (res != BRASERO_BURN_OK)
123 		return res;
124 
125 	if (blocks)
126 		*blocks = blocks_local;
127 
128 	if (bytes)
129 		*bytes = blocks_local * block_size_local;
130 
131 	return BRASERO_BURN_OK;
132 }
133 
134 /**
135  * brasero_track_get_status:
136  * @track: a #BraseroTrack
137  * @status: a #BraseroTrackStatus
138  *
139  * Sets @status to reflect whether @track is ready to be used
140  *
141  * Return value: a #BraseroBurnResult.
142  * BRASERO_BURN_OK if it was successful
143  * BRASERO_BURN_NOT_READY if @track needs more time for processing
144  * BRASERO_BURN_ERR if something is wrong or if it is empty
145  **/
146 
147 BraseroBurnResult
brasero_track_get_status(BraseroTrack * track,BraseroStatus * status)148 brasero_track_get_status (BraseroTrack *track,
149 			  BraseroStatus *status)
150 {
151 	BraseroTrackClass *klass;
152 
153 	g_return_val_if_fail (BRASERO_IS_TRACK (track), BRASERO_BURN_ERR);
154 
155 	klass = BRASERO_TRACK_GET_CLASS (track);
156 
157 	/* If this is not implement we consider that it means it is not needed
158 	 * and that the track doesn't perform on the side (threaded?) checks or
159 	 * information retrieval and that it's therefore always OK:
160 	 * - for example BraseroTrackDisc. */
161 	if (!klass->get_status) {
162 		if (status)
163 			brasero_status_set_completed (status);
164 
165 		return BRASERO_BURN_OK;
166 	}
167 
168 	return klass->get_status (track, status);
169 }
170 
171 /**
172  * brasero_track_set_checksum:
173  * @track: a #BraseroTrack
174  * @type: a #BraseroChecksumType
175  * @checksum: a #gchar * holding the checksum
176  *
177  * Sets a checksum for the track
178  *
179  * Return value: a #BraseroBurnResult.
180  * BRASERO_BURN_OK if the checksum was previously empty or matches the new one
181  * BRASERO_BURN_ERR otherwise
182  **/
183 
184 BraseroBurnResult
brasero_track_set_checksum(BraseroTrack * track,BraseroChecksumType type,const gchar * checksum)185 brasero_track_set_checksum (BraseroTrack *track,
186 			    BraseroChecksumType type,
187 			    const gchar *checksum)
188 {
189 	BraseroBurnResult result = BRASERO_BURN_OK;
190 	BraseroTrackPrivate *priv;
191 
192 	g_return_val_if_fail (BRASERO_IS_TRACK (track), BRASERO_CHECKSUM_NONE);
193 	priv = BRASERO_TRACK_PRIVATE (track);
194 
195 	if (type == priv->checksum_type
196 	&& (type == BRASERO_CHECKSUM_MD5 || type == BRASERO_CHECKSUM_SHA1 || type == BRASERO_CHECKSUM_SHA256)
197 	&&  checksum && strcmp (checksum, priv->checksum))
198 		result = BRASERO_BURN_ERR;
199 
200 	if (priv->checksum)
201 		g_free (priv->checksum);
202 
203 	priv->checksum_type = type;
204 	if (checksum)
205 		priv->checksum = g_strdup (checksum);
206 	else
207 		priv->checksum = NULL;
208 
209 	return result;
210 }
211 
212 /**
213  * brasero_track_get_checksum:
214  * @track: a #BraseroTrack
215  *
216  * Get the current checksum (as a string) for the track
217  *
218  * Return value: a #gchar * (not to be freed) or NULL
219  **/
220 
221 const gchar *
brasero_track_get_checksum(BraseroTrack * track)222 brasero_track_get_checksum (BraseroTrack *track)
223 {
224 	BraseroTrackPrivate *priv;
225 
226 	g_return_val_if_fail (BRASERO_IS_TRACK (track), NULL);
227 	priv = BRASERO_TRACK_PRIVATE (track);
228 
229 	return priv->checksum ? priv->checksum : NULL;
230 }
231 
232 /**
233  * brasero_track_get_checksum_type:
234  * @track: a #BraseroTrack
235  *
236  * Get the current checksum type for the track if any.
237  *
238  * Return value: a #BraseroChecksumType
239  **/
240 
241 BraseroChecksumType
brasero_track_get_checksum_type(BraseroTrack * track)242 brasero_track_get_checksum_type (BraseroTrack *track)
243 {
244 	BraseroTrackPrivate *priv;
245 
246 	g_return_val_if_fail (BRASERO_IS_TRACK (track), BRASERO_CHECKSUM_NONE);
247 	priv = BRASERO_TRACK_PRIVATE (track);
248 
249 	return priv->checksum_type;
250 }
251 
252 /**
253  * Can be used to set arbitrary data
254  */
255 
256 static void
brasero_track_tag_value_free(gpointer user_data)257 brasero_track_tag_value_free (gpointer user_data)
258 {
259 	GValue *value = user_data;
260 
261 	g_value_reset (value);
262 	g_free (value);
263 }
264 
265 /**
266  * brasero_track_tag_add:
267  * @track: a #BraseroTrack
268  * @tag: a #gchar *
269  * @value: a #GValue
270  *
271  * Associates a new @tag with a track. This can be used
272  * to pass arbitrary information for plugins, like parameters
273  * for video discs, ...
274  * See brasero-tags.h for a list of knowns tags.
275  *
276  * Return value: a #BraseroBurnResult.
277  * BRASERO_BURN_OK if it was successful,
278  * BRASERO_BURN_ERR otherwise.
279  **/
280 
281 BraseroBurnResult
brasero_track_tag_add(BraseroTrack * track,const gchar * tag,GValue * value)282 brasero_track_tag_add (BraseroTrack *track,
283 		       const gchar *tag,
284 		       GValue *value)
285 {
286 	BraseroTrackPrivate *priv;
287 
288 	g_return_val_if_fail (BRASERO_IS_TRACK (track), BRASERO_BURN_ERR);
289 
290 	priv = BRASERO_TRACK_PRIVATE (track);
291 
292 	if (!priv->tags)
293 		priv->tags = g_hash_table_new_full (g_str_hash,
294 						    g_str_equal,
295 						    g_free,
296 						    brasero_track_tag_value_free);
297 	g_hash_table_insert (priv->tags,
298 			     g_strdup (tag),
299 			     value);
300 
301 	return BRASERO_BURN_OK;
302 }
303 
304 /**
305  * brasero_track_tag_add_int:
306  * @track: a #BraseroTrack
307  * @tag: a #gchar *
308  * @value: a #int
309  *
310  * A wrapper around brasero_track_tag_add () to associate
311  * a int value with @track
312  * See also brasero_track_tag_add ()
313  *
314  * Return value: a #BraseroBurnResult.
315  * BRASERO_BURN_OK if it was successful,
316  * BRASERO_BURN_ERR otherwise.
317  **/
318 
319 BraseroBurnResult
brasero_track_tag_add_int(BraseroTrack * track,const gchar * tag,int value_int)320 brasero_track_tag_add_int (BraseroTrack *track,
321 			   const gchar *tag,
322 			   int value_int)
323 {
324 	GValue *value;
325 
326 	value = g_new0 (GValue, 1);
327 	g_value_init (value, G_TYPE_INT);
328 	g_value_set_int (value, value_int);
329 
330 	return brasero_track_tag_add (track, tag, value);
331 }
332 
333 /**
334  * brasero_track_tag_add_string:
335  * @track: a #BraseroTrack
336  * @tag: a #gchar *
337  * @string: a #gchar *
338  *
339  * A wrapper around brasero_track_tag_add () to associate
340  * a string with @track
341  * See also brasero_track_tag_add ()
342  *
343  * Return value: a #BraseroBurnResult.
344  * BRASERO_BURN_OK if it was successful,
345  * BRASERO_BURN_ERR otherwise.
346  **/
347 
348 BraseroBurnResult
brasero_track_tag_add_string(BraseroTrack * track,const gchar * tag,const gchar * string)349 brasero_track_tag_add_string (BraseroTrack *track,
350 			      const gchar *tag,
351 			      const gchar *string)
352 {
353 	GValue *value;
354 
355 	value = g_new0 (GValue, 1);
356 	g_value_init (value, G_TYPE_STRING);
357 	g_value_set_string (value, string);
358 
359 	return brasero_track_tag_add (track, tag, value);
360 }
361 
362 /**
363  * brasero_track_tag_lookup:
364  * @track: a #BraseroTrack
365  * @tag: a #gchar *
366  * @value: a #GValue **
367  *
368  * Retrieves a value associated with @track through
369  * brasero_track_tag_add () and stores it in @value. Do
370  * not destroy @value afterwards as it is not a copy
371  *
372  * Return value: a #BraseroBurnResult.
373  * BRASERO_BURN_OK if the retrieval was successful
374  * BRASERO_BURN_ERR otherwise
375  **/
376 
377 BraseroBurnResult
brasero_track_tag_lookup(BraseroTrack * track,const gchar * tag,GValue ** value)378 brasero_track_tag_lookup (BraseroTrack *track,
379 			  const gchar *tag,
380 			  GValue **value)
381 {
382 	gpointer data;
383 	BraseroTrackPrivate *priv;
384 
385 	g_return_val_if_fail (BRASERO_IS_TRACK (track), BRASERO_BURN_ERR);
386 
387 	priv = BRASERO_TRACK_PRIVATE (track);
388 
389 	if (!priv->tags)
390 		return BRASERO_BURN_ERR;
391 
392 	data = g_hash_table_lookup (priv->tags, tag);
393 	if (!data)
394 		return BRASERO_BURN_ERR;
395 
396 	if (value)
397 		*value = data;
398 
399 	return BRASERO_BURN_OK;
400 }
401 
402 /**
403  * brasero_track_tag_lookup_int:
404  * @track: a #BraseroTrack
405  * @tag: a #gchar *
406  *
407  * Retrieves a int value associated with @track. This
408  * is a wrapper around brasero_track_tag_lookup ().
409  *
410  * Return value: a #int; the value or 0 otherwise
411  **/
412 
413 int
brasero_track_tag_lookup_int(BraseroTrack * track,const gchar * tag)414 brasero_track_tag_lookup_int (BraseroTrack *track,
415 			      const gchar *tag)
416 {
417 	GValue *value = NULL;
418 	BraseroBurnResult res;
419 
420 	res = brasero_track_tag_lookup (track, tag, &value);
421 	if (res != BRASERO_BURN_OK)
422 		return 0;
423 
424 	if (!value)
425 		return 0;
426 
427 	if (!G_VALUE_HOLDS_INT (value))
428 		return 0;
429 
430 	return g_value_get_int (value);
431 }
432 
433 /**
434  * brasero_track_tag_lookup_string:
435  * @track: a #BraseroTrack
436  * @tag: a #gchar *
437  *
438  * Retrieves a string value associated with @track. This
439  * is a wrapper around brasero_track_tag_lookup ().
440  *
441  * Return value: a #gchar *. The value or NULL otherwise.
442  * Do not free the string as it is not a copy.
443  **/
444 
445 const gchar *
brasero_track_tag_lookup_string(BraseroTrack * track,const gchar * tag)446 brasero_track_tag_lookup_string (BraseroTrack *track,
447 				 const gchar *tag)
448 {
449 	GValue *value = NULL;
450 	BraseroBurnResult res;
451 
452 	res = brasero_track_tag_lookup (track, tag, &value);
453 	if (res != BRASERO_BURN_OK)
454 		return NULL;
455 
456 	if (!value)
457 		return NULL;
458 
459 	if (!G_VALUE_HOLDS_STRING (value))
460 		return NULL;
461 
462 	return g_value_get_string (value);
463 }
464 
465 /**
466  * brasero_track_tag_copy_missing:
467  * @dest: a #BraseroTrack
468  * @src: a #BraseroTrack
469  *
470  * Adds all tags of @dest to @src provided they do not
471  * already exists.
472  *
473  **/
474 
475 void
brasero_track_tag_copy_missing(BraseroTrack * dest,BraseroTrack * src)476 brasero_track_tag_copy_missing (BraseroTrack *dest,
477 				BraseroTrack *src)
478 {
479 	BraseroTrackPrivate *priv;
480 	GHashTableIter iter;
481 	gpointer new_value;
482 	gpointer new_key;
483 	gpointer value;
484 	gpointer key;
485 
486 	g_return_if_fail (BRASERO_IS_TRACK (dest));
487 	g_return_if_fail (BRASERO_IS_TRACK (src));
488 
489 	priv = BRASERO_TRACK_PRIVATE (src);
490 
491 	if (!priv->tags)
492 		return;
493 
494 	g_hash_table_iter_init (&iter, priv->tags);
495 
496 	priv = BRASERO_TRACK_PRIVATE (dest);
497 	if (!priv->tags)
498 		priv->tags = g_hash_table_new_full (g_str_hash,
499 						    g_str_equal,
500 						    g_free,
501 						    brasero_track_tag_value_free);
502 
503 	while (g_hash_table_iter_next (&iter, &key, &value)) {
504 		if (g_hash_table_lookup (priv->tags, key))
505 			continue;
506 
507 		new_value = g_new0 (GValue, 1);
508 
509 		g_value_init (new_value, G_VALUE_TYPE (value));
510 		g_value_copy (value, new_value);
511 
512 		new_key = g_strdup (key);
513 
514 		g_hash_table_insert (priv->tags, new_key, new_value);
515 	}
516 }
517 
518 /**
519  * brasero_track_changed:
520  * @track: a #BraseroTrack
521  *
522  * Used internally in #BraseroTrack implementations to
523  * signal a #BraseroTrack object has changed.
524  *
525  **/
526 
527 void
brasero_track_changed(BraseroTrack * track)528 brasero_track_changed (BraseroTrack *track)
529 {
530 	g_signal_emit (track,
531 		       track_signals [CHANGED],
532 		       0);
533 }
534 
535 
536 /**
537  * GObject part
538  */
539 
540 static void
brasero_track_init(BraseroTrack * object)541 brasero_track_init (BraseroTrack *object)
542 { }
543 
544 static void
brasero_track_finalize(GObject * object)545 brasero_track_finalize (GObject *object)
546 {
547 	BraseroTrackPrivate *priv;
548 
549 	priv = BRASERO_TRACK_PRIVATE (object);
550 
551 	if (priv->tags) {
552 		g_hash_table_destroy (priv->tags);
553 		priv->tags = NULL;
554 	}
555 
556 	if (priv->checksum) {
557 		g_free (priv->checksum);
558 		priv->checksum = NULL;
559 	}
560 
561 	G_OBJECT_CLASS (brasero_track_parent_class)->finalize (object);
562 }
563 
564 static void
brasero_track_class_init(BraseroTrackClass * klass)565 brasero_track_class_init (BraseroTrackClass *klass)
566 {
567 	GObjectClass* object_class = G_OBJECT_CLASS (klass);
568 
569 	g_type_class_add_private (klass, sizeof (BraseroTrackPrivate));
570 
571 	object_class->finalize = brasero_track_finalize;
572 
573 	track_signals[CHANGED] =
574 		g_signal_new ("changed",
575 		              G_OBJECT_CLASS_TYPE (klass),
576 		              G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE,
577 		              G_STRUCT_OFFSET (BraseroTrackClass, changed),
578 		              NULL, NULL,
579 		              g_cclosure_marshal_VOID__VOID,
580 		              G_TYPE_NONE, 0,
581 		              G_TYPE_NONE);
582 }
583