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