~mfisch/brasero/update-to-3.8.0

« back to all changes in this revision

Viewing changes to src/burn-caps.c

  • Committer: Bazaar Package Importer
  • Author(s): Robert Ancell
  • Date: 2009-06-03 10:36:30 UTC
  • mfrom: (1.1.23 upstream)
  • Revision ID: james.westby@ubuntu.com-20090603103630-2r72408gk45sc0ws
Tags: 2.27.2-0ubuntu1
* New upstream release (LP: #380850)
  - Split burning backend into a new library called libbrasero-burn
  - Split some utilities into a new library called libbrasero-utils
  - Use Brasero as a single instance application using libunique
  - Data spanning
  - Memleak fixes
  - Bug Fixes
  - String fixes
  - Use autogenerated Changelog via git
  - Translation Updates
  - Fixes (LP: #360671)
* Bump GTK+ requirement and add libunique requirement

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/***************************************************************************
2
 
 *            burn-caps.c
3
 
 *
4
 
 *  mar avr 18 20:58:42 2006
5
 
 *  Copyright  2006  Rouquier Philippe
6
 
 *  brasero-app@wanadoo.fr
7
 
 ***************************************************************************/
8
 
 
9
 
/*
10
 
 *  Brasero is free software; you can redistribute it and/or modify
11
 
 *  it under the terms of the GNU General Public License as published by
12
 
 *  the Free Software Foundation; either version 2 of the License, or
13
 
 *  (at your option) any later version.
14
 
 *
15
 
 *  Brasero is distributed in the hope that it will be useful,
16
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 
 *  GNU Library General Public License for more details.
19
 
 *
20
 
 *  You should have received a copy of the GNU General Public License
21
 
 *  along with this program; if not, write to:
22
 
 *      The Free Software Foundation, Inc.,
23
 
 *      51 Franklin Street, Fifth Floor
24
 
 *      Boston, MA  02110-1301, USA.
25
 
 */
26
 
 
27
 
#ifdef HAVE_CONFIG_H
28
 
#  include <config.h>
29
 
#endif
30
 
 
31
 
#include <string.h>
32
 
 
33
 
#include <glib.h>
34
 
#include <glib-object.h>
35
 
#include <glib/gi18n.h>
36
 
 
37
 
#include <gconf/gconf-client.h>
38
 
 
39
 
#include "brasero-media-private.h"
40
 
 
41
 
#include "burn-basics.h"
42
 
#include "burn-debug.h"
43
 
#include "brasero-drive.h"
44
 
#include "brasero-medium.h"
45
 
#include "burn-session.h"
46
 
#include "burn-plugin.h"
47
 
#include "burn-plugin-private.h"
48
 
#include "burn-task.h"
49
 
#include "burn-caps.h"
50
 
 
51
 
#define BRASERO_ENGINE_GROUP_KEY        "/apps/brasero/config/engine-group"
52
 
 
53
 
G_DEFINE_TYPE (BraseroBurnCaps, brasero_burn_caps, G_TYPE_OBJECT);
54
 
 
55
 
struct BraseroBurnCapsPrivate {
56
 
        GSList *caps_list;
57
 
        GSList *tests;
58
 
 
59
 
        GHashTable *groups;
60
 
 
61
 
        gchar *group_str;
62
 
        guint group_id;
63
 
};
64
 
 
65
 
struct _BraseroCaps {
66
 
        GSList *links;
67
 
        GSList *modifiers;
68
 
        BraseroTrackType type;
69
 
        BraseroPluginIOFlag flags;
70
 
};
71
 
typedef struct _BraseroCaps BraseroCaps;
72
 
 
73
 
struct _BraseroCapsLink {
74
 
        GSList *plugins;
75
 
        BraseroCaps *caps;
76
 
};
77
 
typedef struct _BraseroCapsLink BraseroCapsLink;
78
 
 
79
 
struct _BraseroCapsTest {
80
 
        GSList *links;
81
 
        BraseroChecksumType type;
82
 
};
83
 
typedef struct _BraseroCapsTest BraseroCapsTest;
84
 
 
85
 
#define SUBSTRACT(a, b)         ((a) &= ~((b)&(a)))
86
 
 
87
 
static GObjectClass *parent_class = NULL;
88
 
static BraseroBurnCaps *default_caps = NULL;
89
 
 
90
 
/**
91
 
 * These two functions are not public API and defined in burn-medium.c
92
 
 */
93
 
 
94
 
gboolean
95
 
brasero_medium_support_flags (BraseroMedium *medium,
96
 
                              BraseroBurnFlag flags);
97
 
 
98
 
BraseroBurnFlag
99
 
brasero_medium_supported_flags (BraseroMedium *self,
100
 
                                BraseroBurnFlag flags);
101
 
 
102
 
/**
103
 
 * This macro is used to determine whether or not blanking could change anything
104
 
 * for the medium so that we can write to it.
105
 
 */
106
 
#define BRASERO_BURN_CAPS_SHOULD_BLANK(media_MACRO, flags_MACRO)                \
107
 
        ((media_MACRO & BRASERO_MEDIUM_UNFORMATTED) ||                          \
108
 
        ((media_MACRO & (BRASERO_MEDIUM_HAS_AUDIO|BRASERO_MEDIUM_HAS_DATA)) &&  \
109
 
         (flags_MACRO & (BRASERO_BURN_FLAG_MERGE|BRASERO_BURN_FLAG_APPEND)) == FALSE))
110
 
 
111
 
#define BRASERO_BURN_CAPS_NOT_SUPPORTED_LOG(session)                            \
112
 
{                                                                               \
113
 
        brasero_burn_session_log (session, "Unsupported type of task operation"); \
114
 
        BRASERO_BURN_LOG ("Unsupported type of task operation");                \
115
 
        return NULL;                                                            \
116
 
}
117
 
 
118
 
#define BRASERO_BURN_CAPS_NOT_SUPPORTED_LOG_RES(session)                        \
119
 
{                                                                               \
120
 
        brasero_burn_session_log (session, "Unsupported type of task operation"); \
121
 
        BRASERO_BURN_LOG ("Unsupported type of task operation");                \
122
 
        return BRASERO_BURN_NOT_SUPPORTED;                                      \
123
 
}
124
 
 
125
 
#define BRASERO_BURN_CAPS_NOT_SUPPORTED_LOG_ERROR(session, error)               \
126
 
{                                                                               \
127
 
        if (error)                                                              \
128
 
                g_set_error (error,                                             \
129
 
                             BRASERO_BURN_ERROR,                                \
130
 
                             BRASERO_BURN_ERROR_GENERAL,                        \
131
 
                             _("An internal error occured"));                   \
132
 
        BRASERO_BURN_CAPS_NOT_SUPPORTED_LOG (session);                          \
133
 
}
134
 
 
135
 
static void
136
 
brasero_caps_link_free (BraseroCapsLink *link)
137
 
{
138
 
        g_slist_free (link->plugins);
139
 
        g_free (link);
140
 
}
141
 
 
142
 
static void
143
 
brasero_caps_free (BraseroCaps *caps)
144
 
{
145
 
        g_slist_foreach (caps->links, (GFunc) brasero_caps_link_free, NULL);
146
 
        g_slist_free (caps->links);
147
 
        g_free (caps);
148
 
}
149
 
 
150
 
static void
151
 
brasero_burn_caps_finalize (GObject *object)
152
 
{
153
 
        BraseroBurnCaps *cobj;
154
 
 
155
 
        cobj = BRASERO_BURNCAPS (object);
156
 
        
157
 
        default_caps = NULL;
158
 
 
159
 
        if (cobj->priv->groups) {
160
 
                g_hash_table_destroy (cobj->priv->groups);
161
 
                cobj->priv->groups = NULL;
162
 
        }
163
 
 
164
 
        g_slist_foreach (cobj->priv->caps_list, (GFunc) brasero_caps_free, NULL);
165
 
        g_slist_free (cobj->priv->caps_list);
166
 
 
167
 
        g_free (cobj->priv);
168
 
        G_OBJECT_CLASS (parent_class)->finalize (object);
169
 
}
170
 
 
171
 
static void
172
 
brasero_burn_caps_class_init (BraseroBurnCapsClass *klass)
173
 
{
174
 
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
175
 
 
176
 
        parent_class = g_type_class_peek_parent (klass);
177
 
        object_class->finalize = brasero_burn_caps_finalize;
178
 
}
179
 
 
180
 
static void
181
 
brasero_burn_caps_init (BraseroBurnCaps *obj)
182
 
{
183
 
        GConfClient *client;
184
 
 
185
 
        obj->priv = g_new0 (BraseroBurnCapsPrivate, 1);
186
 
 
187
 
        client = gconf_client_get_default ();
188
 
        obj->priv->group_str = gconf_client_get_string (client,
189
 
                                                        BRASERO_ENGINE_GROUP_KEY,
190
 
                                                        NULL);
191
 
        g_object_unref (client);
192
 
}
193
 
 
194
 
BraseroBurnCaps *
195
 
brasero_burn_caps_get_default ()
196
 
{
197
 
        if (!default_caps) 
198
 
                default_caps = BRASERO_BURNCAPS (g_object_new (BRASERO_TYPE_BURNCAPS, NULL));
199
 
        else
200
 
                g_object_ref (default_caps);
201
 
 
202
 
        return default_caps;
203
 
}
204
 
 
205
 
/* that function receives all errors returned by the object and 'learns' from 
206
 
 * these errors what are the safest defaults for a particular system. It should 
207
 
 * also offer fallbacks if an error occurs through a signal */
208
 
static BraseroBurnResult
209
 
brasero_burn_caps_job_error_cb (BraseroJob *job,
210
 
                                BraseroBurnError error,
211
 
                                BraseroBurnCaps *caps)
212
 
{
213
 
#if 0
214
 
        GError *error = NULL;
215
 
        GConfClient *client;
216
 
 
217
 
        /* This was originally to fix a bug in fedora 5 that prevents from
218
 
         * sending SCSI commands as a normal user through cdrdao. There is a
219
 
         * fallback fortunately with cdrecord and raw images but no on_the_fly
220
 
         * burning.
221
 
         * That could be used as a hook to know how a job runs and give a
222
 
         * "penalty" to job types being too often faulty. There could also be
223
 
         * a dialog to ask the user if he wants to use another backend.
224
 
         */
225
 
 
226
 
        /* set it in GConf to remember that next time */
227
 
        client = gconf_client_get_default ();
228
 
        gconf_client_set_bool (client, GCONF_KEY_CDRDAO_DISABLED, TRUE, &error);
229
 
        if (error) {
230
 
                g_warning ("Can't write with GConf: %s", error->message);
231
 
                g_error_free (error);
232
 
        }
233
 
        g_object_unref (client);
234
 
#endif
235
 
        return BRASERO_BURN_ERR;
236
 
}
237
 
 
238
 
static gboolean
239
 
brasero_caps_is_compatible_type (const BraseroCaps *caps,
240
 
                                 const BraseroTrackType *type)
241
 
{
242
 
        if (caps->type.type != type->type)
243
 
                return FALSE;
244
 
 
245
 
        switch (type->type) {
246
 
        case BRASERO_TRACK_TYPE_DATA:
247
 
                if ((caps->type.subtype.fs_type & type->subtype.fs_type) != type->subtype.fs_type)
248
 
                        return FALSE;
249
 
                break;
250
 
        
251
 
        case BRASERO_TRACK_TYPE_DISC:
252
 
                if (type->subtype.media == BRASERO_MEDIUM_NONE)
253
 
                        return FALSE;
254
 
 
255
 
                /* Reminder: we now create every possible types */
256
 
                if (caps->type.subtype.media != type->subtype.media)
257
 
                        return FALSE;
258
 
                break;
259
 
        
260
 
        case BRASERO_TRACK_TYPE_IMAGE:
261
 
                if (type->subtype.img_format == BRASERO_IMAGE_FORMAT_NONE)
262
 
                        return FALSE;
263
 
 
264
 
                if ((caps->type.subtype.img_format & type->subtype.img_format) != type->subtype.img_format)
265
 
                        return FALSE;
266
 
                break;
267
 
 
268
 
        case BRASERO_TRACK_TYPE_AUDIO:
269
 
                /* There is one small special case here with video. */
270
 
                if ((caps->type.subtype.audio_format & (BRASERO_VIDEO_FORMAT_UNDEFINED|
271
 
                                                        BRASERO_VIDEO_FORMAT_VCD|
272
 
                                                        BRASERO_VIDEO_FORMAT_VIDEO_DVD))
273
 
                && !(type->subtype.audio_format & (BRASERO_VIDEO_FORMAT_UNDEFINED|
274
 
                                                   BRASERO_VIDEO_FORMAT_VCD|
275
 
                                                   BRASERO_VIDEO_FORMAT_VIDEO_DVD)))
276
 
                        return FALSE;
277
 
 
278
 
                if ((caps->type.subtype.audio_format & type->subtype.audio_format) != type->subtype.audio_format)
279
 
                        return FALSE;
280
 
                break;
281
 
 
282
 
        default:
283
 
                break;
284
 
        }
285
 
 
286
 
        return TRUE;
287
 
}
288
 
 
289
 
static BraseroCaps *
290
 
brasero_caps_find_start_caps (BraseroTrackType *output)
291
 
{
292
 
        GSList *iter;
293
 
        BraseroBurnCaps *self;
294
 
 
295
 
        self = brasero_burn_caps_get_default ();
296
 
        for (iter = self->priv->caps_list; iter; iter = iter->next) {
297
 
                BraseroCaps *caps;
298
 
 
299
 
                caps = iter->data;
300
 
 
301
 
                if (!brasero_caps_is_compatible_type (caps, output))
302
 
                        continue;
303
 
 
304
 
                if (caps->type.type == BRASERO_TRACK_TYPE_DISC
305
 
                || (caps->flags & BRASERO_PLUGIN_IO_ACCEPT_FILE))
306
 
                        return caps;
307
 
        }
308
 
 
309
 
        return NULL;
310
 
}
311
 
 
312
 
BraseroBurnResult
313
 
brasero_burn_caps_get_blanking_flags_real (BraseroBurnCaps *caps,
314
 
                                           BraseroMedia media,
315
 
                                           BraseroBurnFlag session_flags,
316
 
                                           BraseroBurnFlag *supported,
317
 
                                           BraseroBurnFlag *compulsory)
318
 
{
319
 
        GSList *iter;
320
 
        gboolean supported_media;
321
 
        BraseroBurnFlag supported_flags = BRASERO_BURN_FLAG_NONE;
322
 
        BraseroBurnFlag compulsory_flags = BRASERO_BURN_FLAG_ALL;
323
 
 
324
 
        BRASERO_BURN_LOG_DISC_TYPE (media, "Getting blanking flags for");
325
 
        if (media == BRASERO_MEDIUM_NONE) {
326
 
                BRASERO_BURN_LOG ("Blanking not possible: no media");
327
 
                if (supported)
328
 
                        *supported = BRASERO_BURN_FLAG_NONE;
329
 
                if (compulsory)
330
 
                        *compulsory = BRASERO_BURN_FLAG_NONE;
331
 
                return BRASERO_BURN_NOT_SUPPORTED;
332
 
        }
333
 
 
334
 
        supported_media = FALSE;
335
 
        for (iter = caps->priv->caps_list; iter; iter = iter->next) {
336
 
                BraseroCaps *caps;
337
 
                GSList *links;
338
 
 
339
 
                caps = iter->data;
340
 
                if (caps->type.type != BRASERO_TRACK_TYPE_DISC)
341
 
                        continue;
342
 
 
343
 
                if ((media & caps->type.subtype.media) != media)
344
 
                        continue;
345
 
 
346
 
                for (links = caps->links; links; links = links->next) {
347
 
                        GSList *plugins;
348
 
                        BraseroCapsLink *link;
349
 
 
350
 
                        link = links->data;
351
 
 
352
 
                        if (link->caps != NULL)
353
 
                                continue;
354
 
 
355
 
                        supported_media = TRUE;
356
 
                        /* don't need the plugins to be sorted since we go
357
 
                         * through all the plugin list to get all blanking flags
358
 
                         * available. */
359
 
                        for (plugins = link->plugins; plugins; plugins = plugins->next) {
360
 
                                BraseroPlugin *plugin;
361
 
                                BraseroBurnFlag supported_plugin;
362
 
                                BraseroBurnFlag compulsory_plugin;
363
 
 
364
 
                                plugin = plugins->data;
365
 
                                if (!brasero_plugin_get_active (plugin))
366
 
                                        continue;
367
 
 
368
 
                                if (!brasero_plugin_get_blank_flags (plugin,
369
 
                                                                     media,
370
 
                                                                     session_flags,
371
 
                                                                     &supported_plugin,
372
 
                                                                     &compulsory_plugin))
373
 
                                        continue;
374
 
 
375
 
                                supported_flags |= supported_plugin;
376
 
                                compulsory_flags &= compulsory_plugin;
377
 
                        }
378
 
                }
379
 
        }
380
 
 
381
 
        if (!supported_media) {
382
 
                BRASERO_BURN_LOG ("media blanking not supported");
383
 
                return BRASERO_BURN_NOT_SUPPORTED;
384
 
        }
385
 
 
386
 
        if (supported)
387
 
                *supported = supported_flags;
388
 
        if (compulsory)
389
 
                *compulsory = compulsory_flags;
390
 
 
391
 
        return BRASERO_BURN_OK;
392
 
}
393
 
 
394
 
BraseroBurnResult
395
 
brasero_burn_caps_get_blanking_flags (BraseroBurnCaps *caps,
396
 
                                      BraseroBurnSession *session,
397
 
                                      BraseroBurnFlag *supported,
398
 
                                      BraseroBurnFlag *compulsory)
399
 
{
400
 
        BraseroMedia media;
401
 
        BraseroBurnFlag session_flags;
402
 
 
403
 
        media = brasero_burn_session_get_dest_media (session);
404
 
        BRASERO_BURN_LOG_DISC_TYPE (media, "Getting blanking flags for");
405
 
 
406
 
        if (media == BRASERO_MEDIUM_NONE) {
407
 
                BRASERO_BURN_LOG ("Blanking not possible: no media");
408
 
                if (supported)
409
 
                        *supported = BRASERO_BURN_FLAG_NONE;
410
 
                if (compulsory)
411
 
                        *compulsory = BRASERO_BURN_FLAG_NONE;
412
 
                return BRASERO_BURN_NOT_SUPPORTED;
413
 
        }
414
 
 
415
 
        session_flags = brasero_burn_session_get_flags (session);
416
 
        return brasero_burn_caps_get_blanking_flags_real (caps,
417
 
                                                          media,
418
 
                                                          session_flags,
419
 
                                                          supported,
420
 
                                                          compulsory);
421
 
}
422
 
 
423
 
BraseroTask *
424
 
brasero_burn_caps_new_blanking_task (BraseroBurnCaps *self,
425
 
                                     BraseroBurnSession *session,
426
 
                                     GError **error)
427
 
{
428
 
        GSList *iter;
429
 
        BraseroMedia media;
430
 
        BraseroBurnFlag flags;
431
 
        BraseroTask *task = NULL;
432
 
 
433
 
        media = brasero_burn_session_get_dest_media (session);
434
 
        flags = brasero_burn_session_get_flags (session);
435
 
 
436
 
        for (iter = self->priv->caps_list; iter; iter = iter->next) {
437
 
                BraseroCaps *caps;
438
 
                GSList *links;
439
 
 
440
 
                caps = iter->data;
441
 
                if (caps->type.type != BRASERO_TRACK_TYPE_DISC)
442
 
                        continue;
443
 
 
444
 
                if ((media & caps->type.subtype.media) != media)
445
 
                        continue;
446
 
 
447
 
                for (links = caps->links; links; links = links->next) {
448
 
                        GSList *plugins;
449
 
                        BraseroCapsLink *link;
450
 
                        BraseroPlugin *candidate;
451
 
 
452
 
                        link = links->data;
453
 
 
454
 
                        if (link->caps != NULL)
455
 
                                continue;
456
 
 
457
 
                        /* Go through all the plugins and find the best plugin
458
 
                         * for the task. It must :
459
 
                         * - be active
460
 
                         * - have the highest priority
461
 
                         * - accept the flags */
462
 
                        candidate = NULL;
463
 
                        for (plugins = link->plugins; plugins; plugins = plugins->next) {
464
 
                                BraseroPlugin *plugin;
465
 
 
466
 
                                plugin = plugins->data;
467
 
 
468
 
                                if (!brasero_plugin_get_active (plugin))
469
 
                                        continue;
470
 
 
471
 
                                if (!brasero_plugin_check_blank_flags (plugin, media, flags))
472
 
                                        continue;
473
 
 
474
 
                                if (self->priv->group_id > 0 && candidate) {
475
 
                                        /* the candidate must be in the favourite group as much as possible */
476
 
                                        if (brasero_plugin_get_group (candidate) != self->priv->group_id) {
477
 
                                                if (brasero_plugin_get_group (plugin) == self->priv->group_id) {
478
 
                                                        candidate = plugin;
479
 
                                                        continue;
480
 
                                                }
481
 
                                        }
482
 
                                        else if (brasero_plugin_get_group (plugin) != self->priv->group_id)
483
 
                                                continue;
484
 
                                }
485
 
 
486
 
                                if (!candidate)
487
 
                                        candidate = plugin;
488
 
                                else if (brasero_plugin_get_priority (plugin) >
489
 
                                         brasero_plugin_get_priority (candidate))
490
 
                                        candidate = plugin;
491
 
                        }
492
 
 
493
 
                        if (candidate) {
494
 
                                BraseroJob *job;
495
 
                                GType type;
496
 
 
497
 
                                type = brasero_plugin_get_gtype (candidate);
498
 
                                job = BRASERO_JOB (g_object_new (type,
499
 
                                                                 "output", NULL,
500
 
                                                                 NULL));
501
 
                                g_signal_connect (job,
502
 
                                                  "error",
503
 
                                                  G_CALLBACK (brasero_burn_caps_job_error_cb),
504
 
                                                  caps);
505
 
 
506
 
                                task = BRASERO_TASK (g_object_new (BRASERO_TYPE_TASK,
507
 
                                                                   "session", session,
508
 
                                                                   "action", BRASERO_TASK_ACTION_ERASE,
509
 
                                                                   NULL));
510
 
                                brasero_task_add_item (task, BRASERO_TASK_ITEM (job));
511
 
                                return task;
512
 
                        }
513
 
                }
514
 
        }
515
 
 
516
 
        BRASERO_BURN_CAPS_NOT_SUPPORTED_LOG_ERROR (session, error);
517
 
}
518
 
 
519
 
BraseroBurnResult
520
 
brasero_burn_caps_can_blank_real (BraseroBurnCaps *self,
521
 
                                  BraseroMedia media,
522
 
                                  BraseroBurnFlag flags)
523
 
{
524
 
        GSList *iter;
525
 
 
526
 
        BRASERO_BURN_LOG_DISC_TYPE (media, "Testing blanking caps for");
527
 
        if (media == BRASERO_MEDIUM_NONE) {
528
 
                BRASERO_BURN_LOG ("no media => no blanking possible");
529
 
                return BRASERO_BURN_NOT_SUPPORTED;
530
 
        }
531
 
 
532
 
        for (iter = self->priv->caps_list; iter; iter = iter->next) {
533
 
                BraseroCaps *caps;
534
 
                GSList *links;
535
 
 
536
 
                caps = iter->data;
537
 
                if (caps->type.type != BRASERO_TRACK_TYPE_DISC)
538
 
                        continue;
539
 
 
540
 
                if ((media & caps->type.subtype.media) != media)
541
 
                        continue;
542
 
 
543
 
                BRASERO_BURN_LOG_TYPE (&caps->type, "Searching links for caps");
544
 
 
545
 
                for (links = caps->links; links; links = links->next) {
546
 
                        GSList *plugins;
547
 
                        BraseroCapsLink *link;
548
 
 
549
 
                        link = links->data;
550
 
 
551
 
                        if (link->caps != NULL)
552
 
                                continue;
553
 
 
554
 
                        BRASERO_BURN_LOG ("Searching plugins");
555
 
 
556
 
                        /* Go through all plugins for the link and stop if we 
557
 
                         * find at least one active plugin that accepts the
558
 
                         * flags. No need for plugins to be sorted */
559
 
                        for (plugins = link->plugins; plugins; plugins = plugins->next) {
560
 
                                BraseroPlugin *plugin;
561
 
 
562
 
                                plugin = plugins->data;
563
 
                                if (!brasero_plugin_get_active (plugin))
564
 
                                        continue;
565
 
 
566
 
                                if (brasero_plugin_check_blank_flags (plugin, media, flags)) {
567
 
                                        BRASERO_BURN_LOG_DISC_TYPE (media, "Can blank");
568
 
                                        return BRASERO_BURN_OK;
569
 
                                }
570
 
                        }
571
 
                }
572
 
        }
573
 
 
574
 
        BRASERO_BURN_LOG_DISC_TYPE (media, "No blanking capabilities for");
575
 
 
576
 
        return BRASERO_BURN_NOT_SUPPORTED;
577
 
}
578
 
 
579
 
BraseroBurnResult
580
 
brasero_burn_caps_can_blank (BraseroBurnCaps *self,
581
 
                             BraseroBurnSession *session)
582
 
{
583
 
        BraseroMedia media;
584
 
        BraseroBurnFlag flags;
585
 
 
586
 
        media = brasero_burn_session_get_dest_media (session);
587
 
        BRASERO_BURN_LOG_DISC_TYPE (media, "Testing blanking caps for");
588
 
 
589
 
        if (media == BRASERO_MEDIUM_NONE) {
590
 
                BRASERO_BURN_LOG ("no media => no blanking possible");
591
 
                return BRASERO_BURN_NOT_SUPPORTED;
592
 
        }
593
 
 
594
 
        flags = brasero_burn_session_get_flags (session);
595
 
        return brasero_burn_caps_can_blank_real (self, media, flags);
596
 
}
597
 
 
598
 
/**
599
 
 *
600
 
 */
601
 
 
602
 
static void
603
 
brasero_caps_link_get_record_flags (BraseroCapsLink *link,
604
 
                                    BraseroMedia media,
605
 
                                    BraseroBurnFlag session_flags,
606
 
                                    BraseroBurnFlag *supported,
607
 
                                    BraseroBurnFlag *compulsory_retval)
608
 
{
609
 
        GSList *iter;
610
 
        BraseroBurnFlag compulsory;
611
 
 
612
 
        compulsory = BRASERO_BURN_FLAG_ALL;
613
 
 
614
 
        /* Go through all plugins to get the supported/... record flags for link */
615
 
        for (iter = link->plugins; iter; iter = iter->next) {
616
 
                gboolean result;
617
 
                BraseroPlugin *plugin;
618
 
                BraseroBurnFlag plugin_supported;
619
 
                BraseroBurnFlag plugin_compulsory;
620
 
 
621
 
                plugin = iter->data;
622
 
                if (!brasero_plugin_get_active (plugin))
623
 
                        continue;
624
 
 
625
 
                result = brasero_plugin_get_record_flags (plugin,
626
 
                                                          media,
627
 
                                                          session_flags,
628
 
                                                          &plugin_supported,
629
 
                                                          &plugin_compulsory);
630
 
                if (!result)
631
 
                        continue;
632
 
 
633
 
                *supported |= plugin_supported;
634
 
                compulsory &= plugin_compulsory;
635
 
        }
636
 
 
637
 
        *compulsory_retval = compulsory;
638
 
}
639
 
 
640
 
static void
641
 
brasero_caps_link_get_data_flags (BraseroCapsLink *link,
642
 
                                  BraseroMedia media,
643
 
                                  BraseroBurnFlag session_flags,
644
 
                                  BraseroBurnFlag *supported)
645
 
{
646
 
        GSList *iter;
647
 
 
648
 
        /* Go through all plugins the get the supported/... data flags for link */
649
 
        for (iter = link->plugins; iter; iter = iter->next) {
650
 
                gboolean result;
651
 
                BraseroPlugin *plugin;
652
 
                BraseroBurnFlag plugin_supported;
653
 
                BraseroBurnFlag plugin_compulsory;
654
 
 
655
 
                plugin = iter->data;
656
 
                if (!brasero_plugin_get_active (plugin))
657
 
                        continue;
658
 
 
659
 
                result = brasero_plugin_get_image_flags (plugin,
660
 
                                                         media,
661
 
                                                         session_flags,
662
 
                                                         &plugin_supported,
663
 
                                                         &plugin_compulsory);
664
 
                *supported |= plugin_supported;
665
 
        }
666
 
}
667
 
 
668
 
static gboolean
669
 
brasero_caps_link_active (BraseroCapsLink *link)
670
 
{
671
 
        GSList *iter;
672
 
 
673
 
        /* See if link is active by going through all plugins. There must be at
674
 
         * least one. */
675
 
        for (iter = link->plugins; iter; iter = iter->next) {
676
 
                BraseroPlugin *plugin;
677
 
 
678
 
                plugin = iter->data;
679
 
                if (brasero_plugin_get_active (plugin))
680
 
                        return TRUE;
681
 
        }
682
 
 
683
 
        return FALSE;
684
 
}
685
 
 
686
 
static gboolean
687
 
brasero_caps_link_check_data_flags (BraseroCapsLink *link,
688
 
                                    BraseroBurnFlag session_flags,
689
 
                                    BraseroMedia media)
690
 
{
691
 
        GSList *iter;
692
 
        BraseroBurnFlag flags;
693
 
 
694
 
        /* here we just make sure that at least one of the plugins in the link
695
 
         * can comply with the flags (APPEND/MERGE) */
696
 
        flags = session_flags & (BRASERO_BURN_FLAG_APPEND|BRASERO_BURN_FLAG_MERGE);
697
 
 
698
 
        /* If there are no image flags forget it */
699
 
        if (flags == BRASERO_BURN_FLAG_NONE)
700
 
                return TRUE;
701
 
 
702
 
        /* Go through all plugins; at least one must support image flags */
703
 
        for (iter = link->plugins; iter; iter = iter->next) {
704
 
                gboolean result;
705
 
                BraseroPlugin *plugin;
706
 
 
707
 
                plugin = iter->data;
708
 
                if (!brasero_plugin_get_active (plugin))
709
 
                        continue;
710
 
 
711
 
                result = brasero_plugin_check_image_flags (plugin,
712
 
                                                           media,
713
 
                                                           session_flags);
714
 
                if (result)
715
 
                        return TRUE;
716
 
        }
717
 
 
718
 
        return FALSE;
719
 
}
720
 
 
721
 
static gboolean
722
 
brasero_caps_link_check_record_flags (BraseroCapsLink *link,
723
 
                                      BraseroBurnFlag session_flags,
724
 
                                      BraseroMedia media)
725
 
{
726
 
        GSList *iter;
727
 
        BraseroBurnFlag flags;
728
 
 
729
 
        flags = session_flags & BRASERO_PLUGIN_BURN_FLAG_MASK;
730
 
 
731
 
        /* If there are no record flags forget it */
732
 
        if (flags == BRASERO_BURN_FLAG_NONE)
733
 
                return TRUE;
734
 
        
735
 
        /* Go through all plugins: at least one must support record flags */
736
 
        for (iter = link->plugins; iter; iter = iter->next) {
737
 
                gboolean result;
738
 
                BraseroPlugin *plugin;
739
 
 
740
 
                plugin = iter->data;
741
 
                if (!brasero_plugin_get_active (plugin))
742
 
                        continue;
743
 
 
744
 
                result = brasero_plugin_check_record_flags (plugin,
745
 
                                                            media,
746
 
                                                            session_flags);
747
 
                if (result)
748
 
                        return TRUE;
749
 
        }
750
 
 
751
 
        return FALSE;
752
 
}
753
 
 
754
 
static gboolean
755
 
brasero_caps_link_check_media_restrictions (BraseroCapsLink *link,
756
 
                                            BraseroMedia media)
757
 
{
758
 
        GSList *iter;
759
 
 
760
 
        /* Go through all plugins: at least one must support media */
761
 
        for (iter = link->plugins; iter; iter = iter->next) {
762
 
                gboolean result;
763
 
                BraseroPlugin *plugin;
764
 
 
765
 
                plugin = iter->data;
766
 
                if (!brasero_plugin_get_active (plugin))
767
 
                        continue;
768
 
 
769
 
                result = brasero_plugin_check_media_restrictions (plugin, media);
770
 
                if (result)
771
 
                        return TRUE;
772
 
        }
773
 
 
774
 
        return FALSE;
775
 
}
776
 
 
777
 
static BraseroPlugin *
778
 
brasero_caps_link_find_plugin (BraseroCapsLink *link,
779
 
                               gint group_id,
780
 
                               BraseroBurnFlag session_flags,
781
 
                               BraseroTrackType *output,
782
 
                               BraseroMedia media)
783
 
{
784
 
        GSList *iter;
785
 
        BraseroPlugin *candidate;
786
 
 
787
 
        /* Go through all plugins for a link and find the best one. It must:
788
 
         * - be active
789
 
         * - be part of the group (as much as possible)
790
 
         * - have the highest priority
791
 
         * - support the flags */
792
 
        candidate = NULL;
793
 
        for (iter = link->plugins; iter; iter = iter->next) {
794
 
                BraseroPlugin *plugin;
795
 
 
796
 
                plugin = iter->data;
797
 
 
798
 
                if (!brasero_plugin_get_active (plugin))
799
 
                        continue;
800
 
 
801
 
                if (output->type == BRASERO_TRACK_TYPE_DISC) {
802
 
                        gboolean result;
803
 
 
804
 
                        result = brasero_plugin_check_record_flags (plugin,
805
 
                                                                    media,
806
 
                                                                    session_flags);
807
 
                        if (!result)
808
 
                                continue;
809
 
                }
810
 
 
811
 
                if (link->caps->type.type == BRASERO_TRACK_TYPE_DATA) {
812
 
                        gboolean result;
813
 
 
814
 
                        result = brasero_plugin_check_image_flags (plugin,
815
 
                                                                   media,
816
 
                                                                   session_flags);
817
 
                        if (!result)
818
 
                                continue;
819
 
                }
820
 
                else if (!brasero_plugin_check_media_restrictions (plugin, media))
821
 
                        continue;
822
 
 
823
 
                if (group_id > 0 && candidate) {
824
 
                        /* the candidate must be in the favourite group as much as possible */
825
 
                        if (brasero_plugin_get_group (candidate) != group_id) {
826
 
                                if (brasero_plugin_get_group (plugin) == group_id) {
827
 
                                        candidate = plugin;
828
 
                                        continue;
829
 
                                }
830
 
                        }
831
 
                        else if (brasero_plugin_get_group (plugin) != group_id)
832
 
                                continue;
833
 
                }
834
 
 
835
 
                if (!candidate)
836
 
                        candidate = plugin;
837
 
                else if (brasero_plugin_get_priority (plugin) >
838
 
                         brasero_plugin_get_priority (candidate))
839
 
                        candidate = plugin;
840
 
        }
841
 
 
842
 
        return candidate;
843
 
}
844
 
 
845
 
typedef struct _BraseroCapsLinkList BraseroCapsLinkList;
846
 
struct _BraseroCapsLinkList {
847
 
        BraseroCapsLinkList *next;
848
 
        BraseroCapsLink *link;
849
 
        BraseroPlugin *plugin;
850
 
};
851
 
 
852
 
static BraseroCapsLinkList *
853
 
brasero_caps_link_list_insert (BraseroCapsLinkList *list,
854
 
                               BraseroCapsLinkList *node,
855
 
                               gboolean fits)
856
 
{
857
 
        BraseroCapsLinkList *iter;
858
 
 
859
 
        if (!list)
860
 
                return node;
861
 
 
862
 
        if (brasero_plugin_get_priority (node->plugin) >
863
 
            brasero_plugin_get_priority (list->plugin)) {
864
 
                node->next = list;
865
 
                return node;
866
 
        }
867
 
 
868
 
        if (brasero_plugin_get_priority (node->plugin) ==
869
 
            brasero_plugin_get_priority (list->plugin)) {
870
 
                if (fits) {
871
 
                        node->next = list;
872
 
                        return node;
873
 
                }
874
 
 
875
 
                node->next = list->next;
876
 
                list->next = node;
877
 
                return list;
878
 
        }
879
 
 
880
 
        if (!list->next) {
881
 
                node->next = NULL;
882
 
                list->next = node;
883
 
                return list;
884
 
        }
885
 
 
886
 
        /* Need a node with at least the same priority. Stop if end is reached */
887
 
        iter = list;
888
 
        while (iter->next &&
889
 
               brasero_plugin_get_priority (node->plugin) <
890
 
               brasero_plugin_get_priority (iter->next->plugin))
891
 
                iter = iter->next;
892
 
 
893
 
        if (!iter->next) {
894
 
                /* reached the end of the list, put it at the end */
895
 
                iter->next = node;
896
 
                node->next = NULL;
897
 
        }
898
 
        else if (brasero_plugin_get_priority (node->plugin) <
899
 
                 brasero_plugin_get_priority (iter->next->plugin)) {
900
 
                /* Put it at the end of the list */
901
 
                node->next = NULL;
902
 
                iter->next->next = node;
903
 
        }
904
 
        else if (brasero_plugin_get_priority (node->plugin) >
905
 
                 brasero_plugin_get_priority (iter->next->plugin)) {
906
 
                /* insert it before iter->next */
907
 
                node->next = iter->next;
908
 
                iter->next = node;
909
 
        }
910
 
        else if (fits) {
911
 
                /* insert it before the link with the same priority */
912
 
                node->next = iter->next;
913
 
                iter->next = node;
914
 
        }
915
 
        else {
916
 
                /* insert it after the link with the same priority */
917
 
                node->next = iter->next->next;
918
 
                iter->next->next = node;
919
 
        }
920
 
        return list;
921
 
}
922
 
 
923
 
static GSList *
924
 
brasero_caps_find_best_link (BraseroCaps *caps,
925
 
                             gint group_id,
926
 
                             GSList *used_caps,
927
 
                             BraseroBurnFlag session_flags,
928
 
                             BraseroMedia media,
929
 
                             BraseroTrackType *input,
930
 
                             BraseroPluginIOFlag io_flags)
931
 
{
932
 
        GSList *iter;
933
 
        GSList *results = NULL;
934
 
        BraseroCapsLinkList *node = NULL;
935
 
        BraseroCapsLinkList *list = NULL;
936
 
 
937
 
        BRASERO_BURN_LOG_WITH_TYPE (&caps->type, BRASERO_PLUGIN_IO_NONE, "find_best_link");
938
 
 
939
 
        /* First, build a list of possible links and sort them out according to
940
 
         * the priority based on the highest priority among their plugins. In 
941
 
         * this case, we can't sort links beforehand since according to the
942
 
         * flags, input, output in the session the plugins will or will not 
943
 
         * be used. Moreover given the group_id thing the choice of plugin may
944
 
         * depends. */
945
 
 
946
 
        /* This is done to address possible issues namely:
947
 
         * - growisofs can handle DATA right from the start but has a lower
948
 
         * priority than libburn. In this case growisofs would be used every 
949
 
         * time for DATA despite its having a lower priority than libburn if we
950
 
         * were looking for the best fit first
951
 
         * - We don't want to follow the long path and have a useless (in this
952
 
         * case) image converter plugin get included.
953
 
         * ex: we would have: CDRDAO (input) toc2cue => (CUE) cdrdao => (DISC)
954
 
         * instead of simply: CDRDAO (input) cdrdao => (DISC) */
955
 
 
956
 
        for (iter = caps->links; iter; iter = iter->next) {
957
 
                BraseroPlugin *plugin;
958
 
                BraseroCapsLink *link;
959
 
                gboolean fits;
960
 
 
961
 
                link = iter->data;
962
 
 
963
 
                /* skip blanking links */
964
 
                if (!link->caps) {
965
 
                        BRASERO_BURN_LOG ("Blanking caps");
966
 
                        continue;
967
 
                }
968
 
 
969
 
                /* the link should not link to an already used caps */
970
 
                if (g_slist_find (used_caps, link->caps)) {
971
 
                        BRASERO_BURN_LOG ("Already used caps");
972
 
                        continue;
973
 
                }
974
 
 
975
 
                /* see if that's a perfect fit;
976
 
                 * - it must have the same caps (type + subtype)
977
 
                 * - it must have the proper IO (file). */
978
 
                fits = (link->caps->flags & BRASERO_PLUGIN_IO_ACCEPT_FILE) &&
979
 
                        brasero_caps_is_compatible_type (link->caps, input);
980
 
 
981
 
                if (!fits) {
982
 
                        /* if it doesn't fit it must be at least connectable */
983
 
                        if ((link->caps->flags & io_flags) == BRASERO_PLUGIN_IO_NONE) {
984
 
                                BRASERO_BURN_LOG ("Not connectable");
985
 
                                continue;
986
 
                        }
987
 
 
988
 
                        /* we can't go further than a DISC type, no need to keep it */
989
 
                        if (link->caps->type.type == BRASERO_TRACK_TYPE_DISC) {
990
 
                                BRASERO_BURN_LOG ("Can't go further than DISC caps");
991
 
                                continue;
992
 
                        }
993
 
                }
994
 
 
995
 
                /* See if this link can be used. For a link to be followed it 
996
 
                 * must:
997
 
                 * - have at least an active plugin
998
 
                 * - have at least a plugin accepting the record flags if caps type (output) 
999
 
                 *   is a disc (that means that the link is the recording part) 
1000
 
                 * - have at least a plugin accepting the data flags if caps type (input)
1001
 
                 *   is DATA. */
1002
 
                plugin = brasero_caps_link_find_plugin (link,
1003
 
                                                        group_id,
1004
 
                                                        session_flags,
1005
 
                                                        &caps->type,
1006
 
                                                        media);
1007
 
                if (!plugin) {
1008
 
                        BRASERO_BURN_LOG ("No plugin found");
1009
 
                        continue;
1010
 
                }
1011
 
 
1012
 
                BRASERO_BURN_LOG ("Found candidate link");
1013
 
 
1014
 
                /* A plugin could be found which means that link can be used.
1015
 
                 * Insert it in the list at the right place.
1016
 
                 * The list is sorted according to priorities (starting with the
1017
 
                 * highest). If 2 links have the same priority put first the one
1018
 
                 * that has the correct input. */
1019
 
                node = g_new0 (BraseroCapsLinkList, 1);
1020
 
                node->plugin = plugin;
1021
 
                node->link = link;
1022
 
 
1023
 
                list = brasero_caps_link_list_insert (list, node, fits);
1024
 
        }
1025
 
 
1026
 
        if (!list) {
1027
 
                BRASERO_BURN_LOG ("No links found");
1028
 
                return NULL;
1029
 
        }
1030
 
 
1031
 
        used_caps = g_slist_prepend (used_caps, caps);
1032
 
 
1033
 
        /* Then, go through this list (starting with highest priority links)
1034
 
         * The rule is we prefer the links with the highest priority; if two
1035
 
         * links have the same priority and one of them leads to a caps
1036
 
         * with the correct type then choose this one. */
1037
 
        for (node = list; node; node = node->next) {
1038
 
                guint search_group_id;
1039
 
 
1040
 
                /* see if that's a perfect fit; if so, then we're good. 
1041
 
                 * - it must have the same caps (type + subtype)
1042
 
                 * - it must have the proper IO (file) */
1043
 
                if ((node->link->caps->flags & BRASERO_PLUGIN_IO_ACCEPT_FILE)
1044
 
                &&   brasero_caps_is_compatible_type (node->link->caps, input)) {
1045
 
                        results = g_slist_prepend (NULL, node->link);
1046
 
                        break;
1047
 
                }
1048
 
 
1049
 
                /* determine the group_id for the search */
1050
 
                if (brasero_plugin_get_group (node->plugin) > 0 && group_id <= 0)
1051
 
                        search_group_id = brasero_plugin_get_group (node->plugin);
1052
 
                else
1053
 
                        search_group_id = group_id;
1054
 
 
1055
 
                /* It's not a perfect fit. First see if a plugin with the same
1056
 
                 * priority don't have the right input. Then see if we can reach
1057
 
                 * the right input by going through all previous nodes */
1058
 
                results = brasero_caps_find_best_link (node->link->caps,
1059
 
                                                       search_group_id,
1060
 
                                                       used_caps,
1061
 
                                                       session_flags,
1062
 
                                                       media,
1063
 
                                                       input,
1064
 
                                                       io_flags);
1065
 
                if (results) {
1066
 
                        results = g_slist_prepend (results, node->link);
1067
 
                        break;
1068
 
                }
1069
 
        }
1070
 
 
1071
 
        /* clear up */
1072
 
        used_caps = g_slist_remove (used_caps, caps);
1073
 
        for (node = list; node; node = list) {
1074
 
                list = node->next;
1075
 
                g_free (node);
1076
 
        }
1077
 
 
1078
 
        return results;
1079
 
}
1080
 
 
1081
 
static gboolean
1082
 
brasero_burn_caps_sort_modifiers (gconstpointer a,
1083
 
                                  gconstpointer b)
1084
 
{
1085
 
        BraseroPlugin *plug_a = BRASERO_PLUGIN (a);
1086
 
        BraseroPlugin *plug_b = BRASERO_PLUGIN (b);
1087
 
 
1088
 
        return brasero_plugin_get_priority (plug_a) -
1089
 
               brasero_plugin_get_priority (plug_b);
1090
 
}
1091
 
 
1092
 
static GSList *
1093
 
brasero_caps_add_processing_plugins_to_task (BraseroBurnSession *session,
1094
 
                                             BraseroTask *task,
1095
 
                                             BraseroCaps *caps,
1096
 
                                             BraseroTrackType *io_type,
1097
 
                                             BraseroPluginProcessFlag position)
1098
 
{
1099
 
        GSList *retval = NULL;
1100
 
        GSList *modifiers;
1101
 
        GSList *iter;
1102
 
 
1103
 
        if (position == BRASERO_PLUGIN_RUN_NEVER
1104
 
        ||  caps->type.type == BRASERO_TRACK_TYPE_DISC)
1105
 
                return NULL;
1106
 
 
1107
 
        BRASERO_BURN_LOG_WITH_TYPE (&caps->type,
1108
 
                                    caps->flags,
1109
 
                                    "Adding modifiers (position %i) (%i modifiers available) for",
1110
 
                                    position,
1111
 
                                    g_slist_length (caps->modifiers));
1112
 
 
1113
 
        /* Go through all plugins and add all possible modifiers. They must:
1114
 
         * - be active
1115
 
         * - accept the position flags */
1116
 
        modifiers = g_slist_copy (caps->modifiers);
1117
 
        modifiers = g_slist_sort (modifiers, brasero_burn_caps_sort_modifiers);
1118
 
 
1119
 
        for (iter = modifiers; iter; iter = iter->next) {
1120
 
                BraseroPluginProcessFlag flags;
1121
 
                BraseroPlugin *plugin;
1122
 
                BraseroJob *job;
1123
 
                GType type;
1124
 
 
1125
 
                plugin = iter->data;
1126
 
                if (!brasero_plugin_get_active (plugin))
1127
 
                        continue;
1128
 
 
1129
 
                brasero_plugin_get_process_flags (plugin, &flags);
1130
 
                if ((flags & position) != position)
1131
 
                        continue;
1132
 
 
1133
 
                type = brasero_plugin_get_gtype (plugin);
1134
 
                job = BRASERO_JOB (g_object_new (type,
1135
 
                                                 "output", io_type,
1136
 
                                                 NULL));
1137
 
                g_signal_connect (job,
1138
 
                                  "error",
1139
 
                                  G_CALLBACK (brasero_burn_caps_job_error_cb),
1140
 
                                  caps);
1141
 
 
1142
 
                if (!task
1143
 
                ||  !(caps->flags & BRASERO_PLUGIN_IO_ACCEPT_PIPE)
1144
 
                ||  !BRASERO_BURN_SESSION_NO_TMP_FILE (session)) {
1145
 
                        /* here the action taken is always to create an image */
1146
 
                        task = BRASERO_TASK (g_object_new (BRASERO_TYPE_TASK,
1147
 
                                                           "session", session,
1148
 
                                                           "action", BRASERO_BURN_ACTION_CREATING_IMAGE,
1149
 
                                                           NULL));
1150
 
                        retval = g_slist_prepend (retval, task);
1151
 
                }
1152
 
 
1153
 
                BRASERO_BURN_LOG ("%s (modifier) added to task",
1154
 
                                  brasero_plugin_get_name (plugin));
1155
 
 
1156
 
                BRASERO_BURN_LOG_TYPE (io_type, "IO type");
1157
 
 
1158
 
                brasero_task_add_item (task, BRASERO_TASK_ITEM (job));
1159
 
        }
1160
 
        g_slist_free (modifiers);
1161
 
 
1162
 
        return retval;
1163
 
}
1164
 
 
1165
 
static gboolean
1166
 
brasero_burn_caps_flags_check_for_drive (BraseroBurnSession *session)
1167
 
{
1168
 
        BraseroDrive *drive;
1169
 
        BraseroMedium *medium;
1170
 
        BraseroBurnFlag flags;
1171
 
 
1172
 
        drive = brasero_burn_session_get_burner (session);
1173
 
        if (!drive)
1174
 
                return TRUE;
1175
 
 
1176
 
        if (brasero_drive_is_fake (drive))
1177
 
                return TRUE;
1178
 
 
1179
 
        medium = brasero_drive_get_medium (drive);
1180
 
        if (!medium)
1181
 
                return TRUE;
1182
 
 
1183
 
        flags = brasero_burn_session_get_flags (session);
1184
 
        return brasero_medium_support_flags (medium, flags);
1185
 
}
1186
 
 
1187
 
GSList *
1188
 
brasero_burn_caps_new_task (BraseroBurnCaps *self,
1189
 
                            BraseroBurnSession *session,
1190
 
                            GError **error)
1191
 
{
1192
 
        BraseroPluginProcessFlag position;
1193
 
        BraseroBurnFlag session_flags;
1194
 
        BraseroTrackType plugin_input;
1195
 
        BraseroTask *blanking = NULL;
1196
 
        BraseroPluginIOFlag flags;
1197
 
        BraseroTask *task = NULL;
1198
 
        BraseroTrackType output;
1199
 
        BraseroTrackType input;
1200
 
        BraseroCaps *last_caps;
1201
 
        GSList *retval = NULL;
1202
 
        GSList *iter, *list;
1203
 
        BraseroMedia media;
1204
 
        gint group_id;
1205
 
 
1206
 
        /* determine the output and the flags for this task */
1207
 
        if (brasero_burn_session_is_dest_file (session)) {
1208
 
                media = BRASERO_MEDIUM_FILE;
1209
 
 
1210
 
                output.type = BRASERO_TRACK_TYPE_IMAGE;
1211
 
                output.subtype.img_format = brasero_burn_session_get_output_format (session);
1212
 
        }
1213
 
        else {
1214
 
                media = brasero_burn_session_get_dest_media (session);
1215
 
 
1216
 
                output.type = BRASERO_TRACK_TYPE_DISC;
1217
 
                output.subtype.media = media;
1218
 
        }
1219
 
 
1220
 
        if (BRASERO_BURN_SESSION_NO_TMP_FILE (session))
1221
 
                flags = BRASERO_PLUGIN_IO_ACCEPT_PIPE;
1222
 
        else
1223
 
                flags = BRASERO_PLUGIN_IO_ACCEPT_FILE;
1224
 
 
1225
 
        BRASERO_BURN_LOG_WITH_TYPE (&output,
1226
 
                                    flags,
1227
 
                                    "Creating recording/imaging task");
1228
 
 
1229
 
        /* search the start caps and try to get a list of links */
1230
 
        last_caps = brasero_caps_find_start_caps (&output);
1231
 
        if (!last_caps)
1232
 
                BRASERO_BURN_CAPS_NOT_SUPPORTED_LOG_ERROR (session, error);
1233
 
 
1234
 
        brasero_burn_session_get_input_type (session, &input);
1235
 
        BRASERO_BURN_LOG_WITH_TYPE (&input,
1236
 
                                    BRASERO_PLUGIN_IO_NONE,
1237
 
                                    "Input set =");
1238
 
 
1239
 
        if (!brasero_burn_caps_flags_check_for_drive (session))
1240
 
                BRASERO_BURN_CAPS_NOT_SUPPORTED_LOG (session);
1241
 
 
1242
 
        session_flags = brasero_burn_session_get_flags (session);
1243
 
        list = brasero_caps_find_best_link (last_caps,
1244
 
                                            self->priv->group_id,
1245
 
                                            NULL,
1246
 
                                            session_flags,
1247
 
                                            media,
1248
 
                                            &input,
1249
 
                                            flags);
1250
 
        if (!list) {
1251
 
                /* we reached this point in two cases:
1252
 
                 * - if the disc cannot be handled
1253
 
                 * - if some flags are not handled
1254
 
                 * It is helpful only if:
1255
 
                 * - the disc was closed and no plugin can handle this type of 
1256
 
                 * disc once closed (CD-R(W))
1257
 
                 * - there was the flag BLANK_BEFORE_WRITE set and no plugin can
1258
 
                 * handle this flag (means that the plugin should erase and
1259
 
                 * then write on its own. Basically that works only with
1260
 
                 * overwrite formatted discs, DVD+RW, ...) */
1261
 
                if (output.type != BRASERO_TRACK_TYPE_DISC)
1262
 
                        BRASERO_BURN_CAPS_NOT_SUPPORTED_LOG_ERROR (session, error);
1263
 
 
1264
 
                /* output is a disc try with initial blanking */
1265
 
                BRASERO_BURN_LOG ("failed to create proper task. Trying with initial blanking");
1266
 
 
1267
 
                /* apparently nothing can be done to reach our goal. Maybe that
1268
 
                 * is because we first have to blank the disc. If so add a blank 
1269
 
                 * task to the others as a first step */
1270
 
                if (!(session_flags & BRASERO_BURN_FLAG_BLANK_BEFORE_WRITE)
1271
 
                ||    brasero_burn_caps_can_blank (self, session) != BRASERO_BURN_OK)
1272
 
                        BRASERO_BURN_CAPS_NOT_SUPPORTED_LOG_ERROR (session, error);
1273
 
 
1274
 
                /* retry with the same disc type but blank this time */
1275
 
                media &= ~(BRASERO_MEDIUM_CLOSED|
1276
 
                           BRASERO_MEDIUM_APPENDABLE|
1277
 
                           BRASERO_MEDIUM_UNFORMATTED|
1278
 
                           BRASERO_MEDIUM_HAS_DATA|
1279
 
                           BRASERO_MEDIUM_HAS_AUDIO);
1280
 
                media |= BRASERO_MEDIUM_BLANK;
1281
 
 
1282
 
                output.subtype.media = media;
1283
 
 
1284
 
                last_caps = brasero_caps_find_start_caps (&output);
1285
 
                if (!last_caps)
1286
 
                        BRASERO_BURN_CAPS_NOT_SUPPORTED_LOG_ERROR (session, error);
1287
 
 
1288
 
                /* if the flag BLANK_BEFORE_WRITE was set then remove it since
1289
 
                 * we are actually blanking. Simply the record plugin won't have
1290
 
                 * to do it. */
1291
 
                session_flags &= ~BRASERO_BURN_FLAG_BLANK_BEFORE_WRITE;
1292
 
                list = brasero_caps_find_best_link (last_caps,
1293
 
                                                    self->priv->group_id,
1294
 
                                                    NULL,
1295
 
                                                    session_flags,
1296
 
                                                    media,
1297
 
                                                    &input,
1298
 
                                                    flags);
1299
 
                if (!list)
1300
 
                        BRASERO_BURN_CAPS_NOT_SUPPORTED_LOG_ERROR (session, error);
1301
 
 
1302
 
                BRASERO_BURN_LOG ("initial blank/erase task required")
1303
 
 
1304
 
                blanking = brasero_burn_caps_new_blanking_task (self, session, error);
1305
 
                /* The problem here is that we shouldn't always prepend such a 
1306
 
                 * task. For example when we copy a disc to another using the 
1307
 
                 * same drive. In this case we should insert it before the last.
1308
 
                 * Now, that always work so that's what we do in all cases. Once
1309
 
                 * the whole list of tasks is created we insert this blanking
1310
 
                 * task just before the last one. Another advantage is that the
1311
 
                 * blanking of the disc is delayed as late as we can which means
1312
 
                 * in case of error we keep it intact as late as we can. */
1313
 
        }
1314
 
 
1315
 
        /* reverse the list of links to have them in the right order */
1316
 
        list = g_slist_reverse (list);
1317
 
        position = BRASERO_PLUGIN_RUN_PREPROCESSING;
1318
 
        group_id = self->priv->group_id;
1319
 
 
1320
 
        brasero_burn_session_get_input_type (session, &plugin_input);
1321
 
        for (iter = list; iter; iter = iter->next) {
1322
 
                BraseroTrackType plugin_output;
1323
 
                BraseroCapsLink *link;
1324
 
                BraseroPlugin *plugin;
1325
 
                BraseroJob *job;
1326
 
                GSList *result;
1327
 
                GType type;
1328
 
 
1329
 
                link = iter->data;
1330
 
 
1331
 
                /* determine the plugin output */
1332
 
                if (iter->next) {
1333
 
                        BraseroCapsLink *next_link;
1334
 
 
1335
 
                        next_link = iter->next->data;
1336
 
                        if (next_link == link) {
1337
 
                                /* That's a processing plugin so the output must
1338
 
                                 * be the exact same as the input, which is not
1339
 
                                 * necessarily the caps type referred to by the 
1340
 
                                 * link if the link is amongst the first. In
1341
 
                                 * that case that's the session input. */
1342
 
                                memcpy (&plugin_output,
1343
 
                                        &plugin_input,
1344
 
                                        sizeof (BraseroTrackType));
1345
 
                        }
1346
 
                        else {
1347
 
                                memcpy (&plugin_output,
1348
 
                                        &next_link->caps->type,
1349
 
                                        sizeof (BraseroTrackType));
1350
 
                        }
1351
 
                }
1352
 
                else
1353
 
                        memcpy (&plugin_output,
1354
 
                                &output,
1355
 
                                sizeof (BraseroTrackType));
1356
 
 
1357
 
                /* first see if there are track processing plugins */
1358
 
                result = brasero_caps_add_processing_plugins_to_task (session,
1359
 
                                                                      task,
1360
 
                                                                      link->caps,
1361
 
                                                                      &plugin_input,
1362
 
                                                                      position);
1363
 
                retval = g_slist_concat (retval, result);
1364
 
 
1365
 
                /* create job from the best plugin in link */
1366
 
                plugin = brasero_caps_link_find_plugin (link,
1367
 
                                                        group_id,
1368
 
                                                        session_flags,
1369
 
                                                        &plugin_output,
1370
 
                                                        media);
1371
 
                if (!plugin) {
1372
 
                        g_set_error (error,
1373
 
                                     BRASERO_BURN_ERROR,
1374
 
                                     BRASERO_BURN_ERROR_GENERAL,
1375
 
                                     _("An internal error occured"));
1376
 
                        g_slist_foreach (retval, (GFunc) g_object_unref, NULL);
1377
 
                        g_slist_free (retval);
1378
 
                        g_slist_free (list);
1379
 
                        return NULL;
1380
 
                }
1381
 
 
1382
 
                /* This is meant to have plugins in the same group id as much as
1383
 
                 * possible */
1384
 
                if (brasero_plugin_get_group (plugin) > 0 && group_id <= 0)
1385
 
                        group_id = brasero_plugin_get_group (plugin);
1386
 
 
1387
 
                type = brasero_plugin_get_gtype (plugin);
1388
 
                job = BRASERO_JOB (g_object_new (type,
1389
 
                                                 "output", &plugin_output,
1390
 
                                                 NULL));
1391
 
                g_signal_connect (job,
1392
 
                                  "error",
1393
 
                                  G_CALLBACK (brasero_burn_caps_job_error_cb),
1394
 
                                  link);
1395
 
 
1396
 
                if (!task
1397
 
                ||  !(link->caps->flags & BRASERO_PLUGIN_IO_ACCEPT_PIPE)
1398
 
                ||  !BRASERO_BURN_SESSION_NO_TMP_FILE (session)) {
1399
 
                        /* only the last task will be doing the proper action
1400
 
                         * all other are only steps to take to reach the final
1401
 
                         * action */
1402
 
                        BRASERO_BURN_LOG ("New task");
1403
 
                        task = BRASERO_TASK (g_object_new (BRASERO_TYPE_TASK,
1404
 
                                                           "session", session,
1405
 
                                                           "action", BRASERO_TASK_ACTION_NORMAL,
1406
 
                                                           NULL));
1407
 
                        retval = g_slist_append (retval, task);
1408
 
                }
1409
 
 
1410
 
                brasero_task_add_item (task, BRASERO_TASK_ITEM (job));
1411
 
 
1412
 
                BRASERO_BURN_LOG ("%s added to task", brasero_plugin_get_name (plugin));
1413
 
                BRASERO_BURN_LOG_TYPE (&plugin_input, "input");
1414
 
                BRASERO_BURN_LOG_TYPE (&plugin_output, "output");
1415
 
 
1416
 
                position = BRASERO_PLUGIN_RUN_BEFORE_TARGET;
1417
 
 
1418
 
                /* the output of the plugin will become the input of the next */
1419
 
                memcpy (&plugin_input, &plugin_output, sizeof (BraseroTrackType));
1420
 
        }
1421
 
        g_slist_free (list);
1422
 
 
1423
 
        /* add the post processing plugins */
1424
 
        list = brasero_caps_add_processing_plugins_to_task (session,
1425
 
                                                            NULL,
1426
 
                                                            last_caps,
1427
 
                                                            &output,
1428
 
                                                            BRASERO_PLUGIN_RUN_AFTER_TARGET);
1429
 
        retval = g_slist_concat (retval, list);
1430
 
 
1431
 
        if (last_caps->type.type == BRASERO_TRACK_TYPE_DISC && blanking) {
1432
 
                retval = g_slist_insert_before (retval,
1433
 
                                                g_slist_last (retval),
1434
 
                                                blanking);
1435
 
        }
1436
 
 
1437
 
        return retval;
1438
 
}
1439
 
 
1440
 
BraseroTask *
1441
 
brasero_burn_caps_new_checksuming_task (BraseroBurnCaps *self,
1442
 
                                        BraseroBurnSession *session,
1443
 
                                        GError **error)
1444
 
{
1445
 
        BraseroTrackType track_type;
1446
 
        BraseroPlugin *candidate;
1447
 
        BraseroCaps *last_caps;
1448
 
        BraseroTrackType input;
1449
 
        guint checksum_type;
1450
 
        BraseroTrack *track;
1451
 
        BraseroTask *task;
1452
 
        BraseroJob *job;
1453
 
        GSList *tracks;
1454
 
        GSList *links;
1455
 
        GSList *list;
1456
 
        GSList *iter;
1457
 
 
1458
 
        brasero_burn_session_get_input_type (session, &input);
1459
 
        BRASERO_BURN_LOG_WITH_TYPE (&input,
1460
 
                                    BRASERO_PLUGIN_IO_NONE,
1461
 
                                    "Creating checksuming task with input");
1462
 
 
1463
 
        /* first find a checksuming job that can output the type of required
1464
 
         * checksum. Then go through the caps to see if the input type can be
1465
 
         * found. */
1466
 
 
1467
 
        /* some checks */
1468
 
        tracks = brasero_burn_session_get_tracks (session);
1469
 
        if (g_slist_length (tracks) != 1) {
1470
 
                g_set_error (error,
1471
 
                             BRASERO_BURN_ERROR,
1472
 
                             BRASERO_BURN_ERROR_GENERAL,
1473
 
                             _("Only one track at a time can be checked"));
1474
 
                return NULL;
1475
 
        }
1476
 
 
1477
 
        /* get the required checksum type */
1478
 
        track = tracks->data;
1479
 
        checksum_type = brasero_track_get_checksum_type (track);
1480
 
 
1481
 
        links = NULL;
1482
 
        for (iter = self->priv->tests; iter; iter = iter->next) {
1483
 
                BraseroCapsTest *test;
1484
 
 
1485
 
                test = iter->data;
1486
 
                if (!test->links)
1487
 
                        continue;
1488
 
 
1489
 
                /* check this caps test supports the right checksum type */
1490
 
                if (test->type & checksum_type) {
1491
 
                        links = test->links;
1492
 
                        break;
1493
 
                }
1494
 
        }
1495
 
 
1496
 
        if (!links) {
1497
 
                /* we failed to find and create a proper task */
1498
 
                BRASERO_BURN_CAPS_NOT_SUPPORTED_LOG_ERROR (session, error);
1499
 
        }
1500
 
 
1501
 
        list = NULL;
1502
 
        last_caps = NULL;
1503
 
        brasero_track_get_type (track, &track_type);
1504
 
        for (iter = links; iter; iter = iter->next) {
1505
 
                BraseroCapsLink *link;
1506
 
                GSList *plugins;
1507
 
 
1508
 
                link = iter->data;
1509
 
 
1510
 
                /* NOTE: that shouldn't happen */
1511
 
                if (!link->caps)
1512
 
                        continue;
1513
 
 
1514
 
                BRASERO_BURN_LOG_TYPE (&link->caps->type, "Trying link to");
1515
 
 
1516
 
                /* Make sure we have a candidate */
1517
 
                candidate = NULL;
1518
 
                for (plugins = link->plugins; plugins; plugins = plugins->next) {
1519
 
                        BraseroPlugin *plugin;
1520
 
 
1521
 
                        plugin = plugins->data;
1522
 
                        if (!brasero_plugin_get_active (plugin))
1523
 
                                continue;
1524
 
 
1525
 
                        /* note for checksuming task there is no group possible */
1526
 
                        if (!candidate)
1527
 
                                candidate = plugin;
1528
 
                        else if (brasero_plugin_get_priority (plugin) >
1529
 
                                 brasero_plugin_get_priority (candidate))
1530
 
                                candidate = plugin;
1531
 
                }
1532
 
 
1533
 
                if (!candidate)
1534
 
                        continue;
1535
 
 
1536
 
                /* see if it can handle the input or if it can be linked to 
1537
 
                 * another plugin that can */
1538
 
                if (brasero_caps_is_compatible_type (link->caps, &input)) {
1539
 
                        /* this is the right caps */
1540
 
                        last_caps = link->caps;
1541
 
                        break;
1542
 
                }
1543
 
 
1544
 
                /* don't go any further if that's a DISC type */
1545
 
                if (link->caps->type.type == BRASERO_TRACK_TYPE_DISC)
1546
 
                        continue;
1547
 
 
1548
 
                /* the caps itself is not the right one so we try to 
1549
 
                 * go through its links to find the right caps. */
1550
 
                list = brasero_caps_find_best_link (link->caps,
1551
 
                                                    self->priv->group_id,
1552
 
                                                    NULL,
1553
 
                                                    BRASERO_BURN_FLAG_NONE,
1554
 
                                                    BRASERO_MEDIUM_NONE,
1555
 
                                                    &input,
1556
 
                                                    BRASERO_PLUGIN_IO_ACCEPT_PIPE);
1557
 
                if (list) {
1558
 
                        last_caps = link->caps;
1559
 
                        break;
1560
 
                }
1561
 
        }
1562
 
 
1563
 
        if (!last_caps) {
1564
 
                /* no link worked failure */
1565
 
                BRASERO_BURN_CAPS_NOT_SUPPORTED_LOG_ERROR (session, error);
1566
 
        }
1567
 
 
1568
 
        /* we made it. Create task */
1569
 
        task = BRASERO_TASK (g_object_new (BRASERO_TYPE_TASK,
1570
 
                                           "session", session,
1571
 
                                           "action", BRASERO_TASK_ACTION_CHECKSUM,
1572
 
                                           NULL));
1573
 
 
1574
 
        list = g_slist_reverse (list);
1575
 
        for (iter = list; iter; iter = iter->next) {
1576
 
                GType type;
1577
 
                GSList *plugins;
1578
 
                BraseroCapsLink *link;
1579
 
                BraseroPlugin *candidate_plugin;
1580
 
                BraseroTrackType *plugin_output;
1581
 
 
1582
 
                link = iter->data;
1583
 
 
1584
 
                /* determine the plugin output */
1585
 
                if (iter->next) {
1586
 
                        BraseroCapsLink *next_link;
1587
 
 
1588
 
                        next_link = iter->next->data;
1589
 
                        plugin_output = &next_link->caps->type;
1590
 
                }
1591
 
                else
1592
 
                        plugin_output = &last_caps->type;
1593
 
 
1594
 
                /* find the best plugin */
1595
 
                candidate_plugin = NULL;
1596
 
                for (plugins = link->plugins; plugins; plugins = plugins->next) {
1597
 
                        BraseroPlugin *plugin;
1598
 
 
1599
 
                        plugin = plugins->data;
1600
 
 
1601
 
                        if (!brasero_plugin_get_active (plugin))
1602
 
                                continue;
1603
 
 
1604
 
                        if (!candidate_plugin)
1605
 
                                candidate_plugin = plugin;
1606
 
                        else if (brasero_plugin_get_priority (plugin) >
1607
 
                                 brasero_plugin_get_priority (candidate_plugin))
1608
 
                                candidate_plugin = plugin;
1609
 
                }
1610
 
 
1611
 
                /* create the object */
1612
 
                type = brasero_plugin_get_gtype (candidate_plugin);
1613
 
                job = BRASERO_JOB (g_object_new (type,
1614
 
                                                 "output", plugin_output,
1615
 
                                                 NULL));
1616
 
                g_signal_connect (job,
1617
 
                                  "error",
1618
 
                                  G_CALLBACK (brasero_burn_caps_job_error_cb),
1619
 
                                  link);
1620
 
 
1621
 
                brasero_task_add_item (task, BRASERO_TASK_ITEM (job));
1622
 
 
1623
 
                BRASERO_BURN_LOG ("%s added to task", brasero_plugin_get_name (candidate_plugin));
1624
 
        }
1625
 
        g_slist_free (list);
1626
 
 
1627
 
        /* Create the candidate */
1628
 
        job = BRASERO_JOB (g_object_new (brasero_plugin_get_gtype (candidate),
1629
 
                                         "output", NULL,
1630
 
                                         NULL));
1631
 
        g_signal_connect (job,
1632
 
                          "error",
1633
 
                          G_CALLBACK (brasero_burn_caps_job_error_cb),
1634
 
                          self);
1635
 
        brasero_task_add_item (task, BRASERO_TASK_ITEM (job));
1636
 
 
1637
 
        return task;
1638
 
}
1639
 
 
1640
 
static gboolean
1641
 
brasero_caps_find_link (BraseroCaps *caps,
1642
 
                        BraseroBurnFlag session_flags,
1643
 
                        gboolean use_flags,
1644
 
                        BraseroMedia media,
1645
 
                        BraseroTrackType *input,
1646
 
                        BraseroPluginIOFlag io_flags)
1647
 
{
1648
 
        GSList *iter;
1649
 
 
1650
 
        BRASERO_BURN_LOG_WITH_TYPE (&caps->type, BRASERO_PLUGIN_IO_NONE, "find_link");
1651
 
 
1652
 
        /* Here we only make sure we have at least one link working. For a link
1653
 
         * to be followed it must first:
1654
 
         * - link to a caps with correct io flags
1655
 
         * - have at least a plugin accepting the record flags if caps type is
1656
 
         *   a disc (that means that the link is the recording part)
1657
 
         *
1658
 
         * and either:
1659
 
         * - link to a caps equal to the input
1660
 
         * - link to a caps (linking itself to another caps, ...) accepting the
1661
 
         *   input
1662
 
         */
1663
 
 
1664
 
        for (iter = caps->links; iter; iter = iter->next) {
1665
 
                BraseroCapsLink *link;
1666
 
                gboolean result;
1667
 
 
1668
 
                link = iter->data;
1669
 
 
1670
 
                if (!link->caps)
1671
 
                        continue;
1672
 
 
1673
 
                /* check that the link has some active plugin */
1674
 
                if (!brasero_caps_link_active (link))
1675
 
                        continue;
1676
 
 
1677
 
                /* since this link contains recorders, check that at least one
1678
 
                 * of them can handle the record flags */
1679
 
                if (use_flags
1680
 
                &&  caps->type.type == BRASERO_TRACK_TYPE_DISC
1681
 
                && !brasero_caps_link_check_record_flags (link, session_flags, media))
1682
 
                        continue;
1683
 
 
1684
 
                /* first see if that's the perfect fit:
1685
 
                 * - it must have the same caps (type + subtype)
1686
 
                 * - it must have the proper IO */
1687
 
                if (link->caps->type.type == BRASERO_TRACK_TYPE_DATA) {
1688
 
                        if (use_flags
1689
 
                        && !brasero_caps_link_check_data_flags (link, session_flags, media))
1690
 
                                continue;
1691
 
                }
1692
 
                else if (!brasero_caps_link_check_media_restrictions (link, media))
1693
 
                        continue;
1694
 
 
1695
 
                if ((link->caps->flags & BRASERO_PLUGIN_IO_ACCEPT_FILE)
1696
 
                &&   brasero_caps_is_compatible_type (link->caps, input))
1697
 
                        return TRUE;
1698
 
 
1699
 
                /* we can't go further than a DISC type */
1700
 
                if (link->caps->type.type == BRASERO_TRACK_TYPE_DISC)
1701
 
                        continue;
1702
 
 
1703
 
                if ((link->caps->flags & io_flags) == BRASERO_PLUGIN_IO_NONE)
1704
 
                        continue;
1705
 
 
1706
 
                /* try to see where the inputs of this caps leads to */
1707
 
                result = brasero_caps_find_link (link->caps,
1708
 
                                                 session_flags,
1709
 
                                                 use_flags,
1710
 
                                                 media,
1711
 
                                                 input,
1712
 
                                                 io_flags);
1713
 
                if (result)
1714
 
                        return TRUE;
1715
 
        }
1716
 
 
1717
 
        return FALSE;
1718
 
}
1719
 
 
1720
 
static gboolean
1721
 
brasero_caps_try_output (BraseroBurnFlag session_flags,
1722
 
                         gboolean use_flags,
1723
 
                         BraseroTrackType *output,
1724
 
                         BraseroTrackType *input,
1725
 
                         BraseroPluginIOFlag flags)
1726
 
{
1727
 
        BraseroCaps *caps;
1728
 
        BraseroMedia media;
1729
 
 
1730
 
        /* here we search the start caps */
1731
 
        caps = brasero_caps_find_start_caps (output);
1732
 
        if (!caps) {
1733
 
                BRASERO_BURN_LOG ("No caps available");
1734
 
                return FALSE;
1735
 
        }
1736
 
 
1737
 
        if (output->type == BRASERO_TRACK_TYPE_DISC)
1738
 
                media = output->subtype.media;
1739
 
        else
1740
 
                media = BRASERO_MEDIUM_FILE;
1741
 
 
1742
 
        return brasero_caps_find_link (caps,
1743
 
                                       session_flags,
1744
 
                                       use_flags,
1745
 
                                       media,
1746
 
                                       input,
1747
 
                                       flags);
1748
 
}
1749
 
 
1750
 
static gboolean
1751
 
brasero_caps_try_output_with_blanking (BraseroBurnCaps *self,
1752
 
                                       BraseroBurnSession *session,
1753
 
                                       BraseroTrackType *output,
1754
 
                                       BraseroTrackType *input,
1755
 
                                       BraseroPluginIOFlag io_flags,
1756
 
                                       gboolean use_flags)
1757
 
{
1758
 
        gboolean result;
1759
 
        BraseroMedia media;
1760
 
        BraseroCaps *last_caps;
1761
 
        BraseroBurnFlag session_flags = BRASERO_BURN_FLAG_NONE;
1762
 
 
1763
 
        if (use_flags)
1764
 
                session_flags = brasero_burn_session_get_flags (session);
1765
 
 
1766
 
        result = brasero_caps_try_output (session_flags,
1767
 
                                          use_flags,
1768
 
                                          output,
1769
 
                                          input,
1770
 
                                          io_flags);
1771
 
        if (result)
1772
 
                return result;
1773
 
 
1774
 
        /* we reached this point in two cases:
1775
 
         * - if the disc cannot be handled
1776
 
         * - if some flags are not handled
1777
 
         * It is helpful only if:
1778
 
         * - the disc was closed and no plugin can handle this type of 
1779
 
         * disc once closed (CD-R(W))
1780
 
         * - there was the flag BLANK_BEFORE_WRITE set and no plugin can
1781
 
         * handle this flag (means that the plugin should erase and
1782
 
         * then write on its own. Basically that works only with
1783
 
         * overwrite formatted discs, DVD+RW, ...) */
1784
 
        if (output->type != BRASERO_TRACK_TYPE_DISC)
1785
 
                return FALSE;
1786
 
 
1787
 
        /* output is a disc try with initial blanking */
1788
 
        BRASERO_BURN_LOG ("Support for input/output failed.");
1789
 
 
1790
 
        /* apparently nothing can be done to reach our goal. Maybe that
1791
 
         * is because we first have to blank the disc. If so add a blank 
1792
 
         * task to the others as a first step */
1793
 
        if ((use_flags && !(session_flags & BRASERO_BURN_FLAG_BLANK_BEFORE_WRITE))
1794
 
        ||   brasero_burn_caps_can_blank (self, session) != BRASERO_BURN_OK)
1795
 
                return FALSE;
1796
 
 
1797
 
        BRASERO_BURN_LOG ("Trying with initial blanking");
1798
 
 
1799
 
        /* retry with the same disc type but blank this time */
1800
 
        media = output->subtype.media;
1801
 
        media &= ~(BRASERO_MEDIUM_CLOSED|
1802
 
                   BRASERO_MEDIUM_APPENDABLE|
1803
 
                   BRASERO_MEDIUM_UNFORMATTED|
1804
 
                   BRASERO_MEDIUM_HAS_DATA|
1805
 
                   BRASERO_MEDIUM_HAS_AUDIO);
1806
 
        media |= BRASERO_MEDIUM_BLANK;
1807
 
        output->subtype.media = media;
1808
 
 
1809
 
        last_caps = brasero_caps_find_start_caps (output);
1810
 
        if (!last_caps)
1811
 
                return FALSE;
1812
 
 
1813
 
        return brasero_caps_find_link (last_caps,
1814
 
                                       session_flags,
1815
 
                                       use_flags,
1816
 
                                       media,
1817
 
                                       input,
1818
 
                                       io_flags);
1819
 
}
1820
 
 
1821
 
BraseroBurnResult
1822
 
brasero_burn_caps_is_input_supported (BraseroBurnCaps *self,
1823
 
                                      BraseroBurnSession *session,
1824
 
                                      BraseroTrackType *input,
1825
 
                                      gboolean use_flags)
1826
 
{
1827
 
        gboolean result;
1828
 
        BraseroTrackType output;
1829
 
        BraseroPluginIOFlag io_flags;
1830
 
 
1831
 
        if (use_flags && !brasero_burn_caps_flags_check_for_drive (session))
1832
 
                BRASERO_BURN_CAPS_NOT_SUPPORTED_LOG_RES (session);
1833
 
 
1834
 
        if (!brasero_burn_session_is_dest_file (session)) {
1835
 
                output.type = BRASERO_TRACK_TYPE_DISC;
1836
 
                output.subtype.media = brasero_burn_session_get_dest_media (session);
1837
 
 
1838
 
                /* NOTE: for the special case where a disc could be rewritten
1839
 
                 * and cannot be handled as such but needs prior blanking, we
1840
 
                 * handle that situation in previous function.*/
1841
 
        }
1842
 
        else {
1843
 
                output.type = BRASERO_TRACK_TYPE_IMAGE;
1844
 
                output.subtype.img_format = brasero_burn_session_get_output_format (session);
1845
 
        }
1846
 
 
1847
 
        if (BRASERO_BURN_SESSION_NO_TMP_FILE (session))
1848
 
                io_flags = BRASERO_PLUGIN_IO_ACCEPT_PIPE;
1849
 
        else
1850
 
                io_flags = BRASERO_PLUGIN_IO_ACCEPT_FILE;
1851
 
 
1852
 
        BRASERO_BURN_LOG_TYPE (input, "Checking support for input");
1853
 
        BRASERO_BURN_LOG_TYPE (&output, "and output");
1854
 
 
1855
 
        if (use_flags)
1856
 
                BRASERO_BURN_LOG_FLAGS (brasero_burn_session_get_flags (session), "with flags");
1857
 
 
1858
 
        result = brasero_caps_try_output_with_blanking (self,
1859
 
                                                        session,
1860
 
                                                        &output,
1861
 
                                                        input,
1862
 
                                                        io_flags,
1863
 
                                                        use_flags);
1864
 
        if (!result) {
1865
 
                BRASERO_BURN_LOG_TYPE (input, "Input not supported");
1866
 
                return BRASERO_BURN_NOT_SUPPORTED;
1867
 
        }
1868
 
 
1869
 
        return BRASERO_BURN_OK;
1870
 
}
1871
 
 
1872
 
BraseroBurnResult
1873
 
brasero_burn_caps_is_output_supported (BraseroBurnCaps *self,
1874
 
                                       BraseroBurnSession *session,
1875
 
                                       BraseroTrackType *output)
1876
 
{
1877
 
        gboolean result;
1878
 
        BraseroTrackType input;
1879
 
        BraseroPluginIOFlag io_flags;
1880
 
 
1881
 
        /* Here, we can't check if the drive supports the flags since the output
1882
 
         * is hypothetical. There is no real medium. So forget the following :
1883
 
         * if (!brasero_burn_caps_flags_check_for_drive (session))
1884
 
         *      BRASERO_BURN_CAPS_NOT_SUPPORTED_LOG_RES (session);
1885
 
         * The only thing we could do would be to check some known forbidden 
1886
 
         * flags for some media provided the output type is DISC. */
1887
 
 
1888
 
        /* Here flags don't matter as we don't record anything. Even the IOFlags
1889
 
         * since that can be checked later with brasero_burn_caps_get_flags. */
1890
 
        if (BRASERO_BURN_SESSION_NO_TMP_FILE (session))
1891
 
                io_flags = BRASERO_PLUGIN_IO_ACCEPT_PIPE;
1892
 
        else
1893
 
                io_flags = BRASERO_PLUGIN_IO_ACCEPT_FILE;
1894
 
 
1895
 
        brasero_burn_session_get_input_type (session, &input);
1896
 
        BRASERO_BURN_LOG_TYPE (output, "Checking support for output");
1897
 
        BRASERO_BURN_LOG_TYPE (&input, "and input");
1898
 
        BRASERO_BURN_LOG_FLAGS (brasero_burn_session_get_flags (session), "with flags");
1899
 
        
1900
 
        result = brasero_caps_try_output_with_blanking (self,
1901
 
                                                        session,
1902
 
                                                        output,
1903
 
                                                        &input,
1904
 
                                                        io_flags,
1905
 
                                                        TRUE);
1906
 
        if (!result) {
1907
 
                BRASERO_BURN_LOG_TYPE (output, "Output not supported");
1908
 
                return BRASERO_BURN_NOT_SUPPORTED;
1909
 
        }
1910
 
 
1911
 
        return BRASERO_BURN_OK;
1912
 
}
1913
 
 
1914
 
/**
1915
 
 * This is only to be used in case one wants to copy using the same drive.
1916
 
 * It determines the possible middle image type.
1917
 
 */
1918
 
 
1919
 
static BraseroBurnResult
1920
 
brasero_burn_caps_is_session_supported_same_src_dest (BraseroBurnCaps *self,
1921
 
                                                      BraseroBurnSession *session,
1922
 
                                                      gboolean use_flags)
1923
 
{
1924
 
        GSList *iter;
1925
 
        BraseroTrackType input;
1926
 
        BraseroTrackType output;
1927
 
        BraseroImageFormat format;
1928
 
        BraseroBurnFlag session_flags;
1929
 
 
1930
 
        BRASERO_BURN_LOG ("Checking disc copy support with same source and destination");
1931
 
 
1932
 
        /* To determine if a CD/DVD can be copied using the same source/dest,
1933
 
         * we first determine if can be imaged and then if this image can be 
1934
 
         * burnt to whatever medium type. */
1935
 
        memset (&input, 0, sizeof (BraseroTrackType));
1936
 
        brasero_burn_session_get_input_type (session, &input);
1937
 
        BRASERO_BURN_LOG_TYPE (&input, "input");
1938
 
 
1939
 
        if (use_flags) {
1940
 
                /* NOTE: DAO can be a problem. So just in case remove it. It is
1941
 
                 * not really useful in this context. What we want here is to
1942
 
                 * know whether a medium can be used given the input; only 1
1943
 
                 * flag is important here (MERGE) and can have consequences. */
1944
 
                session_flags = brasero_burn_session_get_flags (session);
1945
 
                session_flags &= ~BRASERO_BURN_FLAG_DAO;
1946
 
 
1947
 
                BRASERO_BURN_LOG_FLAGS (session_flags, "flags");
1948
 
        }
1949
 
        else
1950
 
                session_flags = BRASERO_BURN_FLAG_NONE;
1951
 
 
1952
 
        /* Find one available output format */
1953
 
        format = BRASERO_IMAGE_FORMAT_CDRDAO;
1954
 
        output.type = BRASERO_TRACK_TYPE_IMAGE;
1955
 
 
1956
 
        for (; format > BRASERO_IMAGE_FORMAT_NONE; format >>= 1) {
1957
 
                gboolean supported;
1958
 
 
1959
 
                output.subtype.img_format = format;
1960
 
 
1961
 
                BRASERO_BURN_LOG_TYPE (&output, "Testing temporary image format");
1962
 
                supported = brasero_caps_try_output_with_blanking (self,
1963
 
                                                                   session,
1964
 
                                                                   &output,
1965
 
                                                                   &input,
1966
 
                                                                   BRASERO_PLUGIN_IO_ACCEPT_FILE,
1967
 
                                                                   use_flags);
1968
 
                if (!supported)
1969
 
                        continue;
1970
 
 
1971
 
                /* This format can be used to create an image. Check if can be
1972
 
                 * burnt now. Just find at least one medium. */
1973
 
                for (iter = self->priv->caps_list; iter; iter = iter->next) {
1974
 
                        BraseroCaps *caps;
1975
 
                        gboolean result;
1976
 
 
1977
 
                        caps = iter->data;
1978
 
 
1979
 
                        if (caps->type.type != BRASERO_TRACK_TYPE_DISC)
1980
 
                                continue;
1981
 
 
1982
 
                        result = brasero_caps_find_link (caps,
1983
 
                                                         TRUE,
1984
 
                                                         session_flags,
1985
 
                                                         caps->type.subtype.media,
1986
 
                                                         &input,
1987
 
                                                         BRASERO_PLUGIN_IO_ACCEPT_FILE);
1988
 
 
1989
 
                        BRASERO_BURN_LOG_DISC_TYPE (caps->type.subtype.media,
1990
 
                                                    "Tested medium (%s)",
1991
 
                                                    result ? "working":"not working");
1992
 
 
1993
 
                        if (result)
1994
 
                                return BRASERO_BURN_OK;
1995
 
                }
1996
 
        }
1997
 
 
1998
 
        return BRASERO_BURN_NOT_SUPPORTED;
1999
 
}
2000
 
 
2001
 
BraseroBurnResult
2002
 
brasero_burn_caps_is_session_supported (BraseroBurnCaps *self,
2003
 
                                        BraseroBurnSession *session,
2004
 
                                        gboolean use_flags)
2005
 
{
2006
 
        gboolean result;
2007
 
        BraseroTrackType input;
2008
 
        BraseroTrackType output;
2009
 
        BraseroPluginIOFlag io_flags;
2010
 
 
2011
 
        /* Special case */
2012
 
        if (brasero_burn_session_same_src_dest_drive (session))
2013
 
                return brasero_burn_caps_is_session_supported_same_src_dest (self, session, use_flags);
2014
 
 
2015
 
        if (use_flags && !brasero_burn_caps_flags_check_for_drive (session))
2016
 
                BRASERO_BURN_CAPS_NOT_SUPPORTED_LOG_RES (session);
2017
 
 
2018
 
        /* Here flags don't matter as we don't record anything.
2019
 
         * Even the IOFlags since that can be checked later with
2020
 
         * brasero_burn_caps_get_flags. */
2021
 
        if (BRASERO_BURN_SESSION_NO_TMP_FILE (session))
2022
 
                io_flags = BRASERO_PLUGIN_IO_ACCEPT_PIPE;
2023
 
        else
2024
 
                io_flags = BRASERO_PLUGIN_IO_ACCEPT_FILE;
2025
 
 
2026
 
        brasero_burn_session_get_input_type (session, &input);
2027
 
 
2028
 
        if (!brasero_burn_session_is_dest_file (session)) {
2029
 
                output.type = BRASERO_TRACK_TYPE_DISC;
2030
 
                output.subtype.media = brasero_burn_session_get_dest_media (session);
2031
 
 
2032
 
                /* NOTE: for the special case where a disc could be rewritten
2033
 
                 * and cannot be handled as such but needs prior blanking, we
2034
 
                 * handle that situation in previous function.*/
2035
 
        }
2036
 
        else {
2037
 
                output.type = BRASERO_TRACK_TYPE_IMAGE;
2038
 
                output.subtype.img_format = brasero_burn_session_get_output_format (session);
2039
 
        }
2040
 
 
2041
 
        BRASERO_BURN_LOG_TYPE (&output, "Checking support for session output");
2042
 
        BRASERO_BURN_LOG_TYPE (&input, "and input");
2043
 
 
2044
 
        if (use_flags)
2045
 
                BRASERO_BURN_LOG_FLAGS (brasero_burn_session_get_flags (session), "with flags");
2046
 
 
2047
 
        result = brasero_caps_try_output_with_blanking (self,
2048
 
                                                        session,
2049
 
                                                        &output,
2050
 
                                                        &input,
2051
 
                                                        io_flags,
2052
 
                                                        use_flags);
2053
 
        if (!result) {
2054
 
                BRASERO_BURN_LOG_TYPE (&output, "Output not supported");
2055
 
                return BRASERO_BURN_NOT_SUPPORTED;
2056
 
        }
2057
 
 
2058
 
        return BRASERO_BURN_OK;
2059
 
}
2060
 
 
2061
 
BraseroMedia
2062
 
brasero_burn_caps_get_required_media_type (BraseroBurnCaps *self,
2063
 
                                           BraseroBurnSession *session)
2064
 
{
2065
 
        BraseroMedia required_media = BRASERO_MEDIUM_NONE;
2066
 
        BraseroBurnFlag session_flags;
2067
 
        BraseroPluginIOFlag io_flags;
2068
 
        BraseroTrackType input;
2069
 
        GSList *iter;
2070
 
 
2071
 
        if (brasero_burn_session_is_dest_file (session))
2072
 
                return BRASERO_MEDIUM_FILE;
2073
 
 
2074
 
        /* we try to determine here what type of medium is allowed to be burnt
2075
 
         * to whether a CD or a DVD. Appendable, blank are not properties being
2076
 
         * determined here. We just want it to be writable in a broad sense. */
2077
 
        brasero_burn_session_get_input_type (session, &input);
2078
 
        BRASERO_BURN_LOG_TYPE (&input, "Determining required media type for input");
2079
 
 
2080
 
        /* NOTE: BRASERO_BURN_FLAG_BLANK_BEFORE_WRITE is a problem here since it
2081
 
         * is only used if needed. Likewise DAO can be a problem. So just in
2082
 
         * case remove them. They are not really useful in this context. What we
2083
 
         * want here is to know which media can be used given the input; only 1
2084
 
         * flag is important here (MERGE) and can have consequences. */
2085
 
        session_flags = brasero_burn_session_get_flags (session);
2086
 
        session_flags &= ~BRASERO_BURN_FLAG_DAO;
2087
 
 
2088
 
        BRASERO_BURN_LOG_FLAGS (session_flags, "and flags");
2089
 
 
2090
 
        if (BRASERO_BURN_SESSION_NO_TMP_FILE (session))
2091
 
                io_flags = BRASERO_PLUGIN_IO_ACCEPT_PIPE;
2092
 
        else
2093
 
                io_flags = BRASERO_PLUGIN_IO_ACCEPT_FILE;
2094
 
 
2095
 
        for (iter = self->priv->caps_list; iter; iter = iter->next) {
2096
 
                BraseroCaps *caps;
2097
 
                gboolean result;
2098
 
 
2099
 
                caps = iter->data;
2100
 
 
2101
 
                if (caps->type.type != BRASERO_TRACK_TYPE_DISC)
2102
 
                        continue;
2103
 
 
2104
 
                /* Put BRASERO_MEDIUM_NONE so we can always succeed */
2105
 
                result = brasero_caps_find_link (caps,
2106
 
                                                 session_flags,
2107
 
                                                 TRUE,
2108
 
                                                 BRASERO_MEDIUM_NONE,
2109
 
                                                 &input,
2110
 
                                                 io_flags);
2111
 
 
2112
 
                BRASERO_BURN_LOG_DISC_TYPE (caps->type.subtype.media,
2113
 
                                            "Tested (%s)",
2114
 
                                            result ? "working":"not working");
2115
 
 
2116
 
                if (!result)
2117
 
                        continue;
2118
 
 
2119
 
                /* This caps work, add its subtype */
2120
 
                required_media |= caps->type.subtype.media;
2121
 
        }
2122
 
 
2123
 
        /* filter as we are only interested in these */
2124
 
        required_media &= BRASERO_MEDIUM_WRITABLE|
2125
 
                          BRASERO_MEDIUM_CD|
2126
 
                          BRASERO_MEDIUM_DVD;
2127
 
 
2128
 
        return required_media;
2129
 
}
2130
 
 
2131
 
BraseroImageFormat
2132
 
brasero_burn_caps_get_default_output_format (BraseroBurnCaps *self,
2133
 
                                             BraseroBurnSession *session)
2134
 
{
2135
 
        BraseroTrackType source;
2136
 
        BraseroTrackType output;
2137
 
        BraseroBurnResult result;
2138
 
 
2139
 
        if (!brasero_burn_session_is_dest_file (session))
2140
 
                return BRASERO_IMAGE_FORMAT_NONE;
2141
 
 
2142
 
        brasero_burn_session_get_input_type (session, &source);
2143
 
        if (source.type == BRASERO_TRACK_TYPE_NONE)
2144
 
                return BRASERO_IMAGE_FORMAT_NONE;
2145
 
 
2146
 
        if (source.type == BRASERO_TRACK_TYPE_IMAGE)
2147
 
                return source.subtype.img_format;
2148
 
 
2149
 
        output.type = BRASERO_TRACK_TYPE_IMAGE;
2150
 
        output.subtype.img_format = BRASERO_IMAGE_FORMAT_NONE;
2151
 
 
2152
 
        if (source.type == BRASERO_TRACK_TYPE_AUDIO) {
2153
 
                /* If that's AUDIO only without VIDEO then return */
2154
 
                if (!(source.subtype.audio_format & (BRASERO_VIDEO_FORMAT_UNDEFINED|BRASERO_VIDEO_FORMAT_VCD|BRASERO_VIDEO_FORMAT_VIDEO_DVD)))
2155
 
                        return BRASERO_IMAGE_FORMAT_NONE;
2156
 
 
2157
 
                /* Otherwise try all possible image types */
2158
 
                output.subtype.img_format = BRASERO_IMAGE_FORMAT_CDRDAO;
2159
 
                for (; output.subtype.img_format != BRASERO_IMAGE_FORMAT_NONE;
2160
 
                       output.subtype.img_format >>= 1) {
2161
 
                
2162
 
                        result = brasero_burn_caps_is_output_supported (self,
2163
 
                                                                        session,
2164
 
                                                                        &output);
2165
 
                        if (result == BRASERO_BURN_OK)
2166
 
                                return output.subtype.img_format;
2167
 
                }
2168
 
 
2169
 
                return BRASERO_IMAGE_FORMAT_NONE;
2170
 
        }
2171
 
 
2172
 
        if (source.type == BRASERO_TRACK_TYPE_DATA
2173
 
        || (source.type == BRASERO_TRACK_TYPE_DISC
2174
 
        && (source.subtype.media & BRASERO_MEDIUM_DVD))) {
2175
 
                output.subtype.img_format = BRASERO_IMAGE_FORMAT_BIN;
2176
 
                result = brasero_burn_caps_is_output_supported (self,
2177
 
                                                                session,
2178
 
                                                                &output);
2179
 
                if (result != BRASERO_BURN_OK)
2180
 
                        return BRASERO_IMAGE_FORMAT_NONE;
2181
 
 
2182
 
                return BRASERO_IMAGE_FORMAT_BIN;
2183
 
        }
2184
 
 
2185
 
        /* for the input which are CDs there are lots of possible formats */
2186
 
        output.subtype.img_format = BRASERO_IMAGE_FORMAT_CDRDAO;
2187
 
        for (; output.subtype.img_format != BRASERO_IMAGE_FORMAT_NONE;
2188
 
               output.subtype.img_format >>= 1) {
2189
 
        
2190
 
                result = brasero_burn_caps_is_output_supported (self,
2191
 
                                                                session,
2192
 
                                                                &output);
2193
 
                if (result == BRASERO_BURN_OK)
2194
 
                        return output.subtype.img_format;
2195
 
        }
2196
 
 
2197
 
        return BRASERO_IMAGE_FORMAT_NONE;
2198
 
}
2199
 
 
2200
 
static BraseroCapsLink *
2201
 
brasero_caps_find_link_for_input (BraseroCaps *caps,
2202
 
                                  BraseroCaps *input)
2203
 
{
2204
 
        GSList *links;
2205
 
 
2206
 
        for (links = caps->links; links; links = links->next) {
2207
 
                BraseroCapsLink *link;
2208
 
 
2209
 
                link = links->data;
2210
 
                if (link->caps == input)
2211
 
                        return link;
2212
 
        }
2213
 
 
2214
 
        return NULL;
2215
 
}
2216
 
 
2217
 
static gboolean
2218
 
brasero_caps_has_active_input (BraseroCaps *caps,
2219
 
                               BraseroCaps *input)
2220
 
{
2221
 
        GSList *links;
2222
 
 
2223
 
        for (links = caps->links; links; links = links->next) {
2224
 
                BraseroCapsLink *link;
2225
 
 
2226
 
                link = links->data;
2227
 
                if (link->caps != input)
2228
 
                        continue;
2229
 
 
2230
 
                if (brasero_caps_link_active (link))
2231
 
                        return TRUE;
2232
 
        }
2233
 
 
2234
 
        return FALSE;
2235
 
}
2236
 
 
2237
 
static gboolean
2238
 
brasero_burn_caps_is_input (BraseroBurnCaps *self,
2239
 
                            BraseroCaps *input)
2240
 
{
2241
 
        GSList *iter;
2242
 
 
2243
 
        for (iter = self->priv->caps_list; iter; iter = iter->next) {
2244
 
                BraseroCaps *tmp;
2245
 
 
2246
 
                tmp = iter->data;
2247
 
                if (tmp == input)
2248
 
                        continue;
2249
 
 
2250
 
                if (brasero_caps_has_active_input (tmp, input))
2251
 
                        return TRUE;
2252
 
        }
2253
 
 
2254
 
        return FALSE;
2255
 
}
2256
 
 
2257
 
static BraseroPluginIOFlag
2258
 
brasero_caps_get_flags (BraseroCaps *caps,
2259
 
                        BraseroBurnFlag session_flags,
2260
 
                        BraseroMedia media,
2261
 
                        BraseroTrackType *input,
2262
 
                        BraseroPluginIOFlag flags,
2263
 
                        BraseroBurnFlag *supported,
2264
 
                        BraseroBurnFlag *compulsory)
2265
 
{
2266
 
        GSList *iter;
2267
 
        BraseroPluginIOFlag retval = BRASERO_PLUGIN_IO_NONE;
2268
 
 
2269
 
        /* First we must know if this link leads somewhere. It must 
2270
 
         * accept the already existing flags. If it does, see if it 
2271
 
         * accepts the input and if not, if one of its ancestors does */
2272
 
        for (iter = caps->links; iter; iter = iter->next) {
2273
 
                BraseroBurnFlag data_supported = BRASERO_BURN_FLAG_NONE;
2274
 
                BraseroBurnFlag rec_compulsory = BRASERO_BURN_FLAG_ALL;
2275
 
                BraseroBurnFlag rec_supported = BRASERO_BURN_FLAG_NONE;
2276
 
                BraseroPluginIOFlag io_flags;
2277
 
                BraseroCapsLink *link;
2278
 
 
2279
 
                link = iter->data;
2280
 
 
2281
 
                if (!link->caps)
2282
 
                        continue;
2283
 
 
2284
 
                /* check that the link has some active plugin */
2285
 
                if (!brasero_caps_link_active (link))
2286
 
                        continue;
2287
 
 
2288
 
                if (caps->type.type == BRASERO_TRACK_TYPE_DISC) {
2289
 
                        BraseroBurnFlag tmp;
2290
 
 
2291
 
                        brasero_caps_link_get_record_flags (link,
2292
 
                                                            media,
2293
 
                                                            session_flags,
2294
 
                                                            &rec_supported,
2295
 
                                                            &rec_compulsory);
2296
 
 
2297
 
                        /* see if that link can handle the record flags.
2298
 
                         * NOTE: compulsory are not a failure in this case. */
2299
 
                        tmp = session_flags & BRASERO_PLUGIN_BURN_FLAG_MASK;
2300
 
                        if ((tmp & rec_supported) != tmp)
2301
 
                                continue;
2302
 
                }
2303
 
 
2304
 
                if (link->caps->type.type == BRASERO_TRACK_TYPE_DATA) {
2305
 
                        BraseroBurnFlag tmp;
2306
 
 
2307
 
                        brasero_caps_link_get_data_flags (link,
2308
 
                                                          media,
2309
 
                                                          session_flags,
2310
 
                                                          &data_supported);
2311
 
 
2312
 
                        /* see if that link can handle the data flags. 
2313
 
                         * NOTE: compulsory are not a failure in this case. */
2314
 
                        tmp = session_flags & (BRASERO_BURN_FLAG_APPEND|
2315
 
                                               BRASERO_BURN_FLAG_MERGE);
2316
 
 
2317
 
                        if ((tmp & data_supported) != tmp)
2318
 
                                continue;
2319
 
                }
2320
 
                else if (!brasero_caps_link_check_media_restrictions (link, media))
2321
 
                        continue;
2322
 
 
2323
 
                /* see if that's the perfect fit */
2324
 
                if ((link->caps->flags & BRASERO_PLUGIN_IO_ACCEPT_FILE)
2325
 
                &&   brasero_caps_is_compatible_type (link->caps, input)) {
2326
 
                        /* special case for input that handle output/input */
2327
 
                        if (caps->type.type == BRASERO_TRACK_TYPE_DISC)
2328
 
                                retval |= BRASERO_PLUGIN_IO_ACCEPT_PIPE;
2329
 
                        else
2330
 
                                retval |= caps->flags;
2331
 
 
2332
 
                        (*compulsory) &= rec_compulsory;
2333
 
                        (*supported) |= data_supported|rec_supported;
2334
 
                        continue;
2335
 
                }
2336
 
 
2337
 
                if ((link->caps->flags & flags) == BRASERO_PLUGIN_IO_NONE)
2338
 
                        continue;
2339
 
 
2340
 
                /* we can't go further than a DISC type */
2341
 
                if (link->caps->type.type == BRASERO_TRACK_TYPE_DISC)
2342
 
                        continue;
2343
 
 
2344
 
                /* try to see where the inputs of this caps leads to */
2345
 
                io_flags = brasero_caps_get_flags (link->caps,
2346
 
                                                   session_flags,
2347
 
                                                   media,
2348
 
                                                   input,
2349
 
                                                   flags,
2350
 
                                                   supported,
2351
 
                                                   compulsory);
2352
 
                if (io_flags == BRASERO_PLUGIN_IO_NONE)
2353
 
                        continue;
2354
 
 
2355
 
                retval |= (io_flags & flags);
2356
 
                (*compulsory) &= rec_compulsory;
2357
 
                (*supported) |= data_supported|rec_supported;
2358
 
        }
2359
 
 
2360
 
        return retval;
2361
 
}
2362
 
 
2363
 
static BraseroBurnFlag
2364
 
brasero_burn_caps_flags_update_for_drive (BraseroBurnFlag flags,
2365
 
                                          BraseroBurnSession *session)
2366
 
{
2367
 
        BraseroDrive *drive;
2368
 
        BraseroMedium *medium;
2369
 
 
2370
 
        drive = brasero_burn_session_get_burner (session);
2371
 
        if (!drive)
2372
 
                return flags;
2373
 
 
2374
 
        medium = brasero_drive_get_medium (drive);
2375
 
        if (!medium)
2376
 
                return TRUE;
2377
 
 
2378
 
        return brasero_medium_supported_flags (medium, flags);
2379
 
}
2380
 
 
2381
 
static BraseroBurnResult
2382
 
brasero_caps_get_flags_for_disc (BraseroBurnFlag session_flags,
2383
 
                                 BraseroMedia media,
2384
 
                                 BraseroTrackType *input,
2385
 
                                 BraseroBurnFlag *supported,
2386
 
                                 BraseroBurnFlag *compulsory)
2387
 
{
2388
 
        BraseroBurnFlag supported_flags = BRASERO_BURN_FLAG_NONE;
2389
 
        BraseroBurnFlag compulsory_flags = BRASERO_BURN_FLAG_ALL;
2390
 
        BraseroPluginIOFlag io_flags;
2391
 
        BraseroTrackType output;
2392
 
        BraseroCaps *caps;
2393
 
 
2394
 
        /* create the output to find first caps */
2395
 
        output.type = BRASERO_TRACK_TYPE_DISC;
2396
 
        output.subtype.media = media;
2397
 
 
2398
 
        caps = brasero_caps_find_start_caps (&output);
2399
 
        if (!caps) {
2400
 
                BRASERO_BURN_LOG_DISC_TYPE (media, "FLAGS: no caps could be found for");
2401
 
                return BRASERO_BURN_NOT_SUPPORTED;
2402
 
        }
2403
 
 
2404
 
        BRASERO_BURN_LOG_WITH_TYPE (&caps->type,
2405
 
                                    caps->flags,
2406
 
                                    "FLAGS: trying caps");
2407
 
 
2408
 
        io_flags = brasero_caps_get_flags (caps,
2409
 
                                           session_flags,
2410
 
                                           media,
2411
 
                                           input,
2412
 
                                           BRASERO_PLUGIN_IO_ACCEPT_FILE|
2413
 
                                           BRASERO_PLUGIN_IO_ACCEPT_PIPE,
2414
 
                                           &supported_flags,
2415
 
                                           &compulsory_flags);
2416
 
 
2417
 
        if (io_flags == BRASERO_PLUGIN_IO_NONE) {
2418
 
                BRASERO_BURN_LOG ("FLAGS: not supported");
2419
 
                return BRASERO_BURN_NOT_SUPPORTED;
2420
 
        }
2421
 
 
2422
 
        /* RAW write mode should (must) only be used in this case */
2423
 
        if ((supported_flags & BRASERO_BURN_FLAG_RAW)
2424
 
        &&   input->type == BRASERO_TRACK_TYPE_IMAGE
2425
 
        &&   input->subtype.img_format == BRASERO_IMAGE_FORMAT_CLONE) {
2426
 
                supported_flags &= ~BRASERO_BURN_FLAG_DAO;
2427
 
                compulsory_flags &= ~BRASERO_BURN_FLAG_DAO;
2428
 
                compulsory_flags |= BRASERO_BURN_FLAG_RAW;
2429
 
        }
2430
 
        else
2431
 
                supported_flags &= ~BRASERO_BURN_FLAG_RAW;
2432
 
 
2433
 
        if ((supported_flags & BRASERO_BURN_FLAG_DAO)
2434
 
        &&   input->type == BRASERO_TRACK_TYPE_AUDIO
2435
 
        &&  (input->subtype.img_format & BRASERO_METADATA_INFO)) {
2436
 
                /* In this case, DAO is compulsory if we want to write CD-TEXT */
2437
 
                compulsory_flags |= BRASERO_BURN_FLAG_DAO;
2438
 
        }
2439
 
 
2440
 
        if (io_flags & BRASERO_PLUGIN_IO_ACCEPT_PIPE) {
2441
 
                supported_flags |= BRASERO_BURN_FLAG_NO_TMP_FILES;
2442
 
 
2443
 
                if ((io_flags & BRASERO_PLUGIN_IO_ACCEPT_FILE) == 0)
2444
 
                        compulsory_flags |= BRASERO_BURN_FLAG_NO_TMP_FILES;
2445
 
        }
2446
 
 
2447
 
        *supported |= supported_flags;
2448
 
        *compulsory |= compulsory_flags;
2449
 
 
2450
 
        return BRASERO_BURN_OK;
2451
 
}
2452
 
 
2453
 
static BraseroBurnResult
2454
 
brasero_burn_caps_get_flags_for_medium (BraseroBurnCaps *self,
2455
 
                                        BraseroMedia media,
2456
 
                                        BraseroBurnFlag session_flags,
2457
 
                                        BraseroTrackType *input,
2458
 
                                        BraseroBurnFlag *supported_flags,
2459
 
                                        BraseroBurnFlag *compulsory_flags)
2460
 
{
2461
 
        BraseroBurnResult result;
2462
 
 
2463
 
        /* See if medium is supported out of the box */
2464
 
        result = brasero_caps_get_flags_for_disc (session_flags,
2465
 
                                                  media,
2466
 
                                                  input,
2467
 
                                                  supported_flags,
2468
 
                                                  compulsory_flags);
2469
 
 
2470
 
        /* see if we can add BRASERO_BURN_FLAG_BLANK_BEFORE_WRITE. Add it when:
2471
 
         * - media can be blanked, it has audio or data and we're not merging
2472
 
         * - media is not formatted and it can be blanked/formatted */
2473
 
        if (BRASERO_BURN_CAPS_SHOULD_BLANK (media, session_flags)
2474
 
        &&  brasero_burn_caps_can_blank_real (self, media, session_flags) == BRASERO_BURN_OK)
2475
 
                (*supported_flags) |= BRASERO_BURN_FLAG_BLANK_BEFORE_WRITE;
2476
 
        else if (session_flags & BRASERO_BURN_FLAG_BLANK_BEFORE_WRITE)
2477
 
                return BRASERO_BURN_NOT_SUPPORTED;
2478
 
 
2479
 
        if (((*supported_flags) & BRASERO_BURN_FLAG_BLANK_BEFORE_WRITE)) {
2480
 
                BraseroBurnFlag blank_compulsory = BRASERO_BURN_FLAG_NONE;
2481
 
                BraseroBurnFlag blank_supported = BRASERO_BURN_FLAG_NONE;
2482
 
 
2483
 
                /* If BLANK flag is supported then MERGE/APPEND can't be compulsory */
2484
 
                (*compulsory_flags) &= ~(BRASERO_BURN_FLAG_MERGE|BRASERO_BURN_FLAG_APPEND);
2485
 
 
2486
 
                /* we reached this point in two cases:
2487
 
                 * - if the disc cannot be handled
2488
 
                 * - if some flags are not handled
2489
 
                 * It is helpful only if:
2490
 
                 * - the disc was closed and no plugin can handle this type of 
2491
 
                 * disc once closed (CD-R(W))
2492
 
                 * - there was the flag BLANK_BEFORE_WRITE set and no plugin can
2493
 
                 * handle this flag (means that the plugin should erase and
2494
 
                 * then write on its own. Basically that works only with
2495
 
                 * overwrite formatted discs, DVD+RW, ...) */
2496
 
 
2497
 
                /* What's above is not entirely true. In fact we always need to
2498
 
                 * check even if we first succeeded. There are some cases like
2499
 
                 * CDRW where it's useful.
2500
 
                 * Ex: a CDRW with data appendable can be either appended (then
2501
 
                 * no DAO possible) or blanked and written (DAO possible). */
2502
 
 
2503
 
                (*supported_flags) |= BRASERO_BURN_FLAG_BLANK_BEFORE_WRITE;
2504
 
 
2505
 
                /* result here is the result of the first operation, so if it
2506
 
                 * failed, BLANK before becomes compulsory. */
2507
 
                if (result != BRASERO_BURN_OK)
2508
 
                        (*compulsory_flags) |= BRASERO_BURN_FLAG_BLANK_BEFORE_WRITE;
2509
 
 
2510
 
                /* pretends it is blank and formatted to see if it would work.
2511
 
                 * If it works then that means that the BLANK_BEFORE_WRITE flag
2512
 
                 * is compulsory. */
2513
 
                media &= ~(BRASERO_MEDIUM_CLOSED|
2514
 
                           BRASERO_MEDIUM_APPENDABLE|
2515
 
                           BRASERO_MEDIUM_UNFORMATTED|
2516
 
                           BRASERO_MEDIUM_HAS_DATA|
2517
 
                           BRASERO_MEDIUM_HAS_AUDIO);
2518
 
                media |= BRASERO_MEDIUM_BLANK;
2519
 
                result = brasero_caps_get_flags_for_disc (session_flags,
2520
 
                                                          media,
2521
 
                                                          input,
2522
 
                                                          supported_flags,
2523
 
                                                          compulsory_flags);
2524
 
 
2525
 
                /* if both attempts failed, drop it */
2526
 
                if (result != BRASERO_BURN_OK
2527
 
                && (((*compulsory_flags) & BRASERO_BURN_FLAG_BLANK_BEFORE_WRITE)))
2528
 
                        return result;
2529
 
 
2530
 
                /* need to add blanking flags */
2531
 
                brasero_burn_caps_get_blanking_flags_real (self,
2532
 
                                                           media,
2533
 
                                                           session_flags,
2534
 
                                                           &blank_supported,
2535
 
                                                           &blank_compulsory);
2536
 
                (*supported_flags) |= blank_supported;
2537
 
                (*compulsory_flags) |= blank_compulsory;
2538
 
        }
2539
 
        else if (result != BRASERO_BURN_OK)
2540
 
                return result;
2541
 
 
2542
 
        if (session_flags & BRASERO_BURN_FLAG_BLANK_BEFORE_WRITE) {
2543
 
                /* make sure we remove MERGE/APPEND from supported and
2544
 
                 * compulsory since that's not possible anymore */
2545
 
                (*supported_flags) &= ~(BRASERO_BURN_FLAG_MERGE|BRASERO_BURN_FLAG_APPEND);
2546
 
                (*compulsory_flags) &= ~(BRASERO_BURN_FLAG_MERGE|BRASERO_BURN_FLAG_APPEND);
2547
 
        }
2548
 
 
2549
 
        /* FIXME! we should restart the whole process if
2550
 
         * ((session_flags & compulsory_flags) != compulsory_flags) since that
2551
 
         * means that some supported files could be excluded but were not */
2552
 
 
2553
 
        return BRASERO_BURN_OK;
2554
 
}
2555
 
 
2556
 
static BraseroBurnResult
2557
 
brasero_burn_caps_get_flags_same_src_dest (BraseroBurnCaps *self,
2558
 
                                           BraseroBurnSession *session,
2559
 
                                           BraseroBurnFlag *supported_ret,
2560
 
                                           BraseroBurnFlag *compulsory_ret)
2561
 
{
2562
 
        GSList *iter;
2563
 
        gboolean copy_supported;
2564
 
        BraseroTrackType input;
2565
 
        BraseroTrackType output;
2566
 
        BraseroImageFormat format;
2567
 
        BraseroBurnFlag session_flags;
2568
 
        BraseroBurnFlag supported_final = BRASERO_BURN_FLAG_NONE;
2569
 
        BraseroBurnFlag compulsory_final = BRASERO_BURN_FLAG_ALL;
2570
 
 
2571
 
        BRASERO_BURN_LOG ("Retrieving disc copy flags with same source and destination");
2572
 
 
2573
 
        /* To determine if a CD/DVD can be copied using the same source/dest,
2574
 
         * we first determine if can be imaged and then what are the flags when
2575
 
         * we can burn it to a particular medium type. */
2576
 
        memset (&input, 0, sizeof (BraseroTrackType));
2577
 
        brasero_burn_session_get_input_type (session, &input);
2578
 
        BRASERO_BURN_LOG_TYPE (&input, "input");
2579
 
 
2580
 
        session_flags = brasero_burn_session_get_flags (session);
2581
 
        BRASERO_BURN_LOG_FLAGS (session_flags, "(FLAGS) Session flags");
2582
 
 
2583
 
        /* Check the current flags are possible */
2584
 
        if (session_flags & (BRASERO_BURN_FLAG_MERGE|BRASERO_BURN_FLAG_NO_TMP_FILES))
2585
 
                return BRASERO_BURN_NOT_SUPPORTED;
2586
 
 
2587
 
        /* Check flags for all available format */
2588
 
        format = BRASERO_IMAGE_FORMAT_CDRDAO;
2589
 
        output.type = BRASERO_TRACK_TYPE_IMAGE;
2590
 
 
2591
 
        copy_supported = FALSE;
2592
 
        for (; format > BRASERO_IMAGE_FORMAT_NONE; format >>= 1) {
2593
 
                BraseroBurnResult result;
2594
 
                gboolean format_supported;
2595
 
 
2596
 
                /* check this image type is possible given the current flags */
2597
 
                if (format != BRASERO_IMAGE_FORMAT_CLONE
2598
 
                && (session_flags & BRASERO_BURN_FLAG_RAW))
2599
 
                        continue;
2600
 
 
2601
 
                output.subtype.img_format = format;
2602
 
 
2603
 
                /* NOTE: there is no need to get the flags here since there are
2604
 
                 * no specific DISC => IMAGE flags. We just want to know if that
2605
 
                 * is possible. */
2606
 
                BRASERO_BURN_LOG_TYPE (&output, "Testing temporary image format");
2607
 
                format_supported = brasero_caps_try_output_with_blanking (self,
2608
 
                                                                          session,
2609
 
                                                                          &output,
2610
 
                                                                          &input,
2611
 
                                                                          BRASERO_PLUGIN_IO_ACCEPT_FILE,
2612
 
                                                                          FALSE);
2613
 
                if (!format_supported) {
2614
 
                        BRASERO_BURN_LOG_TYPE (&output, "Format not supported");
2615
 
                        continue;
2616
 
                }
2617
 
 
2618
 
                /* This format can be used to create an image. Check if can be
2619
 
                 * burnt now. Just find at least one medium. */
2620
 
                format_supported = FALSE;
2621
 
                for (iter = self->priv->caps_list; iter; iter = iter->next) {
2622
 
                        BraseroBurnFlag compulsory;
2623
 
                        BraseroBurnFlag supported;
2624
 
                        BraseroCaps *caps;
2625
 
 
2626
 
                        caps = iter->data;
2627
 
                        if (caps->type.type != BRASERO_TRACK_TYPE_DISC)
2628
 
                                continue;
2629
 
 
2630
 
                        /* Merge all available flags for each possible medium type */
2631
 
                        supported = BRASERO_BURN_FLAG_NONE;
2632
 
                        compulsory = BRASERO_BURN_FLAG_NONE;
2633
 
                        result = brasero_burn_caps_get_flags_for_medium (self,
2634
 
                                                                         caps->type.subtype.media,
2635
 
                                                                         session_flags,
2636
 
                                                                         &output,
2637
 
                                                                         &supported,
2638
 
                                                                         &compulsory);
2639
 
                        if (result != BRASERO_BURN_OK)
2640
 
                                continue;
2641
 
 
2642
 
                        format_supported = TRUE;
2643
 
                        supported_final |= supported;
2644
 
                        compulsory_final &= compulsory;
2645
 
                }
2646
 
 
2647
 
                BRASERO_BURN_LOG_TYPE (&output, "Format supported %i", format_supported);
2648
 
                if (format_supported)
2649
 
                        copy_supported = TRUE;
2650
 
        }
2651
 
 
2652
 
        if (!copy_supported)
2653
 
                return BRASERO_BURN_NOT_SUPPORTED;
2654
 
 
2655
 
        *supported_ret |= supported_final;
2656
 
        *compulsory_ret |= compulsory_final;
2657
 
        
2658
 
        return BRASERO_BURN_OK;
2659
 
}
2660
 
 
2661
 
BraseroBurnResult
2662
 
brasero_burn_caps_get_flags (BraseroBurnCaps *self,
2663
 
                             BraseroBurnSession *session,
2664
 
                             BraseroBurnFlag *supported,
2665
 
                             BraseroBurnFlag *compulsory)
2666
 
{
2667
 
        BraseroMedia media;
2668
 
        BraseroTrackType input;
2669
 
        BraseroBurnResult result;
2670
 
 
2671
 
        BraseroBurnFlag session_flags;
2672
 
        /* FIXME: what's the meaning of NOGRACE when outputting ? */
2673
 
        BraseroBurnFlag compulsory_flags = BRASERO_BURN_FLAG_NONE;
2674
 
        BraseroBurnFlag supported_flags = BRASERO_BURN_FLAG_DONT_OVERWRITE|
2675
 
                                          BRASERO_BURN_FLAG_CHECK_SIZE|
2676
 
                                          BRASERO_BURN_FLAG_NOGRACE;
2677
 
 
2678
 
        g_return_val_if_fail (BRASERO_IS_BURNCAPS (self), BRASERO_BURN_ERR);
2679
 
 
2680
 
        brasero_burn_session_get_input_type (session, &input);
2681
 
        BRASERO_BURN_LOG_WITH_TYPE (&input,
2682
 
                                    BRASERO_PLUGIN_IO_NONE,
2683
 
                                    "FLAGS: searching available flags for input");
2684
 
 
2685
 
        if (brasero_burn_session_is_dest_file (session)) {
2686
 
                BRASERO_BURN_LOG ("FLAGS: image required");
2687
 
 
2688
 
                /* In this case no APPEND/MERGE is possible */
2689
 
                if (input.type == BRASERO_TRACK_TYPE_DISC)
2690
 
                        supported_flags |= BRASERO_BURN_FLAG_EJECT;
2691
 
 
2692
 
                *supported = supported_flags;
2693
 
                *compulsory = compulsory_flags;
2694
 
 
2695
 
                BRASERO_BURN_LOG_FLAGS (supported_flags, "FLAGS: supported");
2696
 
                BRASERO_BURN_LOG_FLAGS (compulsory_flags, "FLAGS: compulsory");
2697
 
                return BRASERO_BURN_OK;
2698
 
        }
2699
 
 
2700
 
        supported_flags |= BRASERO_BURN_FLAG_EJECT;
2701
 
 
2702
 
        /* special case */
2703
 
        if (brasero_burn_session_same_src_dest_drive (session)) {
2704
 
                result = brasero_burn_caps_get_flags_same_src_dest (self,
2705
 
                                                                    session,
2706
 
                                                                    &supported_flags,
2707
 
                                                                    &compulsory_flags);
2708
 
 
2709
 
                /* These flags are of course never possible */
2710
 
                supported_flags &= ~(BRASERO_BURN_FLAG_NO_TMP_FILES|
2711
 
                                     BRASERO_BURN_FLAG_MERGE);
2712
 
                compulsory_flags &= ~(BRASERO_BURN_FLAG_NO_TMP_FILES|
2713
 
                                      BRASERO_BURN_FLAG_MERGE);
2714
 
 
2715
 
                if (result == BRASERO_BURN_OK) {
2716
 
                        BRASERO_BURN_LOG_FLAGS (supported_flags, "FLAGS: supported");
2717
 
                        BRASERO_BURN_LOG_FLAGS (compulsory_flags, "FLAGS: compulsory");
2718
 
 
2719
 
                        *supported = supported_flags;
2720
 
                        *compulsory = compulsory_flags;
2721
 
                }
2722
 
                else
2723
 
                        BRASERO_BURN_LOG ("No available flags for copy");
2724
 
 
2725
 
                return result;
2726
 
        }
2727
 
 
2728
 
        session_flags = brasero_burn_session_get_flags (session);
2729
 
        BRASERO_BURN_LOG_FLAGS (session_flags, "FLAGS (session):");
2730
 
 
2731
 
        /* sanity check:
2732
 
         * - drive must support flags
2733
 
         * - MERGE and BLANK are not possible together.
2734
 
         * - APPEND and MERGE are compatible. MERGE wins
2735
 
         * - APPEND and BLANK are incompatible */
2736
 
        if (!brasero_burn_caps_flags_check_for_drive (session)) {
2737
 
                BRASERO_BURN_LOG ("Session flags not supported by drive");
2738
 
                return BRASERO_BURN_ERR;
2739
 
        }
2740
 
 
2741
 
        if ((session_flags & (BRASERO_BURN_FLAG_MERGE|BRASERO_BURN_FLAG_APPEND))
2742
 
        &&  (session_flags & BRASERO_BURN_FLAG_BLANK_BEFORE_WRITE))
2743
 
                return BRASERO_BURN_NOT_SUPPORTED;
2744
 
        
2745
 
        /* Let's get flags for recording */
2746
 
        media = brasero_burn_session_get_dest_media (session);
2747
 
        result = brasero_burn_caps_get_flags_for_medium (self,
2748
 
                                                         media,
2749
 
                                                         session_flags,
2750
 
                                                         &input,
2751
 
                                                         &supported_flags,
2752
 
                                                         &compulsory_flags);
2753
 
 
2754
 
        if (result != BRASERO_BURN_OK)
2755
 
                return result;
2756
 
 
2757
 
        supported_flags = brasero_burn_caps_flags_update_for_drive (supported_flags,
2758
 
                                                                    session);
2759
 
 
2760
 
        if (supported)
2761
 
                *supported = supported_flags;
2762
 
 
2763
 
        if (compulsory)
2764
 
                *compulsory = compulsory_flags;
2765
 
 
2766
 
        BRASERO_BURN_LOG_FLAGS (supported_flags, "FLAGS: supported");
2767
 
        BRASERO_BURN_LOG_FLAGS (compulsory_flags, "FLAGS: compulsory");
2768
 
        return BRASERO_BURN_OK;
2769
 
}
2770
 
 
2771
 
/**
2772
 
 * the following functions are used to register new caps
2773
 
 */
2774
 
 
2775
 
static gint
2776
 
brasero_burn_caps_sort (gconstpointer a, gconstpointer b)
2777
 
{
2778
 
        const BraseroCaps *caps_a = a;
2779
 
        const BraseroCaps *caps_b = b;
2780
 
        gint result;
2781
 
 
2782
 
        /* First put DISC (the most used caps) then IMAGE type; these two types
2783
 
         * are the ones that most often searched. At the end of the list we put
2784
 
         * DATA  and AUDIO.
2785
 
         * Another (sub)rule is that for DATA, DISC, AUDIO we put a caps that is
2786
 
         * encompassed by another before.
2787
 
         */
2788
 
 
2789
 
        result = caps_b->type.type - caps_a->type.type;
2790
 
        if (result)
2791
 
                return result;
2792
 
 
2793
 
        switch (caps_a->type.type) {
2794
 
        case BRASERO_TRACK_TYPE_DISC:
2795
 
                if (BRASERO_MEDIUM_TYPE (caps_a->type.subtype.media) !=
2796
 
                    BRASERO_MEDIUM_TYPE (caps_b->type.subtype.media))
2797
 
                        return ((gint32) BRASERO_MEDIUM_TYPE (caps_a->type.subtype.media) -
2798
 
                                (gint32) BRASERO_MEDIUM_TYPE (caps_b->type.subtype.media));
2799
 
 
2800
 
                if ((caps_a->type.subtype.media & BRASERO_MEDIUM_DVD)
2801
 
                &&  BRASERO_MEDIUM_SUBTYPE (caps_a->type.subtype.media) !=
2802
 
                    BRASERO_MEDIUM_SUBTYPE (caps_b->type.subtype.media))                        
2803
 
                        return ((gint32) BRASERO_MEDIUM_SUBTYPE (caps_a->type.subtype.media) -
2804
 
                                (gint32) BRASERO_MEDIUM_SUBTYPE (caps_b->type.subtype.media));
2805
 
 
2806
 
                if (BRASERO_MEDIUM_ATTR (caps_a->type.subtype.media) !=
2807
 
                    BRASERO_MEDIUM_ATTR (caps_b->type.subtype.media))
2808
 
                        return BRASERO_MEDIUM_ATTR (caps_a->type.subtype.media) -
2809
 
                               BRASERO_MEDIUM_ATTR (caps_b->type.subtype.media);
2810
 
 
2811
 
                if (BRASERO_MEDIUM_STATUS (caps_a->type.subtype.media) !=
2812
 
                    BRASERO_MEDIUM_STATUS (caps_b->type.subtype.media))
2813
 
                        return BRASERO_MEDIUM_STATUS (caps_a->type.subtype.media) -
2814
 
                               BRASERO_MEDIUM_STATUS (caps_b->type.subtype.media);
2815
 
 
2816
 
                return (BRASERO_MEDIUM_INFO (caps_a->type.subtype.media) -
2817
 
                        BRASERO_MEDIUM_INFO (caps_b->type.subtype.media));
2818
 
 
2819
 
        case BRASERO_TRACK_TYPE_IMAGE:
2820
 
                /* This way BIN subtype is always sorted at the end */
2821
 
                return caps_a->type.subtype.img_format - caps_b->type.subtype.img_format;
2822
 
 
2823
 
        case BRASERO_TRACK_TYPE_AUDIO:
2824
 
                if (caps_a->type.subtype.audio_format != caps_b->type.subtype.audio_format) {
2825
 
                        result = (caps_a->type.subtype.audio_format & caps_b->type.subtype.audio_format);
2826
 
                        if (result == caps_a->type.subtype.audio_format)
2827
 
                                return -1;
2828
 
                        else if (result == caps_b->type.subtype.audio_format)
2829
 
                                return 1;
2830
 
 
2831
 
                        return  (gint32) caps_a->type.subtype.audio_format -
2832
 
                                (gint32) caps_b->type.subtype.audio_format;
2833
 
                }
2834
 
                break;
2835
 
 
2836
 
        case BRASERO_TRACK_TYPE_DATA:
2837
 
                result = (caps_a->type.subtype.fs_type & caps_b->type.subtype.fs_type);
2838
 
                if (result == caps_a->type.subtype.fs_type)
2839
 
                        return -1;
2840
 
                else if (result == caps_b->type.subtype.fs_type)
2841
 
                        return 1;
2842
 
 
2843
 
                return (caps_a->type.subtype.fs_type - caps_b->type.subtype.fs_type);
2844
 
 
2845
 
        default:
2846
 
                break;
2847
 
        }
2848
 
 
2849
 
        return 0;
2850
 
}
2851
 
 
2852
 
static BraseroCapsLink *
2853
 
brasero_caps_link_copy (BraseroCapsLink *link)
2854
 
{
2855
 
        BraseroCapsLink *retval;
2856
 
 
2857
 
        retval = g_new0 (BraseroCapsLink, 1);
2858
 
        retval->plugins = g_slist_copy (link->plugins);
2859
 
        retval->caps = link->caps;
2860
 
 
2861
 
        return retval;
2862
 
}
2863
 
 
2864
 
static void
2865
 
brasero_caps_link_list_duplicate (BraseroCaps *dest, BraseroCaps *src)
2866
 
{
2867
 
        GSList *iter;
2868
 
 
2869
 
        for (iter = src->links; iter; iter = iter->next) {
2870
 
                BraseroCapsLink *link;
2871
 
 
2872
 
                link = iter->data;
2873
 
                dest->links = g_slist_prepend (dest->links, brasero_caps_link_copy (link));
2874
 
        }
2875
 
}
2876
 
 
2877
 
static BraseroCaps *
2878
 
brasero_caps_copy (BraseroCaps *caps)
2879
 
{
2880
 
        BraseroCaps *retval;
2881
 
 
2882
 
        retval = g_new0 (BraseroCaps, 1);
2883
 
        retval->flags = caps->flags;
2884
 
        memcpy (&retval->type, &caps->type, sizeof (BraseroTrackType));
2885
 
        retval->modifiers = g_slist_copy (caps->modifiers);
2886
 
 
2887
 
        return retval;
2888
 
}
2889
 
 
2890
 
static void
2891
 
brasero_caps_replicate_modifiers (BraseroCaps *dest, BraseroCaps *src)
2892
 
{
2893
 
        GSList *iter;
2894
 
 
2895
 
        for (iter = src->modifiers; iter; iter = iter->next) {
2896
 
                BraseroPlugin *plugin;
2897
 
 
2898
 
                plugin = iter->data;
2899
 
 
2900
 
                if (g_slist_find (dest->modifiers, plugin))
2901
 
                        continue;
2902
 
 
2903
 
                dest->modifiers = g_slist_prepend (dest->modifiers, plugin);
2904
 
        }
2905
 
}
2906
 
 
2907
 
static void
2908
 
brasero_caps_replicate_links (BraseroCaps *dest, BraseroCaps *src)
2909
 
{
2910
 
        BraseroBurnCaps *self;
2911
 
        GSList *iter;
2912
 
 
2913
 
        self = brasero_burn_caps_get_default ();
2914
 
 
2915
 
        brasero_caps_link_list_duplicate (dest, src);
2916
 
 
2917
 
        for (iter = self->priv->caps_list; iter; iter = iter->next) {
2918
 
                BraseroCaps *iter_caps;
2919
 
                GSList *links;
2920
 
 
2921
 
                iter_caps = iter->data;
2922
 
                if (iter_caps == src)
2923
 
                        continue;
2924
 
 
2925
 
                for (links = iter_caps->links; links; links = links->next) {
2926
 
                        BraseroCapsLink *link;
2927
 
 
2928
 
                        link = links->data;
2929
 
                        if (link->caps == src) {
2930
 
                                BraseroCapsLink *copy;
2931
 
 
2932
 
                                copy = brasero_caps_link_copy (link);
2933
 
                                copy->caps = dest;
2934
 
                                iter_caps->links = g_slist_prepend (iter_caps->links, copy);
2935
 
                        }
2936
 
                }
2937
 
        }
2938
 
}
2939
 
 
2940
 
static void
2941
 
brasero_caps_replicate_tests (BraseroCaps *dest, BraseroCaps *src)
2942
 
{
2943
 
        BraseroBurnCaps *self;
2944
 
        GSList *iter;
2945
 
 
2946
 
        self = brasero_burn_caps_get_default ();
2947
 
 
2948
 
        for (iter = self->priv->tests; iter; iter = iter->next) {
2949
 
                BraseroCapsTest *test;
2950
 
                GSList *links;
2951
 
 
2952
 
                test = iter->data;
2953
 
                for (links = test->links; links; links = links->next) {
2954
 
                        BraseroCapsLink *link;
2955
 
 
2956
 
                        link = links->data;
2957
 
                        if (link->caps == src) {
2958
 
                                BraseroCapsLink *copy;
2959
 
 
2960
 
                                copy = brasero_caps_link_copy (link);
2961
 
                                copy->caps = dest;
2962
 
                                test->links = g_slist_prepend (test->links, copy);
2963
 
                        }
2964
 
                }
2965
 
        }
2966
 
}
2967
 
 
2968
 
static BraseroCaps *
2969
 
brasero_caps_copy_deep (BraseroCaps *caps)
2970
 
{
2971
 
        BraseroCaps *retval;
2972
 
        BraseroBurnCaps *self;
2973
 
 
2974
 
        self = brasero_burn_caps_get_default ();
2975
 
 
2976
 
        retval = brasero_caps_copy (caps);
2977
 
        brasero_caps_replicate_links (retval, caps);
2978
 
        brasero_caps_replicate_tests (retval, caps);
2979
 
        return retval;
2980
 
}
2981
 
 
2982
 
static GSList *
2983
 
brasero_caps_list_check_io (GSList *list, BraseroPluginIOFlag flags)
2984
 
{
2985
 
        GSList *iter;
2986
 
        BraseroBurnCaps *self;
2987
 
 
2988
 
        self = brasero_burn_caps_get_default ();
2989
 
 
2990
 
        /* in this function we create the caps with the missing IO. All in the
2991
 
         * list have something in common with flags. */
2992
 
        for (iter = list; iter; iter = iter->next) {
2993
 
                BraseroCaps *caps;
2994
 
                BraseroPluginIOFlag common;
2995
 
 
2996
 
                caps = iter->data;
2997
 
                common = caps->flags & flags;
2998
 
                if (common != caps->flags) {
2999
 
                        BraseroCaps *new_caps;
3000
 
 
3001
 
                        /* (common == flags) && common != caps->flags
3002
 
                         * caps->flags encompasses flags: Split the caps in two
3003
 
                         * and only keep the interesting part */
3004
 
                        caps->flags &= ~common;
3005
 
 
3006
 
                        /* this caps has changed and needs to be sorted again */
3007
 
                        self->priv->caps_list = g_slist_sort (self->priv->caps_list,
3008
 
                                                              brasero_burn_caps_sort);
3009
 
 
3010
 
                        new_caps = brasero_caps_copy_deep (caps);
3011
 
                        new_caps->flags = common;
3012
 
 
3013
 
                        self->priv->caps_list = g_slist_insert_sorted (self->priv->caps_list,
3014
 
                                                                       new_caps,
3015
 
                                                                       brasero_burn_caps_sort);
3016
 
 
3017
 
                        list = g_slist_prepend (list, new_caps);
3018
 
                }
3019
 
                else if (common != flags) {
3020
 
                        GSList *node, *next;
3021
 
                        BraseroPluginIOFlag complement = flags;
3022
 
 
3023
 
                        complement &= ~common;
3024
 
                        for (node = list; node; node = next) {
3025
 
                                BraseroCaps *tmp;
3026
 
 
3027
 
                                tmp = node->data;
3028
 
                                next = node->next;
3029
 
 
3030
 
                                if (node == iter)
3031
 
                                        continue;
3032
 
 
3033
 
                                if (caps->type.type != tmp->type.type
3034
 
                                ||  caps->type.subtype.media != tmp->type.subtype.media)
3035
 
                                        continue;
3036
 
 
3037
 
                                /* substract the flags and relocate them at the
3038
 
                                 * head of the list since we don't need to look
3039
 
                                 * them up again */
3040
 
                                complement &= ~(tmp->flags);
3041
 
                                list = g_slist_remove (list, tmp);
3042
 
                                list = g_slist_prepend (list, tmp);
3043
 
                        }
3044
 
 
3045
 
                        if (complement != BRASERO_PLUGIN_IO_NONE) {
3046
 
                                BraseroCaps *new_caps;
3047
 
 
3048
 
                                /* common == caps->flags && common != flags.
3049
 
                                 * Flags encompasses caps->flags. So we need to
3050
 
                                 * create a new caps for this type with the
3051
 
                                 * substraction of flags if the other part isn't
3052
 
                                 * in the list */
3053
 
                                new_caps = brasero_caps_copy (caps);
3054
 
                                new_caps->flags = flags & (~common);
3055
 
                                self->priv->caps_list = g_slist_insert_sorted (self->priv->caps_list,
3056
 
                                                                               new_caps,
3057
 
                                                                               brasero_burn_caps_sort);
3058
 
 
3059
 
                                list = g_slist_prepend (list, new_caps);
3060
 
                        }
3061
 
                }
3062
 
        }
3063
 
 
3064
 
        return list;
3065
 
}
3066
 
 
3067
 
GSList *
3068
 
brasero_caps_image_new (BraseroPluginIOFlag flags,
3069
 
                        BraseroImageFormat format)
3070
 
{
3071
 
        BraseroImageFormat remaining_format;
3072
 
        BraseroBurnCaps *self;
3073
 
        GSList *retval = NULL;
3074
 
        GSList *iter;
3075
 
 
3076
 
        BRASERO_BURN_LOG_WITH_FULL_TYPE (BRASERO_TRACK_TYPE_IMAGE,
3077
 
                                         format,
3078
 
                                         flags,
3079
 
                                         "New caps required");
3080
 
 
3081
 
        self = brasero_burn_caps_get_default ();
3082
 
 
3083
 
        remaining_format = format;
3084
 
 
3085
 
        /* We have to search all caps with or related to the format */
3086
 
        for (iter = self->priv->caps_list; iter; iter = iter->next) {
3087
 
                BraseroCaps *caps;
3088
 
                BraseroImageFormat common;
3089
 
                BraseroPluginIOFlag common_io;
3090
 
 
3091
 
                caps = iter->data;
3092
 
                if (caps->type.type != BRASERO_TRACK_TYPE_IMAGE)
3093
 
                        continue;
3094
 
 
3095
 
                common_io = caps->flags & flags;
3096
 
                if (common_io == BRASERO_PLUGIN_IO_NONE)
3097
 
                        continue;
3098
 
 
3099
 
                common = (caps->type.subtype.img_format & format);
3100
 
                if (common == BRASERO_IMAGE_FORMAT_NONE)
3101
 
                        continue;
3102
 
 
3103
 
                if (common != caps->type.subtype.img_format) {
3104
 
                        /* img_format encompasses format. Split it in two and
3105
 
                         * keep caps with common format */
3106
 
                        SUBSTRACT (caps->type.subtype.img_format, common);
3107
 
                        self->priv->caps_list = g_slist_sort (self->priv->caps_list,
3108
 
                                                              brasero_burn_caps_sort);
3109
 
 
3110
 
                        caps = brasero_caps_copy_deep (caps);
3111
 
                        caps->type.subtype.img_format = common;
3112
 
 
3113
 
                        self->priv->caps_list = g_slist_insert_sorted (self->priv->caps_list,
3114
 
                                                                       caps,
3115
 
                                                                       brasero_burn_caps_sort);
3116
 
                }
3117
 
 
3118
 
                retval = g_slist_prepend (retval, caps);
3119
 
                remaining_format &= ~common;
3120
 
        }
3121
 
 
3122
 
        /* Now we make sure that all these new or already 
3123
 
         * existing caps have the proper IO Flags */
3124
 
        retval = brasero_caps_list_check_io (retval, flags);
3125
 
 
3126
 
        if (remaining_format != BRASERO_IMAGE_FORMAT_NONE) {
3127
 
                BraseroCaps *caps;
3128
 
 
3129
 
                caps = g_new0 (BraseroCaps, 1);
3130
 
                caps->flags = flags;
3131
 
                caps->type.subtype.img_format = remaining_format;
3132
 
                caps->type.type = BRASERO_TRACK_TYPE_IMAGE;
3133
 
 
3134
 
                self->priv->caps_list = g_slist_insert_sorted (self->priv->caps_list,
3135
 
                                                               caps,
3136
 
                                                               brasero_burn_caps_sort);
3137
 
                retval = g_slist_prepend (retval, caps);
3138
 
 
3139
 
                BRASERO_BURN_LOG_TYPE (&caps->type, "Created new caps");
3140
 
        }
3141
 
 
3142
 
        return retval;
3143
 
}
3144
 
 
3145
 
GSList *
3146
 
brasero_caps_audio_new (BraseroPluginIOFlag flags,
3147
 
                        BraseroAudioFormat format)
3148
 
{
3149
 
        GSList *iter;
3150
 
        GSList *retval = NULL;
3151
 
        BraseroBurnCaps *self;
3152
 
        GSList *encompassing = NULL;
3153
 
        gboolean have_the_one = FALSE;
3154
 
 
3155
 
        BRASERO_BURN_LOG_WITH_FULL_TYPE (BRASERO_TRACK_TYPE_AUDIO,
3156
 
                                         format,
3157
 
                                         flags,
3158
 
                                         "New caps required");
3159
 
 
3160
 
        self = brasero_burn_caps_get_default ();
3161
 
 
3162
 
        for (iter = self->priv->caps_list; iter; iter = iter->next) {
3163
 
                BraseroCaps *caps;
3164
 
                BraseroAudioFormat common;
3165
 
                BraseroPluginIOFlag common_io;
3166
 
                BraseroAudioFormat common_audio;
3167
 
                BraseroAudioFormat common_video;
3168
 
 
3169
 
                caps = iter->data;
3170
 
 
3171
 
                if (caps->type.type != BRASERO_TRACK_TYPE_AUDIO)
3172
 
                        continue;
3173
 
 
3174
 
                common_io = (flags & caps->flags);
3175
 
                if (common_io == BRASERO_PLUGIN_IO_NONE)
3176
 
                        continue;
3177
 
 
3178
 
                if (caps->type.subtype.audio_format == format) {
3179
 
                        /* that's the perfect fit */
3180
 
                        have_the_one = TRUE;
3181
 
                        retval = g_slist_prepend (retval, caps);
3182
 
                        continue;
3183
 
                }
3184
 
 
3185
 
                /* Search caps strictly encompassed or encompassing our format
3186
 
                 * NOTE: make sure that if there is a VIDEO stream in one of
3187
 
                 * them, the other does have a VIDEO stream too. */
3188
 
                common_audio = BRASERO_AUDIO_CAPS_AUDIO (caps->type.subtype.audio_format) & 
3189
 
                               BRASERO_AUDIO_CAPS_AUDIO (format);
3190
 
                if (common_audio == BRASERO_AUDIO_FORMAT_NONE
3191
 
                && (BRASERO_AUDIO_CAPS_AUDIO (caps->type.subtype.audio_format)
3192
 
                ||  BRASERO_AUDIO_CAPS_AUDIO (format)))
3193
 
                        continue;
3194
 
 
3195
 
                common_video = BRASERO_AUDIO_CAPS_VIDEO (caps->type.subtype.audio_format) & 
3196
 
                               BRASERO_AUDIO_CAPS_VIDEO (format);
3197
 
 
3198
 
                if (common_video == BRASERO_AUDIO_FORMAT_NONE
3199
 
                && (BRASERO_AUDIO_CAPS_VIDEO (caps->type.subtype.audio_format)
3200
 
                ||  BRASERO_AUDIO_CAPS_VIDEO (format)))
3201
 
                        continue;
3202
 
 
3203
 
                /* Likewise... that must be common */
3204
 
                if ((caps->type.subtype.audio_format & BRASERO_METADATA_INFO) != (format & BRASERO_METADATA_INFO))
3205
 
                        continue;
3206
 
 
3207
 
                common = common_audio|common_video|(format & BRASERO_METADATA_INFO);
3208
 
 
3209
 
                /* encompassed caps just add it to retval */
3210
 
                if (caps->type.subtype.audio_format == common)
3211
 
                        retval = g_slist_prepend (retval, caps);
3212
 
 
3213
 
                /* encompassing caps keep it if we need to create perfect fit */
3214
 
                if (format == common)
3215
 
                        encompassing = g_slist_prepend (encompassing, caps);
3216
 
        }
3217
 
 
3218
 
        /* Now we make sure that all these new or already 
3219
 
         * existing caps have the proper IO Flags */
3220
 
        retval = brasero_caps_list_check_io (retval, flags);
3221
 
 
3222
 
        if (!have_the_one) {
3223
 
                BraseroCaps *caps;
3224
 
 
3225
 
                caps = g_new0 (BraseroCaps, 1);
3226
 
                caps->flags = flags;
3227
 
                caps->type.subtype.audio_format = format;
3228
 
                caps->type.type = BRASERO_TRACK_TYPE_AUDIO;
3229
 
 
3230
 
                if (encompassing) {
3231
 
                        for (iter = encompassing; iter; iter = iter->next) {
3232
 
                                BraseroCaps *iter_caps;
3233
 
 
3234
 
                                iter_caps = iter->data;
3235
 
                                brasero_caps_replicate_links (caps, iter_caps);
3236
 
                                brasero_caps_replicate_tests (caps, iter_caps);
3237
 
                                brasero_caps_replicate_modifiers (caps, iter_caps);
3238
 
                        }
3239
 
                }
3240
 
 
3241
 
                self->priv->caps_list = g_slist_insert_sorted (self->priv->caps_list,
3242
 
                                                               caps,
3243
 
                                                               brasero_burn_caps_sort);
3244
 
                retval = g_slist_prepend (retval, caps);
3245
 
 
3246
 
                BRASERO_BURN_LOG_TYPE (&caps->type, "Created new caps");
3247
 
        }
3248
 
 
3249
 
        g_slist_free (encompassing);
3250
 
        return retval;
3251
 
}
3252
 
 
3253
 
GSList *
3254
 
brasero_caps_data_new (BraseroImageFS fs_type)
3255
 
{
3256
 
        GSList *iter;
3257
 
        GSList *retval = NULL;
3258
 
        BraseroBurnCaps *self;
3259
 
        GSList *encompassing = NULL;
3260
 
        gboolean have_the_one = FALSE;
3261
 
 
3262
 
        BRASERO_BURN_LOG_WITH_FULL_TYPE (BRASERO_TRACK_TYPE_DATA,
3263
 
                                         fs_type,
3264
 
                                         BRASERO_PLUGIN_IO_NONE,
3265
 
                                         "New caps required");
3266
 
        self = brasero_burn_caps_get_default ();
3267
 
 
3268
 
        for (iter = self->priv->caps_list; iter; iter = iter->next) {
3269
 
                BraseroCaps *caps;
3270
 
                BraseroImageFS common;
3271
 
 
3272
 
                caps = iter->data;
3273
 
 
3274
 
                if (caps->type.type != BRASERO_TRACK_TYPE_DATA)
3275
 
                        continue;
3276
 
 
3277
 
                if (caps->type.subtype.fs_type == fs_type) {
3278
 
                        /* that's the perfect fit */
3279
 
                        have_the_one = TRUE;
3280
 
                        retval = g_slist_prepend (retval, caps);
3281
 
                        continue;
3282
 
                }
3283
 
 
3284
 
                /* search caps strictly encompassing our format ... */
3285
 
                common = caps->type.subtype.fs_type & fs_type;
3286
 
                if (common == BRASERO_IMAGE_FS_NONE)
3287
 
                        continue;
3288
 
 
3289
 
                /* encompassed caps just add it to retval */
3290
 
                if (caps->type.subtype.fs_type == common)
3291
 
                        retval = g_slist_prepend (retval, caps);
3292
 
 
3293
 
                /* encompassing caps keep it if we need to create perfect fit */
3294
 
                if (fs_type == common)
3295
 
                        encompassing = g_slist_prepend (encompassing, caps);
3296
 
        }
3297
 
 
3298
 
        if (!have_the_one) {
3299
 
                BraseroCaps *caps;
3300
 
 
3301
 
                caps = g_new0 (BraseroCaps, 1);
3302
 
                caps->flags = BRASERO_PLUGIN_IO_ACCEPT_FILE;
3303
 
                caps->type.type = BRASERO_TRACK_TYPE_DATA;
3304
 
                caps->type.subtype.fs_type = fs_type;
3305
 
 
3306
 
                if (encompassing) {
3307
 
                        for (iter = encompassing; iter; iter = iter->next) {
3308
 
                                BraseroCaps *iter_caps;
3309
 
 
3310
 
                                iter_caps = iter->data;
3311
 
                                brasero_caps_replicate_links (caps, iter_caps);
3312
 
                                brasero_caps_replicate_tests (caps, iter_caps);
3313
 
                                brasero_caps_replicate_modifiers (caps, iter_caps);
3314
 
                        }
3315
 
                }
3316
 
 
3317
 
                self->priv->caps_list = g_slist_insert_sorted (self->priv->caps_list,
3318
 
                                                               caps,
3319
 
                                                               brasero_burn_caps_sort);
3320
 
                retval = g_slist_prepend (retval, caps);
3321
 
        }
3322
 
 
3323
 
        g_slist_free (encompassing);
3324
 
        return retval;
3325
 
}
3326
 
 
3327
 
static GSList *
3328
 
brasero_caps_disc_lookup_or_create (GSList *retval,
3329
 
                                    BraseroMedia media)
3330
 
{
3331
 
        GSList *iter;
3332
 
        BraseroCaps *caps;
3333
 
 
3334
 
        if (!default_caps)
3335
 
                brasero_burn_caps_get_default ();
3336
 
 
3337
 
        for (iter = default_caps->priv->caps_list; iter; iter = iter->next) {
3338
 
                caps = iter->data;
3339
 
 
3340
 
                if (caps->type.type != BRASERO_TRACK_TYPE_DISC)
3341
 
                        continue;
3342
 
 
3343
 
                if (caps->type.subtype.media == media) {
3344
 
                        BRASERO_BURN_LOG_WITH_TYPE (&caps->type,
3345
 
                                                    caps->flags,
3346
 
                                                    "Retrieved");
3347
 
                        return g_slist_prepend (retval, caps);
3348
 
                }
3349
 
        }
3350
 
 
3351
 
        caps = g_new0 (BraseroCaps, 1);
3352
 
        caps->flags = BRASERO_PLUGIN_IO_ACCEPT_FILE;
3353
 
        caps->type.type = BRASERO_TRACK_TYPE_DISC;
3354
 
        caps->type.subtype.media = media;
3355
 
 
3356
 
        BRASERO_BURN_LOG_WITH_TYPE (&caps->type,
3357
 
                                    caps->flags,
3358
 
                                    "Created");
3359
 
 
3360
 
        default_caps->priv->caps_list = g_slist_prepend (default_caps->priv->caps_list, caps);
3361
 
        return g_slist_prepend (retval, caps);
3362
 
}
3363
 
 
3364
 
GSList *
3365
 
brasero_caps_disc_new (BraseroMedia type)
3366
 
{
3367
 
        GSList *retval = NULL;
3368
 
        GSList *list;
3369
 
        GSList *iter;
3370
 
 
3371
 
        list = brasero_media_get_all_list (type);
3372
 
        for (iter = list; iter; iter = iter->next) {
3373
 
                BraseroMedia medium;
3374
 
 
3375
 
                medium = GPOINTER_TO_INT (iter->data);
3376
 
                retval = brasero_caps_disc_lookup_or_create (retval, medium);
3377
 
        }
3378
 
        g_slist_free (list);
3379
 
 
3380
 
        return retval;
3381
 
}
3382
 
 
3383
 
/**
3384
 
 * these functions are to create links
3385
 
 */
3386
 
 
3387
 
static void
3388
 
brasero_caps_create_links (BraseroCaps *output,
3389
 
                           GSList *inputs,
3390
 
                           BraseroPlugin *plugin)
3391
 
{
3392
 
        for (; inputs; inputs = inputs->next) {
3393
 
                BraseroCaps *input;
3394
 
                BraseroCapsLink *link;
3395
 
 
3396
 
                input = inputs->data;
3397
 
 
3398
 
                if (output == input) {
3399
 
                        BRASERO_BURN_LOG ("Same input and output for link. Dropping");
3400
 
                        continue;
3401
 
                }
3402
 
 
3403
 
                if (input->flags == output->flags
3404
 
                &&  input->type.type == output->type.type  
3405
 
                &&  input->type.subtype.media == output->type.subtype.media)
3406
 
                        BRASERO_BURN_LOG ("Recursive link");
3407
 
 
3408
 
                link = brasero_caps_find_link_for_input (output, input);
3409
 
 
3410
 
#if 0
3411
 
 
3412
 
                /* Mainly for extra debugging */
3413
 
                BRASERO_BURN_LOG_TYPE (&output->type, "Linking");
3414
 
                BRASERO_BURN_LOG_TYPE (&input->type, "to");
3415
 
                BRASERO_BURN_LOG ("with %s", brasero_plugin_get_name (plugin));
3416
 
 
3417
 
#endif
3418
 
 
3419
 
                if (!link) {
3420
 
                        link = g_new0 (BraseroCapsLink, 1);
3421
 
                        link->caps = input;
3422
 
                        link->plugins = g_slist_prepend (NULL, plugin);
3423
 
 
3424
 
                        output->links = g_slist_prepend (output->links, link);
3425
 
                }
3426
 
                else
3427
 
                        link->plugins = g_slist_prepend (link->plugins, plugin);
3428
 
        }
3429
 
}
3430
 
 
3431
 
void
3432
 
brasero_plugin_link_caps (BraseroPlugin *plugin,
3433
 
                          GSList *outputs,
3434
 
                          GSList *inputs)
3435
 
{
3436
 
        /* we make sure the caps exists and if not we create them */
3437
 
        for (; outputs; outputs = outputs->next) {
3438
 
                BraseroCaps *output;
3439
 
 
3440
 
                output = outputs->data;
3441
 
                brasero_caps_create_links (output, inputs, plugin);
3442
 
        }
3443
 
}
3444
 
 
3445
 
void
3446
 
brasero_plugin_blank_caps (BraseroPlugin *plugin,
3447
 
                           GSList *caps_list)
3448
 
{
3449
 
        for (; caps_list; caps_list = caps_list->next) {
3450
 
                BraseroCaps *caps;
3451
 
                BraseroCapsLink *link;
3452
 
 
3453
 
                caps = caps_list->data;
3454
 
 
3455
 
                if (caps->type.type != BRASERO_TRACK_TYPE_DISC)
3456
 
                        continue;
3457
 
        
3458
 
                BRASERO_BURN_LOG_WITH_TYPE (&caps->type,
3459
 
                                            caps->flags,
3460
 
                                            "Adding blank caps for");
3461
 
 
3462
 
                /* we need to find the link whose caps is NULL */
3463
 
                link = brasero_caps_find_link_for_input (caps, NULL);
3464
 
                if (!link) {
3465
 
                        link = g_new0 (BraseroCapsLink, 1);
3466
 
                        link->caps = NULL;
3467
 
                        link->plugins = g_slist_prepend (NULL, plugin);
3468
 
 
3469
 
                        caps->links = g_slist_prepend (caps->links, link);
3470
 
                }
3471
 
                else
3472
 
                        link->plugins = g_slist_prepend (link->plugins, plugin);
3473
 
        }
3474
 
}
3475
 
 
3476
 
void
3477
 
brasero_plugin_process_caps (BraseroPlugin *plugin,
3478
 
                             GSList *caps_list)
3479
 
{
3480
 
        for (; caps_list; caps_list = caps_list->next) {
3481
 
                BraseroCaps *caps;
3482
 
 
3483
 
                caps = caps_list->data;
3484
 
                caps->modifiers = g_slist_prepend (caps->modifiers, plugin);
3485
 
        }
3486
 
}
3487
 
 
3488
 
void
3489
 
brasero_plugin_check_caps (BraseroPlugin *plugin,
3490
 
                           BraseroChecksumType type,
3491
 
                           GSList *caps_list)
3492
 
{
3493
 
        BraseroCapsTest *test = NULL;
3494
 
        BraseroBurnCaps *self;
3495
 
        GSList *iter;
3496
 
 
3497
 
        /* Find the the BraseroCapsTest for this type; if none create it */
3498
 
        self = brasero_burn_caps_get_default ();
3499
 
        for (iter = self->priv->tests; iter; iter = iter->next) {
3500
 
                BraseroCapsTest *tmp;
3501
 
 
3502
 
                tmp = iter->data;
3503
 
                if (tmp->type == type) {
3504
 
                        test = tmp;
3505
 
                        break;
3506
 
                }
3507
 
        }
3508
 
 
3509
 
        if (!test) {
3510
 
                test = g_new0 (BraseroCapsTest, 1);
3511
 
                test->type = type;
3512
 
                self->priv->tests = g_slist_prepend (self->priv->tests, test);
3513
 
        }
3514
 
 
3515
 
        g_object_unref (self);
3516
 
 
3517
 
        for (; caps_list; caps_list = caps_list->next) {
3518
 
                GSList *links;
3519
 
                BraseroCaps *caps;
3520
 
                BraseroCapsLink *link;
3521
 
 
3522
 
                caps = caps_list->data;
3523
 
 
3524
 
                /* try to find a link for the above caps, if none create one */
3525
 
                link = NULL;
3526
 
                for (links = test->links; links; links = links->next) {
3527
 
                        BraseroCapsLink *tmp;
3528
 
 
3529
 
                        tmp = links->data;
3530
 
                        if (tmp->caps == caps) {
3531
 
                                link = tmp;
3532
 
                                break;
3533
 
                        }
3534
 
                }
3535
 
 
3536
 
                if (!link) {
3537
 
                        link = g_new0 (BraseroCapsLink, 1);
3538
 
                        link->caps = caps;
3539
 
                        test->links = g_slist_prepend (test->links, link);
3540
 
                }
3541
 
 
3542
 
                link->plugins = g_slist_prepend (link->plugins, plugin);
3543
 
        }
3544
 
}
3545
 
 
3546
 
/**
3547
 
 * This is to register a plugin group 
3548
 
 * This function is only define here (though it's implemented in burn-plugin.c).
3549
 
 */
3550
 
 
3551
 
void
3552
 
brasero_plugin_set_group (BraseroPlugin *plugin, gint group_id);
3553
 
 
3554
 
void
3555
 
brasero_plugin_register_group (BraseroPlugin *plugin,
3556
 
                               const gchar *name)
3557
 
{
3558
 
        guint retval;
3559
 
        BraseroBurnCaps *self;
3560
 
 
3561
 
        if (!name) {
3562
 
                brasero_plugin_set_group (plugin, 0);
3563
 
                return;
3564
 
        }
3565
 
 
3566
 
        self = brasero_burn_caps_get_default ();
3567
 
 
3568
 
        if (!self->priv->groups)
3569
 
                self->priv->groups = g_hash_table_new_full (g_str_hash,
3570
 
                                                            g_str_equal,
3571
 
                                                            g_free,
3572
 
                                                            NULL);
3573
 
 
3574
 
        retval = GPOINTER_TO_INT (g_hash_table_lookup (self->priv->groups, name));
3575
 
        if (retval) {
3576
 
                brasero_plugin_set_group (plugin, retval);
3577
 
                return;
3578
 
        }
3579
 
 
3580
 
        g_hash_table_insert (self->priv->groups,
3581
 
                             g_strdup (name),
3582
 
                             GINT_TO_POINTER (g_hash_table_size (self->priv->groups) + 1));
3583
 
 
3584
 
        /* see if we have a group id now */
3585
 
        if (!self->priv->group_id
3586
 
        &&   self->priv->group_str
3587
 
        &&  !strcmp (name, self->priv->group_str))
3588
 
                self->priv->group_id = g_hash_table_size (self->priv->groups) + 1;
3589
 
 
3590
 
        brasero_plugin_set_group (plugin, g_hash_table_size (self->priv->groups) + 1);
3591
 
}
3592
 
 
3593
 
/** 
3594
 
 * This is to find out what are the capacities of a plugin
3595
 
 * Declared in brasero-plugin-private.h
3596
 
 */
3597
 
 
3598
 
BraseroBurnResult
3599
 
brasero_plugin_can_burn (BraseroPlugin *plugin)
3600
 
{
3601
 
        GSList *iter;
3602
 
        BraseroBurnCaps *self;
3603
 
 
3604
 
        self = brasero_burn_caps_get_default ();
3605
 
 
3606
 
        for (iter = self->priv->caps_list; iter; iter = iter->next) {
3607
 
                BraseroCaps *caps;
3608
 
                GSList *links;
3609
 
 
3610
 
                caps = iter->data;
3611
 
                if (caps->type.type != BRASERO_TRACK_TYPE_DISC)
3612
 
                        continue;
3613
 
 
3614
 
                for (links = caps->links; links; links = links->next) {
3615
 
                        BraseroCapsLink *link;
3616
 
                        GSList *plugins;
3617
 
 
3618
 
                        link = links->data;
3619
 
 
3620
 
                        /* see if the plugin is in the link by going through the list */
3621
 
                        for (plugins = link->plugins; plugins; plugins = plugins->next) {
3622
 
                                BraseroPlugin *tmp;
3623
 
 
3624
 
                                tmp = plugins->data;
3625
 
                                if (tmp == plugin)
3626
 
                                        return BRASERO_BURN_OK;
3627
 
                        }
3628
 
                }
3629
 
        }
3630
 
 
3631
 
        return BRASERO_BURN_NOT_SUPPORTED;
3632
 
}
3633
 
 
3634
 
BraseroBurnResult
3635
 
brasero_plugin_can_image (BraseroPlugin *plugin)
3636
 
{
3637
 
        GSList *iter;
3638
 
        BraseroBurnCaps *self;
3639
 
 
3640
 
        self = brasero_burn_caps_get_default ();
3641
 
        for (iter = self->priv->caps_list; iter; iter = iter->next) {
3642
 
                BraseroTrackDataType destination;
3643
 
                BraseroCaps *caps;
3644
 
                GSList *links;
3645
 
 
3646
 
                caps = iter->data;
3647
 
                if (caps->type.type != BRASERO_TRACK_TYPE_IMAGE
3648
 
                &&  caps->type.type != BRASERO_TRACK_TYPE_AUDIO
3649
 
                &&  caps->type.type != BRASERO_TRACK_TYPE_DATA)
3650
 
                        continue;
3651
 
 
3652
 
                destination = caps->type.type;
3653
 
                for (links = caps->links; links; links = links->next) {
3654
 
                        BraseroCapsLink *link;
3655
 
                        GSList *plugins;
3656
 
 
3657
 
                        link = links->data;
3658
 
                        if (!link->caps
3659
 
                        ||   link->caps->type.type == destination)
3660
 
                                continue;
3661
 
 
3662
 
                        /* see if the plugin is in the link by going through the list */
3663
 
                        for (plugins = link->plugins; plugins; plugins = plugins->next) {
3664
 
                                BraseroPlugin *tmp;
3665
 
 
3666
 
                                tmp = plugins->data;
3667
 
                                if (tmp == plugin)
3668
 
                                        return BRASERO_BURN_OK;
3669
 
                        }
3670
 
                }
3671
 
        }
3672
 
 
3673
 
        return BRASERO_BURN_NOT_SUPPORTED;
3674
 
}
3675
 
 
3676
 
BraseroBurnResult
3677
 
brasero_plugin_can_convert (BraseroPlugin *plugin)
3678
 
{
3679
 
        GSList *iter;
3680
 
        BraseroBurnCaps *self;
3681
 
 
3682
 
        self = brasero_burn_caps_get_default ();
3683
 
        for (iter = self->priv->caps_list; iter; iter = iter->next) {
3684
 
                BraseroTrackDataType destination;
3685
 
                BraseroCaps *caps;
3686
 
                GSList *links;
3687
 
 
3688
 
                caps = iter->data;
3689
 
                if (caps->type.type != BRASERO_TRACK_TYPE_IMAGE
3690
 
                &&  caps->type.type != BRASERO_TRACK_TYPE_AUDIO)
3691
 
                        continue;
3692
 
 
3693
 
                destination = caps->type.type;
3694
 
                for (links = caps->links; links; links = links->next) {
3695
 
                        BraseroCapsLink *link;
3696
 
                        GSList *plugins;
3697
 
 
3698
 
                        link = links->data;
3699
 
                        if (!link->caps
3700
 
                        ||   link->caps->type.type != destination)
3701
 
                                continue;
3702
 
 
3703
 
                        /* see if the plugin is in the link by going through the list */
3704
 
                        for (plugins = link->plugins; plugins; plugins = plugins->next) {
3705
 
                                BraseroPlugin *tmp;
3706
 
 
3707
 
                                tmp = plugins->data;
3708
 
                                if (tmp == plugin)
3709
 
                                        return BRASERO_BURN_OK;
3710
 
                        }
3711
 
                }
3712
 
        }
3713
 
 
3714
 
        return BRASERO_BURN_NOT_SUPPORTED;
3715
 
}
3716
 
 
3717
 
/**
3718
 
 * Used to test what the library can do based on the medium type.
3719
 
 * Returns BRASERO_MEDIUM_WRITABLE if the disc can be written
3720
 
 * and / or BRASERO_MEDIUM_REWRITABLE if the disc can be erased.
3721
 
 * Declared in burn-media.h.
3722
 
 */
3723
 
 
3724
 
BraseroMedia
3725
 
brasero_media_capabilities (BraseroMedia media)
3726
 
{
3727
 
        GSList *iter;
3728
 
        GSList *links;
3729
 
        BraseroMedia retval;
3730
 
        BraseroBurnCaps *self;
3731
 
        BraseroCaps *caps = NULL;
3732
 
 
3733
 
        self = brasero_burn_caps_get_default ();
3734
 
 
3735
 
        retval = BRASERO_MEDIUM_NONE;
3736
 
        BRASERO_BURN_LOG_DISC_TYPE (media, "checking media caps for");
3737
 
 
3738
 
        /* we're only interested in DISC caps. There should be only one caps fitting */
3739
 
        for (iter = self->priv->caps_list; iter; iter = iter->next) {
3740
 
                caps = iter->data;
3741
 
                if (caps->type.type != BRASERO_TRACK_TYPE_DISC)
3742
 
                        continue;
3743
 
 
3744
 
                if ((media & caps->type.subtype.media) == media)
3745
 
                        break;
3746
 
 
3747
 
                caps = NULL;
3748
 
        }
3749
 
 
3750
 
        if (!caps)
3751
 
                return BRASERO_MEDIUM_NONE;
3752
 
 
3753
 
        /* check the links */
3754
 
        for (links = caps->links; links; links = links->next) {
3755
 
                GSList *plugins;
3756
 
                gboolean active;
3757
 
                BraseroCapsLink *link;
3758
 
 
3759
 
                link = links->data;
3760
 
 
3761
 
                /* this link must have at least one active plugin to be valid
3762
 
                 * plugins are not sorted but in this case we don't need them
3763
 
                 * to be. we just need one active if another is with a better
3764
 
                 * priority all the better. */
3765
 
                active = FALSE;
3766
 
                for (plugins = link->plugins; plugins; plugins = plugins->next) {
3767
 
                        BraseroPlugin *plugin;
3768
 
 
3769
 
                        plugin = plugins->data;
3770
 
                        if (brasero_plugin_get_active (plugin)) {
3771
 
                                /* this link is valid */
3772
 
                                active = TRUE;
3773
 
                                break;
3774
 
                        }
3775
 
                }
3776
 
 
3777
 
                if (!active)
3778
 
                        continue;
3779
 
 
3780
 
                if (!link->caps) {
3781
 
                        /* means that it can be blanked */
3782
 
                        retval |= BRASERO_MEDIUM_REWRITABLE;
3783
 
                        continue;
3784
 
                }
3785
 
 
3786
 
                /* means it can be written. NOTE: if this disc has already some
3787
 
                 * data on it, it even means it can be appended */
3788
 
                retval |= BRASERO_MEDIUM_WRITABLE;
3789
 
        }
3790
 
 
3791
 
        return retval;
3792
 
}
3793
 
 
3794
 
/**
3795
 
 * This function is declared in burn-basics.h
3796
 
 * It can be used to determine whether or not brasero can do any checksuming.
3797
 
 */
3798
 
 
3799
 
gboolean
3800
 
brasero_burn_library_can_checksum (void)
3801
 
{
3802
 
        GSList *iter;
3803
 
        BraseroBurnCaps *self;
3804
 
 
3805
 
        self = brasero_burn_caps_get_default ();
3806
 
 
3807
 
        if (self->priv->tests == NULL)
3808
 
                return FALSE;
3809
 
 
3810
 
        for (iter = self->priv->tests; iter; iter = iter->next) {
3811
 
                BraseroCapsTest *tmp;
3812
 
                GSList *links;
3813
 
 
3814
 
                tmp = iter->data;
3815
 
                for (links = tmp->links; links; links = links->next) {
3816
 
                        BraseroCapsLink *link;
3817
 
 
3818
 
                        link = links->data;
3819
 
                        if (brasero_caps_link_active (link))
3820
 
                                return TRUE;
3821
 
                }
3822
 
        }
3823
 
 
3824
 
        return FALSE;
3825
 
}
3826
 
 
3827
 
/**
3828
 
 * This is declared in burn-basics.c. It's private stuff that needs to be
3829
 
 * defined in this file. For debugging use only.
3830
 
 */
3831
 
 
3832
 
void
3833
 
brasero_caps_list_dump (void)
3834
 
{
3835
 
        GSList *iter;
3836
 
        BraseroBurnCaps *self;
3837
 
 
3838
 
        self = brasero_burn_caps_get_default ();
3839
 
        for (iter = self->priv->caps_list; iter; iter = iter->next) {
3840
 
                BraseroCaps *caps;
3841
 
 
3842
 
                caps = iter->data;
3843
 
                BRASERO_BURN_LOG_WITH_TYPE (&caps->type,
3844
 
                                            caps->flags,
3845
 
                                            "Created %i links pointing to",
3846
 
                                            g_slist_length (caps->links));
3847
 
        }
3848
 
}
3849
 
 
3850
 
 
3851
 
/**
3852
 
 * Declared in burn-track.h
3853
 
 * This is to determine whether of not a track type is supported
3854
 
 */
3855
 
 
3856
 
BraseroBurnResult
3857
 
brasero_track_type_is_supported (BraseroTrackType *type)
3858
 
{
3859
 
        GSList *iter;
3860
 
        BraseroBurnCaps *self;
3861
 
 
3862
 
        self = brasero_burn_caps_get_default ();
3863
 
 
3864
 
        for (iter = self->priv->caps_list; iter; iter = iter->next) {
3865
 
                BraseroCaps *caps;
3866
 
 
3867
 
                caps = iter->data;
3868
 
 
3869
 
                if (brasero_caps_is_compatible_type (caps, type)
3870
 
                &&  brasero_burn_caps_is_input (self, caps))
3871
 
                        return BRASERO_BURN_OK;
3872
 
        }
3873
 
 
3874
 
        return BRASERO_BURN_ERR;
3875
 
}
3876