[brasero] Missing files that were not taken into account during last commit
- From: Philippe Rouquier <philippr src gnome org>
- To: svn-commits-list gnome org
- Subject: [brasero] Missing files that were not taken into account during last commit
- Date: Sun, 19 Apr 2009 07:55:35 -0400 (EDT)
commit 8b1a7218493615f02a2ce8ec8c73e898086a4441
Author: Philippe Rouquier <bonfire-app wanadoo fr>
Date: Sun Apr 19 13:49:56 2009 +0200
Missing files that were not taken into account during last commit
---
plugins/Makefile.am | 13 +
plugins/cdrdao/Makefile.am | 31 +
plugins/cdrdao/burn-cdrdao-common.h | 39 +
plugins/cdrdao/burn-cdrdao.c | 698 ++++++++++++
plugins/cdrdao/burn-cdrdao.h | 44 +
plugins/cdrdao/burn-toc2cue.c | 339 ++++++
plugins/cdrdao/burn-toc2cue.h | 44 +
plugins/cdrkit/Makefile.am | 39 +
plugins/cdrkit/burn-cdrkit.h | 39 +
plugins/cdrkit/burn-genisoimage.c | 579 ++++++++++
plugins/cdrkit/burn-genisoimage.h | 46 +
plugins/cdrkit/burn-readom.c | 484 +++++++++
plugins/cdrkit/burn-readom.h | 46 +
plugins/cdrkit/burn-wodim.c | 1380 ++++++++++++++++++++++++
plugins/cdrkit/burn-wodim.h | 44 +
plugins/cdrtools/Makefile.am | 39 +
plugins/cdrtools/burn-cdrecord.c | 1371 ++++++++++++++++++++++++
plugins/cdrtools/burn-cdrecord.h | 44 +
plugins/cdrtools/burn-cdrtools.h | 39 +
plugins/cdrtools/burn-mkisofs.c | 586 ++++++++++
plugins/cdrtools/burn-mkisofs.h | 46 +
plugins/cdrtools/burn-readcd.c | 496 +++++++++
plugins/cdrtools/burn-readcd.h | 46 +
plugins/checksum/Makefile.am | 34 +
plugins/checksum/burn-checksum-files.c | 1506 ++++++++++++++++++++++++++
plugins/checksum/burn-checksum-files.h | 44 +
plugins/checksum/burn-checksum-image.c | 824 +++++++++++++++
plugins/checksum/burn-checksum-image.h | 44 +
plugins/checksum/burn-volume-read.c | 397 +++++++
plugins/checksum/burn-volume-read.h | 72 ++
plugins/dvdauthor/Makefile.am | 23 +
plugins/dvdauthor/burn-dvdauthor.c | 423 ++++++++
plugins/dvdauthor/burn-dvdauthor.h | 41 +
plugins/dvdcss/Makefile.am | 22 +
plugins/dvdcss/burn-dvdcss-private.h | 66 ++
plugins/dvdcss/burn-dvdcss.c | 698 ++++++++++++
plugins/dvdcss/burn-dvdcss.h | 48 +
plugins/growisofs/Makefile.am | 30 +
plugins/growisofs/burn-dvd-rw-format.c | 212 ++++
plugins/growisofs/burn-dvd-rw-format.h | 46 +
plugins/growisofs/burn-growisofs-common.h | 39 +
plugins/growisofs/burn-growisofs.c | 924 ++++++++++++++++
plugins/growisofs/burn-growisofs.h | 44 +
plugins/libburnia/Makefile.am | 36 +
plugins/libburnia/burn-libburn-common.c | 377 +++++++
plugins/libburnia/burn-libburn-common.h | 71 ++
plugins/libburnia/burn-libburn.c | 1026 ++++++++++++++++++
plugins/libburnia/burn-libburn.h | 48 +
plugins/libburnia/burn-libburnia.h | 38 +
plugins/libburnia/burn-libisofs.c | 1074 +++++++++++++++++++
plugins/libburnia/burn-libisofs.h | 48 +
plugins/libburnia/burn-libread-disc.h | 68 ++
plugins/local-track/Makefile.am | 31 +
plugins/local-track/burn-local-image.c | 946 +++++++++++++++++
plugins/local-track/burn-local-image.h | 44 +
plugins/local-track/burn-uri.c | 746 +++++++++++++
plugins/local-track/burn-uri.h | 44 +
plugins/transcode/Makefile.am | 36 +
plugins/transcode/burn-normalize.c | 628 +++++++++++
plugins/transcode/burn-normalize.h | 48 +
plugins/transcode/burn-transcode.c | 1647 +++++++++++++++++++++++++++++
plugins/transcode/burn-transcode.h | 44 +
plugins/transcode/burn-vob.c | 1269 ++++++++++++++++++++++
plugins/transcode/burn-vob.h | 41 +
plugins/vcdimager/Makefile.am | 23 +
plugins/vcdimager/burn-vcdimager.c | 527 +++++++++
plugins/vcdimager/burn-vcdimager.h | 36 +
67 files changed, 20965 insertions(+), 0 deletions(-)
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
new file mode 100644
index 0000000..723b75f
--- /dev/null
+++ b/plugins/Makefile.am
@@ -0,0 +1,13 @@
+SUBDIRS = cdrdao transcode dvdcss growisofs checksum local-track dvdauthor vcdimager
+
+if BUILD_LIBBURNIA
+SUBDIRS += libburnia
+endif
+
+if BUILD_CDRKIT
+SUBDIRS += cdrkit
+endif
+
+if BUILD_CDRTOOLS
+SUBDIRS += cdrtools
+endif
diff --git a/plugins/cdrdao/Makefile.am b/plugins/cdrdao/Makefile.am
new file mode 100644
index 0000000..67c0e7e
--- /dev/null
+++ b/plugins/cdrdao/Makefile.am
@@ -0,0 +1,31 @@
+
+INCLUDES = \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/libbrasero-media/ \
+ -I$(top_builddir)/libbrasero-media/ \
+ -I$(top_srcdir)/libbrasero-burn \
+ -I$(top_builddir)/libbrasero-burn/ \
+ -DBRASERO_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
+ -DBRASERO_PREFIX=\"$(prefix)\" \
+ -DBRASERO_SYSCONFDIR=\"$(sysconfdir)\" \
+ -DBRASERO_DATADIR=\"$(datadir)/brasero\" \
+ -DBRASERO_LIBDIR=\"$(libdir)\" \
+ $(DISABLE_DEPRECATED) \
+ $(BRASERO_GLIB_CFLAGS) \
+ $(BRASERO_GCONF_CFLAGS)
+
+#cdrdao
+cdrdaodir = $(libdir)/brasero/plugins
+cdrdao_LTLIBRARIES = libbrasero-cdrdao.la
+libbrasero_cdrdao_la_SOURCES = burn-cdrdao.c burn-cdrdao.h \
+ burn-cdrdao-common.h
+libbrasero_cdrdao_la_LIBADD = $(BRASERO_GLIB_LIBS) $(BRASERO_GCONF_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_cdrdao_la_LDFLAGS = -module -avoid-version
+
+#toc2cue
+toc2cuedir = $(libdir)/brasero/plugins
+toc2cue_LTLIBRARIES = libbrasero-toc2cue.la
+libbrasero_toc2cue_la_SOURCES = burn-toc2cue.c burn-toc2cue.h \
+ burn-cdrdao-common.h
+libbrasero_toc2cue_la_LIBADD = $(BRASERO_GLIB_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_toc2cue_la_LDFLAGS = -module -avoid-version
diff --git a/plugins/cdrdao/burn-cdrdao-common.h b/plugins/cdrdao/burn-cdrdao-common.h
new file mode 100644
index 0000000..f26e3d6
--- /dev/null
+++ b/plugins/cdrdao/burn-cdrdao-common.h
@@ -0,0 +1,39 @@
+/***************************************************************************
+ * burn-cdrdao-common.h
+ *
+ * Mon Oct 29 12:34:41 2007
+ * Copyright 2007 Philippe Rouquier
+ * <bonfire-app wanadoo fr>
+ ****************************************************************************/
+
+/*
+ * Libbrasero-media is free software; you can redistribute it and/or modify
+fy
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA
+ */
+
+#ifndef _BURN_CDRDAO_COMMON_H
+#define _BURN_CDRDAO_COMMON_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define CDRDAO_DESCRIPTION N_("Cdrdao burning suite")
+
+G_END_DECLS
+
+#endif /* _BURN_CDRDAO_COMMON_H */
+
+
diff --git a/plugins/cdrdao/burn-cdrdao.c b/plugins/cdrdao/burn-cdrdao.c
new file mode 100644
index 0000000..080ed27
--- /dev/null
+++ b/plugins/cdrdao/burn-cdrdao.c
@@ -0,0 +1,698 @@
+/***************************************************************************
+ * cdrdao.c
+ *
+ * dim jan 22 15:38:18 2006
+ * Copyright 2006 Rouquier Philippe
+ * brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+#include <gmodule.h>
+
+#include <gconf/gconf-client.h>
+
+#include "burn-cdrdao-common.h"
+#include "burn-cdrdao.h"
+#include "brasero-error.h"
+#include "brasero-plugin-registration.h"
+#include "burn-job.h"
+#include "burn-process.h"
+#include "brasero-track-disc.h"
+#include "brasero-track-image.h"
+#include "brasero-drive.h"
+#include "brasero-medium.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroCdrdao, brasero_cdrdao, BRASERO_TYPE_PROCESS, BraseroProcess);
+
+struct _BraseroCdrdaoPrivate {
+ guint use_raw:1;
+};
+typedef struct _BraseroCdrdaoPrivate BraseroCdrdaoPrivate;
+#define BRASERO_CDRDAO_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_CDRDAO, BraseroCdrdaoPrivate))
+
+static GObjectClass *parent_class = NULL;
+
+#define GCONF_KEY_RAW_FLAG "/apps/brasero/config/raw_flag"
+
+static gboolean
+brasero_cdrdao_read_stderr_image (BraseroCdrdao *cdrdao, const gchar *line)
+{
+ int min, sec, sub, s1;
+
+ if (sscanf (line, "%d:%d:%d", &min, &sec, &sub) == 3) {
+ guint64 secs = min * 60 + sec;
+
+ brasero_job_set_written_track (BRASERO_JOB (cdrdao), secs * 75 * 2352);
+ if (secs > 2)
+ brasero_job_start_progress (BRASERO_JOB (cdrdao), FALSE);
+ }
+ else if (sscanf (line, "Leadout %*s %*d %d:%d:%*d(%i)", &min, &sec, &s1) == 3) {
+ BraseroJobAction action;
+
+ brasero_job_get_action (BRASERO_JOB (cdrdao), &action);
+ if (action == BRASERO_JOB_ACTION_SIZE) {
+ /* get the number of sectors. As we added -raw sector = 2352 bytes */
+ brasero_job_set_output_size_for_current_track (BRASERO_JOB (cdrdao), s1, (gint64) s1 * 2352ULL);
+ brasero_job_finished_session (BRASERO_JOB (cdrdao));
+ }
+ }
+ else if (strstr (line, "Copying audio tracks")) {
+ brasero_job_set_current_action (BRASERO_JOB (cdrdao),
+ BRASERO_BURN_ACTION_DRIVE_COPY,
+ _("Copying audio track"),
+ FALSE);
+ }
+ else if (strstr (line, "Copying data track")) {
+ brasero_job_set_current_action (BRASERO_JOB (cdrdao),
+ BRASERO_BURN_ACTION_DRIVE_COPY,
+ _("Copying data track"),
+ FALSE);
+ }
+ else
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+brasero_cdrdao_read_stderr_record (BraseroCdrdao *cdrdao, const gchar *line)
+{
+ int fifo, track, min, sec;
+ guint written, total;
+
+ if (sscanf (line, "Wrote %u of %u (Buffers %d%% %*s", &written, &total, &fifo) >= 2) {
+ brasero_job_set_dangerous (BRASERO_JOB (cdrdao), TRUE);
+
+ brasero_job_set_written_session (BRASERO_JOB (cdrdao), written * 1048576);
+ brasero_job_set_current_action (BRASERO_JOB (cdrdao),
+ BRASERO_BURN_ACTION_RECORDING,
+ NULL,
+ FALSE);
+
+ brasero_job_start_progress (BRASERO_JOB (cdrdao), FALSE);
+ }
+ else if (sscanf (line, "Wrote %*s blocks. Buffer fill min") == 1) {
+ /* this is for fixating phase */
+ brasero_job_set_current_action (BRASERO_JOB (cdrdao),
+ BRASERO_BURN_ACTION_FIXATING,
+ NULL,
+ FALSE);
+ }
+ else if (sscanf (line, "Analyzing track %d %*s start %d:%d:%*d, length %*d:%*d:%*d", &track, &min, &sec) == 3) {
+ gchar *string;
+
+ string = g_strdup_printf (_("Analysing track %02i"), track);
+ brasero_job_set_current_action (BRASERO_JOB (cdrdao),
+ BRASERO_BURN_ACTION_ANALYSING,
+ string,
+ TRUE);
+ g_free (string);
+ }
+ else if (sscanf (line, "%d:%d:%*d", &min, &sec) == 2) {
+ gint64 written;
+ guint64 secs = min * 60 + sec;
+
+ if (secs > 2)
+ brasero_job_start_progress (BRASERO_JOB (cdrdao), FALSE);
+
+ written = secs * 75 * 2352;
+ brasero_job_set_written_session (BRASERO_JOB (cdrdao), written);
+ }
+ else if (strstr (line, "Writing track")) {
+ brasero_job_set_dangerous (BRASERO_JOB (cdrdao), TRUE);
+ }
+ else if (strstr (line, "Writing finished successfully")
+ || strstr (line, "On-the-fly CD copying finished successfully")) {
+ brasero_job_set_dangerous (BRASERO_JOB (cdrdao), FALSE);
+ }
+ else if (strstr (line, "Blanking disk...")) {
+ brasero_job_set_current_action (BRASERO_JOB (cdrdao),
+ BRASERO_BURN_ACTION_BLANKING,
+ NULL,
+ FALSE);
+ brasero_job_start_progress (BRASERO_JOB (cdrdao), FALSE);
+ brasero_job_set_dangerous (BRASERO_JOB (cdrdao), TRUE);
+ }
+ else {
+ gchar *name = NULL;
+ gchar *cuepath = NULL;
+ BraseroTrack *track = NULL;
+ BraseroJobAction action;
+
+ /* Try to catch error could not find cue file */
+
+ /* Track could be NULL here if we're simply blanking a medium */
+ brasero_job_get_action (BRASERO_JOB (cdrdao), &action);
+ if (action == BRASERO_JOB_ACTION_ERASE)
+ return TRUE;
+
+ brasero_job_get_current_track (BRASERO_JOB (cdrdao), &track);
+ if (!track)
+ return FALSE;
+
+ cuepath = brasero_track_image_get_toc_source (BRASERO_TRACK_IMAGE (track), FALSE);
+
+ if (!cuepath)
+ return FALSE;
+
+ if (!strstr (line, cuepath)
+ && !strstr (line, "ERROR: Could not find input file")) {
+ g_free (cuepath);
+ return FALSE;
+ }
+
+ name = g_path_get_basename (cuepath);
+ g_free (cuepath);
+
+ brasero_job_error (BRASERO_JOB (cdrdao),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_FILE_NOT_FOUND,
+ /* Translators: %s is a filename */
+ _("\"%s\" could not be found"),
+ name));
+ g_free (name);
+ }
+
+ return TRUE;
+}
+
+static BraseroBurnResult
+brasero_cdrdao_read_stderr (BraseroProcess *process, const gchar *line)
+{
+ BraseroCdrdao *cdrdao;
+ gboolean result = FALSE;
+ BraseroJobAction action;
+
+ cdrdao = BRASERO_CDRDAO (process);
+
+ brasero_job_get_action (BRASERO_JOB (cdrdao), &action);
+ if (action == BRASERO_JOB_ACTION_RECORD
+ || action == BRASERO_JOB_ACTION_ERASE)
+ result = brasero_cdrdao_read_stderr_record (cdrdao, line);
+ else if (action == BRASERO_JOB_ACTION_IMAGE
+ || action == BRASERO_JOB_ACTION_SIZE)
+ result = brasero_cdrdao_read_stderr_image (cdrdao, line);
+
+ if (result)
+ return BRASERO_BURN_OK;
+
+ if (strstr (line, "Cannot setup device")) {
+ brasero_job_error (BRASERO_JOB (cdrdao),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_DRIVE_BUSY,
+ _("The drive is busy")));
+ }
+ else if (strstr (line, "Illegal command")) {
+ brasero_job_error (BRASERO_JOB (cdrdao),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("Your version of cdrdao does not seem to be supported by libbrasero")));
+ }
+ else if (strstr (line, "Operation not permitted. Cannot send SCSI")) {
+ brasero_job_error (BRASERO_JOB (cdrdao),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_PERMISSION,
+ _("You do not have the required permissions to use this drive")));
+ }
+
+ return BRASERO_BURN_OK;
+}
+
+static void
+brasero_cdrdao_set_argv_device (BraseroCdrdao *cdrdao,
+ GPtrArray *argv)
+{
+ gchar *device = NULL;
+
+ g_ptr_array_add (argv, g_strdup ("--device"));
+
+#ifdef HAVE_CAM_LIB_H
+ /* FreeBSD like that better */
+ brasero_job_get_bus_target_lun (BRASERO_JOB (cdrdao), &device);
+#else
+ brasero_job_get_device (BRASERO_JOB (cdrdao), &device);
+#endif
+
+ g_ptr_array_add (argv, device);
+}
+
+static void
+brasero_cdrdao_set_argv_common_rec (BraseroCdrdao *cdrdao,
+ GPtrArray *argv)
+{
+ BraseroBurnFlag flags;
+ gchar *speed_str;
+ guint speed;
+
+ brasero_job_get_flags (BRASERO_JOB (cdrdao), &flags);
+ if (flags & BRASERO_BURN_FLAG_DUMMY)
+ g_ptr_array_add (argv, g_strdup ("--simulate"));
+
+ g_ptr_array_add (argv, g_strdup ("--speed"));
+
+ brasero_job_get_speed (BRASERO_JOB (cdrdao), &speed);
+ speed_str = g_strdup_printf ("%d", speed);
+ g_ptr_array_add (argv, speed_str);
+
+ if (flags & BRASERO_BURN_FLAG_OVERBURN)
+ g_ptr_array_add (argv, g_strdup ("--overburn"));
+ if (flags & BRASERO_BURN_FLAG_MULTI)
+ g_ptr_array_add (argv, g_strdup ("--multi"));
+}
+
+static void
+brasero_cdrdao_set_argv_common (BraseroCdrdao *cdrdao,
+ GPtrArray *argv)
+{
+ BraseroBurnFlag flags;
+
+ brasero_job_get_flags (BRASERO_JOB (cdrdao), &flags);
+
+ /* cdrdao manual says it is a similar option to gracetime */
+ if (flags & BRASERO_BURN_FLAG_NOGRACE)
+ g_ptr_array_add (argv, g_strdup ("-n"));
+
+ g_ptr_array_add (argv, g_strdup ("-v"));
+ g_ptr_array_add (argv, g_strdup ("2"));
+}
+
+static BraseroBurnResult
+brasero_cdrdao_set_argv_record (BraseroCdrdao *cdrdao,
+ GPtrArray *argv)
+{
+ BraseroTrackType *type = NULL;
+ BraseroCdrdaoPrivate *priv;
+
+ priv = BRASERO_CDRDAO_PRIVATE (cdrdao);
+
+ g_ptr_array_add (argv, g_strdup ("cdrdao"));
+
+ type = brasero_track_type_new ();
+ brasero_job_get_input_type (BRASERO_JOB (cdrdao), type);
+
+ if (brasero_track_type_get_has_medium (type)) {
+ BraseroDrive *drive;
+ BraseroTrack *track;
+ BraseroBurnFlag flags;
+
+ g_ptr_array_add (argv, g_strdup ("copy"));
+ brasero_cdrdao_set_argv_device (cdrdao, argv);
+ brasero_cdrdao_set_argv_common (cdrdao, argv);
+ brasero_cdrdao_set_argv_common_rec (cdrdao, argv);
+
+ brasero_job_get_flags (BRASERO_JOB (cdrdao), &flags);
+ if (flags & BRASERO_BURN_FLAG_NO_TMP_FILES)
+ g_ptr_array_add (argv, g_strdup ("--on-the-fly"));
+
+ if (priv->use_raw)
+ g_ptr_array_add (argv, g_strdup ("--driver generic-mmc-raw"));
+
+ g_ptr_array_add (argv, g_strdup ("--source-device"));
+
+ brasero_job_get_current_track (BRASERO_JOB (cdrdao), &track);
+ drive = brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track));
+
+#ifdef HAVE_CAM_LIB_H
+ /* FreeBSD like that better */
+ g_ptr_array_add (argv, brasero_drive_get_bus_target_lun_string (drive));
+#else
+ g_ptr_array_add (argv, g_strdup (brasero_drive_get_device (drive)));
+#endif
+
+ }
+ else if (brasero_track_type_get_has_image (type)) {
+ gchar *cuepath;
+ BraseroTrack *track;
+
+ brasero_job_get_current_track (BRASERO_JOB (cdrdao), &track);
+
+ if (brasero_track_type_get_image_format (type) == BRASERO_IMAGE_FORMAT_CUE) {
+ gchar *parent;
+
+ cuepath = brasero_track_image_get_toc_source (BRASERO_TRACK_IMAGE (track), FALSE);
+ parent = g_path_get_dirname (cuepath);
+ brasero_process_set_working_directory (BRASERO_PROCESS (cdrdao), parent);
+ g_free (parent);
+ }
+ else if (brasero_track_type_get_image_format (type) == BRASERO_IMAGE_FORMAT_CDRDAO)
+ cuepath = brasero_track_image_get_toc_source (BRASERO_TRACK_IMAGE (track), FALSE);
+ else {
+ brasero_track_type_free (type);
+ BRASERO_JOB_NOT_SUPPORTED (cdrdao);
+ }
+
+ if (!cuepath) {
+ brasero_track_type_free (type);
+ BRASERO_JOB_NOT_READY (cdrdao);
+ }
+
+ g_ptr_array_add (argv, g_strdup ("write"));
+
+ brasero_cdrdao_set_argv_device (cdrdao, argv);
+ brasero_cdrdao_set_argv_common (cdrdao, argv);
+ brasero_cdrdao_set_argv_common_rec (cdrdao, argv);
+
+ g_ptr_array_add (argv, cuepath);
+ }
+ else {
+ brasero_track_type_free (type);
+ BRASERO_JOB_NOT_SUPPORTED (cdrdao);
+ }
+
+ brasero_track_type_free (type);
+ brasero_job_set_use_average_rate (BRASERO_JOB (cdrdao), TRUE);
+ brasero_job_set_current_action (BRASERO_JOB (cdrdao),
+ BRASERO_BURN_ACTION_START_RECORDING,
+ NULL,
+ FALSE);
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_cdrdao_set_argv_blank (BraseroCdrdao *cdrdao,
+ GPtrArray *argv)
+{
+ BraseroBurnFlag flags;
+
+ g_ptr_array_add (argv, g_strdup ("cdrdao"));
+ g_ptr_array_add (argv, g_strdup ("blank"));
+
+ brasero_cdrdao_set_argv_device (cdrdao, argv);
+ brasero_cdrdao_set_argv_common (cdrdao, argv);
+
+ g_ptr_array_add (argv, g_strdup ("--blank-mode"));
+ brasero_job_get_flags (BRASERO_JOB (cdrdao), &flags);
+ if (!(flags & BRASERO_BURN_FLAG_FAST_BLANK))
+ g_ptr_array_add (argv, g_strdup ("full"));
+ else
+ g_ptr_array_add (argv, g_strdup ("minimal"));
+
+ brasero_job_set_current_action (BRASERO_JOB (cdrdao),
+ BRASERO_BURN_ACTION_BLANKING,
+ NULL,
+ FALSE);
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_cdrdao_set_argv_image (BraseroCdrdao *cdrdao,
+ GPtrArray *argv,
+ GError **error)
+{
+ gchar *image = NULL, *toc = NULL;
+ BraseroTrackType *output = NULL;
+ BraseroBurnResult result;
+ BraseroJobAction action;
+ BraseroDrive *drive;
+ BraseroTrack *track;
+
+ g_ptr_array_add (argv, g_strdup ("cdrdao"));
+ g_ptr_array_add (argv, g_strdup ("read-cd"));
+ g_ptr_array_add (argv, g_strdup ("--device"));
+
+ brasero_job_get_current_track (BRASERO_JOB (cdrdao), &track);
+ drive = brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track));
+
+#ifdef HAVE_CAM_LIB_H
+ /* FreeBSD like that better */
+ g_ptr_array_add (argv, brasero_drive_get_bus_target_lun_string (drive));
+#else
+ g_ptr_array_add (argv, g_strdup (brasero_drive_get_device (drive)));
+#endif
+
+ g_ptr_array_add (argv, g_strdup ("--read-raw"));
+
+ /* This is done so that if a cue file is required we first generate
+ * a temporary toc file that will be later converted to a cue file.
+ * The datafile is written where it should be from the start. */
+ output = brasero_track_type_new ();
+ brasero_job_get_output_type (BRASERO_JOB (cdrdao), output);
+
+ if (brasero_track_type_get_image_format (output) == BRASERO_IMAGE_FORMAT_CDRDAO) {
+ result = brasero_job_get_image_output (BRASERO_JOB (cdrdao),
+ &image,
+ &toc);
+ if (result != BRASERO_BURN_OK) {
+ brasero_track_type_free (output);
+ return result;
+ }
+ }
+ else {
+ result = brasero_job_get_image_output (BRASERO_JOB (cdrdao),
+ &image,
+ NULL);
+ if (result != BRASERO_BURN_OK) {
+ brasero_track_type_free (output);
+ return result;
+ }
+
+ result = brasero_job_get_tmp_file (BRASERO_JOB (cdrdao),
+ NULL,
+ &toc,
+ error);
+ if (result != BRASERO_BURN_OK) {
+ brasero_track_type_free (output);
+ return result;
+ }
+ }
+
+ brasero_track_type_free (output);
+
+ /* it's safe to remove them: session/task make sure they don't exist
+ * when there is the proper flag whether it be tmp or real output. */
+ if (toc)
+ g_remove (toc);
+ if (image)
+ g_remove (image);
+
+ brasero_job_get_action (BRASERO_JOB (cdrdao), &action);
+ if (action == BRASERO_JOB_ACTION_SIZE) {
+ brasero_job_set_current_action (BRASERO_JOB (cdrdao),
+ BRASERO_BURN_ACTION_GETTING_SIZE,
+ NULL,
+ FALSE);
+ brasero_job_start_progress (BRASERO_JOB (cdrdao), FALSE);
+ }
+
+ g_ptr_array_add (argv, g_strdup ("--datafile"));
+ g_ptr_array_add (argv, image);
+
+ g_ptr_array_add (argv, g_strdup ("-v"));
+ g_ptr_array_add (argv, g_strdup ("2"));
+
+ g_ptr_array_add (argv, toc);
+
+ brasero_job_set_use_average_rate (BRASERO_JOB (cdrdao), TRUE);
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_cdrdao_set_argv (BraseroProcess *process,
+ GPtrArray *argv,
+ GError **error)
+{
+ BraseroCdrdao *cdrdao;
+ BraseroJobAction action;
+
+ cdrdao = BRASERO_CDRDAO (process);
+
+ /* sets the first argv */
+ brasero_job_get_action (BRASERO_JOB (cdrdao), &action);
+ if (action == BRASERO_JOB_ACTION_RECORD)
+ return brasero_cdrdao_set_argv_record (cdrdao, argv);
+ else if (action == BRASERO_JOB_ACTION_ERASE)
+ return brasero_cdrdao_set_argv_blank (cdrdao, argv);
+ else if (action == BRASERO_JOB_ACTION_IMAGE)
+ return brasero_cdrdao_set_argv_image (cdrdao, argv, error);
+ else if (action == BRASERO_JOB_ACTION_SIZE) {
+ BraseroTrack *track;
+
+ brasero_job_get_current_track (BRASERO_JOB (cdrdao), &track);
+ if (BRASERO_IS_TRACK_DISC (track)) {
+ guint64 sectors = 0;
+
+ brasero_track_get_size (track, §ors, NULL);
+
+ /* cdrdao won't get a track size under 300 sectors */
+ if (sectors < 300)
+ sectors = 300;
+
+ brasero_job_set_output_size_for_current_track (BRASERO_JOB (cdrdao),
+ sectors,
+ sectors * 2352ULL);
+ }
+ else
+ return BRASERO_BURN_NOT_SUPPORTED;
+
+ return BRASERO_BURN_NOT_RUNNING;
+ }
+
+ BRASERO_JOB_NOT_SUPPORTED (cdrdao);
+}
+
+static void
+brasero_cdrdao_class_init (BraseroCdrdaoClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ BraseroProcessClass *process_class = BRASERO_PROCESS_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (BraseroCdrdaoPrivate));
+
+ parent_class = g_type_class_peek_parent(klass);
+ object_class->finalize = brasero_cdrdao_finalize;
+
+ process_class->stderr_func = brasero_cdrdao_read_stderr;
+ process_class->set_argv = brasero_cdrdao_set_argv;
+ process_class->post = brasero_job_finished_session;
+}
+
+static void
+brasero_cdrdao_init (BraseroCdrdao *obj)
+{
+ GConfClient *client;
+ BraseroCdrdaoPrivate *priv;
+
+ /* load our "configuration" */
+ priv = BRASERO_CDRDAO_PRIVATE (obj);
+
+ client = gconf_client_get_default ();
+ priv->use_raw = gconf_client_get_bool (client,
+ GCONF_KEY_RAW_FLAG,
+ NULL);
+
+ g_object_unref (client);
+}
+
+static void
+brasero_cdrdao_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static BraseroBurnResult
+brasero_cdrdao_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+ GSList *input;
+ GSList *output;
+ BraseroBurnResult result;
+ BraseroPluginConfOption *use_raw;
+ const BraseroMedia media_w = BRASERO_MEDIUM_CD|
+ BRASERO_MEDIUM_WRITABLE|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_BLANK;
+ const BraseroMedia media_rw = BRASERO_MEDIUM_CD|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_CLOSED|
+ BRASERO_MEDIUM_HAS_DATA|
+ BRASERO_MEDIUM_HAS_AUDIO|
+ BRASERO_MEDIUM_BLANK;
+
+ brasero_plugin_define (plugin,
+ "Cdrdao",
+ _("Use cdrdao to copy and burn CDs"),
+ "Philippe Rouquier",
+ 20);
+
+ /* First see if this plugin can be used */
+ result = brasero_process_check_path ("cdrdao", error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+
+ /* that's for cdrdao images: CDs only as input */
+ input = brasero_caps_disc_new (BRASERO_MEDIUM_CD|
+ BRASERO_MEDIUM_ROM|
+ BRASERO_MEDIUM_WRITABLE|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_CLOSED|
+ BRASERO_MEDIUM_HAS_AUDIO|
+ BRASERO_MEDIUM_HAS_DATA);
+
+ /* an image can be created ... */
+ output = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_IMAGE_FORMAT_CDRDAO);
+
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (output);
+
+ /* ... or a disc */
+ output = brasero_caps_disc_new (media_w);
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (input);
+
+ /* cdrdao can also record these types of images to a disc */
+ input = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_IMAGE_FORMAT_CDRDAO|
+ BRASERO_IMAGE_FORMAT_CUE);
+
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (output);
+ g_slist_free (input);
+
+ /* cdrdao is used to burn images so it can't APPEND and the disc must
+ * have been blanked before (it can't overwrite)
+ * NOTE: BRASERO_MEDIUM_FILE is needed here because of restriction API
+ * when we output an image. */
+ brasero_plugin_set_flags (plugin,
+ media_w|
+ BRASERO_MEDIUM_FILE,
+ BRASERO_BURN_FLAG_DAO|
+ BRASERO_BURN_FLAG_BURNPROOF|
+ BRASERO_BURN_FLAG_OVERBURN|
+ BRASERO_BURN_FLAG_DUMMY|
+ BRASERO_BURN_FLAG_NOGRACE,
+ BRASERO_BURN_FLAG_NONE);
+
+ /* cdrdao can also blank */
+ output = brasero_caps_disc_new (media_rw);
+ brasero_plugin_blank_caps (plugin, output);
+ g_slist_free (output);
+
+ brasero_plugin_set_blank_flags (plugin,
+ media_rw,
+ BRASERO_BURN_FLAG_NOGRACE|
+ BRASERO_BURN_FLAG_FAST_BLANK,
+ BRASERO_BURN_FLAG_NONE);
+
+ use_raw = brasero_plugin_conf_option_new (GCONF_KEY_RAW_FLAG,
+ _("Enable \"--driver generic-mmc-raw\" flag (see cdrdao manual)"),
+ BRASERO_PLUGIN_OPTION_BOOL);
+
+ brasero_plugin_add_conf_option (plugin, use_raw);
+
+ brasero_plugin_register_group (plugin, _(CDRDAO_DESCRIPTION));
+ return BRASERO_BURN_OK;
+}
diff --git a/plugins/cdrdao/burn-cdrdao.h b/plugins/cdrdao/burn-cdrdao.h
new file mode 100644
index 0000000..3a50a2c
--- /dev/null
+++ b/plugins/cdrdao/burn-cdrdao.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ * cdrdao.h
+ *
+ * dim jan 22 15:38:18 2006
+ * Copyright 2006 Rouquier Philippe
+ * brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef CDRDAO_H
+#define CDRDAO_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_CDRDAO (brasero_cdrdao_get_type ())
+#define BRASERO_CDRDAO(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_CDRDAO, BraseroCdrdao))
+#define BRASERO_CDRDAO_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_CDRDAO, BraseroCdrdaoClass))
+#define BRASERO_IS_CDRDAO(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_CDRDAO))
+#define BRASERO_IS_CDRDAO_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_CDRDAO))
+#define BRASERO_CDRDAO_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_CDRDAO, BraseroCdrdaoClass))
+
+G_END_DECLS
+
+#endif /* CDRDAO_H */
diff --git a/plugins/cdrdao/burn-toc2cue.c b/plugins/cdrdao/burn-toc2cue.c
new file mode 100644
index 0000000..902aaf8
--- /dev/null
+++ b/plugins/cdrdao/burn-toc2cue.c
@@ -0,0 +1,339 @@
+/***************************************************************************
+ * burn-toc2cue.c
+ *
+ * mar oct 3 18:30:51 2006
+ * Copyright 2006 Philippe Rouquier
+ * bonfire-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+#include <gmodule.h>
+
+#include "brasero-plugin-registration.h"
+#include "burn-job.h"
+#include "burn-process.h"
+#include "burn-cdrdao-common.h"
+#include "burn-toc2cue.h"
+#include "brasero-track-image.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroToc2Cue, brasero_toc2cue, BRASERO_TYPE_PROCESS, BraseroProcess);
+
+struct _BraseroToc2CuePrivate {
+ gchar *output;
+};
+typedef struct _BraseroToc2CuePrivate BraseroToc2CuePrivate;
+
+#define BRASERO_TOC2CUE_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_TOC2CUE, BraseroToc2CuePrivate))
+
+static BraseroProcessClass *parent_class = NULL;
+
+static BraseroBurnResult
+brasero_toc2cue_read_stdout (BraseroProcess *process,
+ const gchar *line)
+{
+ BraseroToc2Cue *self;
+
+ self = BRASERO_TOC2CUE (process);
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_toc2cue_read_stderr (BraseroProcess *process,
+ const gchar *line)
+{
+ BraseroTrack *current = NULL;
+ BraseroToc2CuePrivate *priv;
+ BraseroTrackImage *track;
+ BraseroToc2Cue *self;
+ GError *error = NULL;
+ gchar *tmp_img_path;
+ GIOChannel *source;
+ guint tmp_path_len;
+ GIOStatus status;
+ gchar *img_path;
+ gchar *toc_path;
+ gchar *buffer;
+ FILE *output;
+
+ self = BRASERO_TOC2CUE (process);
+ priv = BRASERO_TOC2CUE_PRIVATE (self);
+
+ if (!strstr (line, "Converted toc-file"))
+ return BRASERO_BURN_OK;
+
+ /* Now we also need to replace all the occurences of tmp file name by
+ * the real output file name in the created cue */
+ source = g_io_channel_new_file (priv->output, "r", &error);
+ if (!source) {
+ brasero_job_error (BRASERO_JOB (process), error);
+ return BRASERO_BURN_OK;
+ }
+
+ brasero_job_get_image_output (BRASERO_JOB (self),
+ &img_path,
+ &toc_path);
+
+ output = fopen (toc_path, "w");
+ if (!output) {
+ int errsv = errno;
+
+ g_io_channel_unref (source);
+
+ g_free (img_path);
+ g_free (toc_path);
+
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new_literal (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ g_strerror (errsv)));
+ return BRASERO_BURN_OK;
+ }
+
+ /* get the path of the image that should remain unchanged */
+ brasero_job_get_current_track (BRASERO_JOB (self), ¤t);
+ tmp_img_path = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (current), FALSE);
+ tmp_path_len = strlen (tmp_img_path);
+
+ status = g_io_channel_read_line (source, &buffer, NULL, NULL, &error);
+ while (status == G_IO_STATUS_NORMAL) {
+ gchar *location;
+
+ location = strstr (buffer, tmp_img_path);
+ if (location) {
+ gchar *tmp;
+
+ tmp = buffer;
+ buffer = g_strdup_printf ("%.*s%s%s",
+ location - buffer,
+ buffer,
+ img_path,
+ location + tmp_path_len);
+ g_free (tmp);
+ }
+
+ if (!fwrite (buffer, strlen (buffer), 1, output)) {
+ int errsv = errno;
+
+ g_free (buffer);
+
+ fclose (output);
+ g_io_channel_unref (source);
+
+ g_free (tmp_img_path);
+
+ g_free (img_path);
+ g_free (toc_path);
+
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new_literal (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ g_strerror (errsv)));
+ return BRASERO_BURN_OK;
+ }
+
+ g_free (buffer);
+ status = g_io_channel_read_line (source, &buffer, NULL, NULL, &error);
+ }
+
+ fclose (output);
+ g_io_channel_unref (source);
+
+ if (status == G_IO_STATUS_ERROR) {
+ g_free (tmp_img_path);
+ g_free (img_path);
+ g_free (toc_path);
+ brasero_job_error (BRASERO_JOB (process), error);
+ return BRASERO_BURN_OK;
+ }
+
+ /* the previous track image path will now be a link pointing to the
+ * image path of the new track just created */
+ if (g_rename (tmp_img_path, img_path)) {
+ int errsv = errno;
+
+ brasero_job_error (BRASERO_JOB (self),
+ g_error_new_literal (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ g_strerror (errsv)));
+ return BRASERO_BURN_OK;
+ }
+
+ if (link (img_path, tmp_img_path)) {
+ int errsv = errno;
+
+ brasero_job_error (BRASERO_JOB (self),
+ g_error_new_literal (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ g_strerror (errsv)));
+ return BRASERO_BURN_OK;
+ } /* symlink () could also be used */
+
+ track = brasero_track_image_new ();
+ brasero_track_image_set_source (track,
+ img_path,
+ toc_path,
+ BRASERO_IMAGE_FORMAT_CUE);
+
+ g_free (tmp_img_path);
+ g_free (img_path);
+ g_free (toc_path);
+
+ brasero_job_add_track (BRASERO_JOB (process), BRASERO_TRACK (track));
+
+ /* It's good practice to unref the track afterwards as we don't need it
+ * anymore. BraseroTaskCtx refs it. */
+ g_object_unref (track);
+
+ brasero_job_finished_track (BRASERO_JOB (process));
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_toc2cue_set_argv (BraseroProcess *process,
+ GPtrArray *argv,
+ GError **error)
+{
+ BraseroToc2CuePrivate *priv;
+ BraseroBurnResult result;
+ BraseroJobAction action;
+ BraseroToc2Cue *self;
+ BraseroTrack *track;
+ gchar *tocpath;
+ gchar *output;
+
+ self = BRASERO_TOC2CUE (process);
+ priv = BRASERO_TOC2CUE_PRIVATE (self);
+
+ brasero_job_get_action (BRASERO_JOB (self), &action);
+ if (action != BRASERO_JOB_ACTION_IMAGE)
+ BRASERO_JOB_NOT_SUPPORTED (process);
+
+ result = brasero_job_get_tmp_file (BRASERO_JOB (process),
+ NULL,
+ &output,
+ error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+
+ brasero_job_get_current_track (BRASERO_JOB (self), &track);
+ tocpath = brasero_track_image_get_toc_source (BRASERO_TRACK_IMAGE (track), FALSE);
+
+ priv->output = g_strdup (output);
+ g_remove (priv->output);
+
+ g_ptr_array_add (argv, g_strdup ("toc2cue"));
+ g_ptr_array_add (argv, tocpath);
+ g_ptr_array_add (argv, output);
+
+ brasero_job_set_current_action (BRASERO_JOB (self),
+ BRASERO_BURN_ACTION_CREATING_IMAGE,
+ _("Converting toc file"),
+ FALSE);
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_toc2cue_post (BraseroJob *job)
+{
+ BraseroToc2CuePrivate *priv;
+
+ priv = BRASERO_TOC2CUE_PRIVATE (job);
+ if (priv->output) {
+ g_free (priv->output);
+ priv->output = NULL;
+ }
+
+ return brasero_job_finished_session (job);
+}
+
+static void
+brasero_toc2cue_class_init (BraseroToc2CueClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ BraseroProcessClass *process_class = BRASERO_PROCESS_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (BraseroToc2CuePrivate));
+
+ parent_class = g_type_class_peek_parent (klass);
+ object_class->finalize = brasero_toc2cue_finalize;
+
+ process_class->stdout_func = brasero_toc2cue_read_stdout;
+ process_class->stderr_func = brasero_toc2cue_read_stderr;
+ process_class->set_argv = brasero_toc2cue_set_argv;
+ process_class->post = brasero_toc2cue_post;
+}
+
+static void
+brasero_toc2cue_init (BraseroToc2Cue *obj)
+{ }
+
+static void
+brasero_toc2cue_finalize (GObject *object)
+{
+ brasero_toc2cue_post (BRASERO_JOB (object));
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static BraseroBurnResult
+brasero_toc2cue_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+ BraseroBurnResult result;
+ GSList *output;
+ GSList *input;
+
+ brasero_plugin_define (plugin,
+ "toc2cue",
+ _("Toc2cue converts .toc files into .cue files"),
+ "Philippe Rouquier",
+ 0);
+
+ /* First see if this plugin can be used */
+ result = brasero_process_check_path ("toc2cue", error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+
+ input = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_IMAGE_FORMAT_CDRDAO);
+
+ output = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_IMAGE_FORMAT_CUE);
+
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (output);
+ g_slist_free (input);
+
+ brasero_plugin_register_group (plugin, _(CDRDAO_DESCRIPTION));
+
+ return BRASERO_BURN_OK;
+}
diff --git a/plugins/cdrdao/burn-toc2cue.h b/plugins/cdrdao/burn-toc2cue.h
new file mode 100644
index 0000000..e3af7d2
--- /dev/null
+++ b/plugins/cdrdao/burn-toc2cue.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ * burn-toc2cue.h
+ *
+ * mar oct 3 18:30:51 2006
+ * Copyright 2006 Philippe Rouquier
+ * bonfire-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef BURN_TOC2CUE_H
+#define BURN_TOC2CUE_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_TOC2CUE (brasero_toc2cue_get_type ())
+#define BRASERO_TOC2CUE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_TOC2CUE, BraseroToc2Cue))
+#define BRASERO_TOC2CUE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_TOC2CUE, BraseroToc2CueClass))
+#define BRASERO_IS_TOC2CUE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_TOC2CUE))
+#define BRASERO_IS_TOC2CUE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_TOC2CUE))
+#define BRASERO_TOC2CUE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_TOC2CUE, BraseroToc2CueClass))
+
+G_END_DECLS
+
+#endif /* BURN_TOC2CUE_H */
diff --git a/plugins/cdrkit/Makefile.am b/plugins/cdrkit/Makefile.am
new file mode 100644
index 0000000..8d56bfd
--- /dev/null
+++ b/plugins/cdrkit/Makefile.am
@@ -0,0 +1,39 @@
+
+INCLUDES = \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/libbrasero-media/ \
+ -I$(top_builddir)/libbrasero-media/ \
+ -I$(top_srcdir)/libbrasero-burn \
+ -I$(top_builddir)/libbrasero-burn/ \
+ -DBRASERO_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
+ -DBRASERO_PREFIX=\"$(prefix)\" \
+ -DBRASERO_SYSCONFDIR=\"$(sysconfdir)\" \
+ -DBRASERO_DATADIR=\"$(datadir)/brasero\" \
+ -DBRASERO_LIBDIR=\"$(libdir)\" \
+ $(DISABLE_DEPRECATED) \
+ $(BRASERO_GLIB_CFLAGS) \
+ $(BRASERO_GCONF_CFLAGS)
+
+#wodim
+wodimdir = $(libdir)/brasero/plugins
+wodim_LTLIBRARIES = libbrasero-wodim.la
+libbrasero_wodim_la_SOURCES = burn-wodim.c burn-wodim.h \
+ burn-cdrkit.h
+libbrasero_wodim_la_LIBADD = $(BRASERO_GLIB_LIBS) $(BRASERO_GCONF_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_wodim_la_LDFLAGS = -module -avoid-version
+
+#genisoimage
+genisoimagedir = $(libdir)/brasero/plugins
+genisoimage_LTLIBRARIES = libbrasero-genisoimage.la
+libbrasero_genisoimage_la_SOURCES = burn-genisoimage.c burn-genisoimage.h \
+ burn-cdrkit.h
+libbrasero_genisoimage_la_LIBADD = $(BRASERO_GLIB_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_genisoimage_la_LDFLAGS = -module -avoid-version
+
+#readom
+readomdir = $(libdir)/brasero/plugins
+readom_LTLIBRARIES = libbrasero-readom.la
+libbrasero_readom_la_SOURCES = burn-readom.c burn-readom.h \
+ burn-cdrkit.h
+libbrasero_readom_la_LIBADD = $(BRASERO_GLIB_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_readom_la_LDFLAGS = -module -avoid-version
diff --git a/plugins/cdrkit/burn-cdrkit.h b/plugins/cdrkit/burn-cdrkit.h
new file mode 100644
index 0000000..ef3e33b
--- /dev/null
+++ b/plugins/cdrkit/burn-cdrkit.h
@@ -0,0 +1,39 @@
+/***************************************************************************
+ * cdrkit.h
+ *
+ * Mon Oct 29 12:21:53 2007
+ * Copyright 2007 Philippe Rouquier
+ * <bonfire-app wanadoo fr>
+ ****************************************************************************/
+
+/*
+ * Libbrasero-media is free software; you can redistribute it and/or modify
+fy
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA
+ */
+
+#ifndef _CDRKIT_H
+#define _CDRKIT_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define CDRKIT_DESCRIPTION N_("Cdrkit burning suite")
+
+G_END_DECLS
+
+#endif /* _CDRKIT_H */
+
+
diff --git a/plugins/cdrkit/burn-genisoimage.c b/plugins/cdrkit/burn-genisoimage.c
new file mode 100644
index 0000000..7bae00e
--- /dev/null
+++ b/plugins/cdrkit/burn-genisoimage.c
@@ -0,0 +1,579 @@
+/***************************************************************************
+ * genisoimage.c
+ *
+ * dim jan 22 15:20:57 2006
+ * Copyright 2006 Rouquier Philippe
+ * bonfire-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+#include <gmodule.h>
+
+#include "burn-job.h"
+#include "burn-process.h"
+#include "brasero-plugin-registration.h"
+#include "burn-cdrkit.h"
+#include "burn-genisoimage.h"
+#include "brasero-track-data.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroGenisoimage, brasero_genisoimage, BRASERO_TYPE_PROCESS, BraseroProcess);
+
+struct _BraseroGenisoimagePrivate {
+ guint use_utf8:1;
+};
+typedef struct _BraseroGenisoimagePrivate BraseroGenisoimagePrivate;
+
+#define BRASERO_GENISOIMAGE_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_GENISOIMAGE, BraseroGenisoimagePrivate))
+static GObjectClass *parent_class = NULL;
+
+static BraseroBurnResult
+brasero_genisoimage_read_isosize (BraseroProcess *process, const gchar *line)
+{
+ gint64 sectors;
+
+ sectors = strtoll (line, NULL, 10);
+ if (!sectors)
+ return BRASERO_BURN_OK;
+
+ /* genisoimage reports blocks of 2048 bytes */
+ brasero_job_set_output_size_for_current_track (BRASERO_JOB (process),
+ sectors,
+ (gint64) sectors * 2048ULL);
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_genisoimage_read_stdout (BraseroProcess *process, const gchar *line)
+{
+ BraseroJobAction action;
+
+ brasero_job_get_action (BRASERO_JOB (process), &action);
+ if (action == BRASERO_JOB_ACTION_SIZE)
+ return brasero_genisoimage_read_isosize (process, line);
+
+ return TRUE;
+}
+
+static BraseroBurnResult
+brasero_genisoimage_read_stderr (BraseroProcess *process, const gchar *line)
+{
+ gchar fraction_str [7] = { 0, };
+ BraseroGenisoimage *genisoimage;
+ BraseroGenisoimagePrivate *priv;
+
+ genisoimage = BRASERO_GENISOIMAGE (process);
+ priv = BRASERO_GENISOIMAGE_PRIVATE (process);
+
+ if (strstr (line, "estimate finish")
+ && sscanf (line, "%6c%% done, estimate finish", fraction_str) == 1) {
+ gdouble fraction;
+
+ fraction = g_strtod (fraction_str, NULL) / (gdouble) 100.0;
+ brasero_job_set_progress (BRASERO_JOB (genisoimage), fraction);
+ brasero_job_start_progress (BRASERO_JOB (process), FALSE);
+ }
+ else if (strstr (line, "Input/output error. Read error on old image")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new_literal (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_IMAGE_LAST_SESSION,
+ _("Last session import failed")));
+ }
+ else if (strstr (line, "Unable to sort directory")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new_literal (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_WRITE_IMAGE,
+ _("An image could not be created")));
+ }
+ else if (strstr (line, "have the same joliet name")
+ || strstr (line, "Joliet tree sort failed.")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new_literal (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_IMAGE_JOLIET,
+ _("An image could not be created")));
+ }
+ else if (strstr (line, "Use genisoimage -help")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new_literal (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("This version of genisoimage is not supported")));
+ }
+/* else if ((pos = strstr (line,"genisoimage: Permission denied. "))) {
+ int res = FALSE;
+ gboolean isdir = FALSE;
+ char *path = NULL;
+
+ pos += strlen ("genisoimage: Permission denied. ");
+ if (!strncmp (pos, "Unable to open directory ", 24)) {
+ isdir = TRUE;
+
+ pos += strlen ("Unable to open directory ");
+ path = g_strdup (pos);
+ path[strlen (path) - 1] = 0;
+ }
+ else if (!strncmp (pos, "File ", 5)) {
+ char *end;
+
+ isdir = FALSE;
+ pos += strlen ("File ");
+ end = strstr (pos, " is not readable - ignoring");
+ if (end)
+ path = g_strndup (pos, end - pos);
+ }
+ else
+ return TRUE;
+
+ res = brasero_genisoimage_base_ask_unreadable_file (BRASERO_GENISOIMAGE_BASE (process),
+ path,
+ isdir);
+ if (!res) {
+ g_free (path);
+
+ brasero_job_progress_changed (BRASERO_JOB (process), 1.0, -1);
+ brasero_job_cancel (BRASERO_JOB (process), FALSE);
+ return FALSE;
+ }
+ }*/
+ else if (strstr (line, "Incorrectly encoded string")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new_literal (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_INPUT_INVALID,
+ _("Some files have invalid filenames")));
+ }
+ else if (strstr (line, "Unknown charset")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new_literal (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_INPUT_INVALID,
+ _("Unknown character encoding")));
+ }
+ else if (strstr (line, "No space left on device")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new_literal (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_DISK_SPACE,
+ _("There is no space left on the device")));
+
+ }
+ else if (strstr (line, "Unable to open disc image file")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new_literal (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_PERMISSION,
+ _("You do not have the required permission to write at this location")));
+
+ }
+ else if (strstr (line, "Value too large for defined data type")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new_literal (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_MEDIUM_SPACE,
+ _("Not enough space available on the disc")));
+ }
+
+ /** REMINDER: these should not be necessary
+
+ else if (strstr (line, "Resource temporarily unavailable")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new_literal (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_INPUT,
+ _("Data could not be written")));
+ }
+ else if (strstr (line, "Bad file descriptor.")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new_literal (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_INPUT,
+ _("Internal error: bad file descriptor")));
+ }
+
+ **/
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_genisoimage_set_argv_image (BraseroGenisoimage *genisoimage,
+ GPtrArray *argv,
+ GError **error)
+{
+ gchar *label = NULL;
+ BraseroTrack *track;
+ BraseroBurnFlag flags;
+ gchar *emptydir = NULL;
+ gchar *videodir = NULL;
+ BraseroImageFS image_fs;
+ BraseroBurnResult result;
+ BraseroJobAction action;
+ gchar *grafts_path = NULL;
+ gchar *excluded_path = NULL;
+
+ /* set argv */
+ g_ptr_array_add (argv, g_strdup ("-r"));
+
+ result = brasero_job_get_current_track (BRASERO_JOB (genisoimage), &track);
+ if (result != BRASERO_BURN_OK)
+ BRASERO_JOB_NOT_READY (genisoimage);
+
+ image_fs = brasero_track_data_get_fs (BRASERO_TRACK_DATA (track));
+ if (image_fs & BRASERO_IMAGE_FS_JOLIET)
+ g_ptr_array_add (argv, g_strdup ("-J"));
+
+ if ((image_fs & BRASERO_IMAGE_FS_ISO)
+ && (image_fs & BRASERO_IMAGE_ISO_FS_LEVEL_3)) {
+ g_ptr_array_add (argv, g_strdup ("-iso-level"));
+ g_ptr_array_add (argv, g_strdup ("3"));
+
+ /* NOTE: the following is specific to genisoimage
+ * It allows to burn files over 4 GiB */
+ g_ptr_array_add (argv, g_strdup ("-allow-limited-size"));
+ }
+
+ if (image_fs & BRASERO_IMAGE_FS_UDF)
+ g_ptr_array_add (argv, g_strdup ("-udf"));
+
+ if (image_fs & BRASERO_IMAGE_FS_VIDEO) {
+ g_ptr_array_add (argv, g_strdup ("-dvd-video"));
+
+ result = brasero_job_get_tmp_dir (BRASERO_JOB (genisoimage),
+ &videodir,
+ error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+ }
+
+ g_ptr_array_add (argv, g_strdup ("-graft-points"));
+
+ if (image_fs & BRASERO_IMAGE_ISO_FS_DEEP_DIRECTORY)
+ g_ptr_array_add (argv, g_strdup ("-D")); // This is dangerous the manual says but apparently it works well
+
+ result = brasero_job_get_tmp_file (BRASERO_JOB (genisoimage),
+ NULL,
+ &grafts_path,
+ error);
+ if (result != BRASERO_BURN_OK) {
+ g_free (videodir);
+ return result;
+ }
+
+ result = brasero_job_get_tmp_file (BRASERO_JOB (genisoimage),
+ NULL,
+ &excluded_path,
+ error);
+ if (result != BRASERO_BURN_OK) {
+ g_free (videodir);
+ g_free (grafts_path);
+ return result;
+ }
+
+ result = brasero_job_get_tmp_dir (BRASERO_JOB (genisoimage),
+ &emptydir,
+ error);
+ if (result != BRASERO_BURN_OK) {
+ g_free (videodir);
+ g_free (grafts_path);
+ g_free (excluded_path);
+ return result;
+ }
+
+ result = brasero_track_data_get_paths (BRASERO_TRACK_DATA (track),
+ (image_fs & BRASERO_IMAGE_FS_JOLIET) != 0,
+ grafts_path,
+ excluded_path,
+ emptydir,
+ videodir,
+ error);
+ g_free (emptydir);
+
+ if (result != BRASERO_BURN_OK) {
+ g_free (videodir);
+ g_free (grafts_path);
+ g_free (excluded_path);
+ return result;
+ }
+
+ g_ptr_array_add (argv, g_strdup ("-path-list"));
+ g_ptr_array_add (argv, grafts_path);
+
+ g_ptr_array_add (argv, g_strdup ("-exclude-list"));
+ g_ptr_array_add (argv, excluded_path);
+
+ brasero_job_get_data_label (BRASERO_JOB (genisoimage), &label);
+ if (label) {
+ g_ptr_array_add (argv, g_strdup ("-V"));
+ g_ptr_array_add (argv, label);
+ }
+
+ g_ptr_array_add (argv, g_strdup ("-A"));
+ g_ptr_array_add (argv, g_strdup_printf ("Brasero-%i.%i.%i",
+ BRASERO_MAJOR_VERSION,
+ BRASERO_MINOR_VERSION,
+ BRASERO_SUB));
+
+ g_ptr_array_add (argv, g_strdup ("-sysid"));
+ g_ptr_array_add (argv, g_strdup ("LINUX"));
+
+ /* FIXME! -sort is an interesting option allowing to decide where the
+ * files are written on the disc and therefore to optimize later reading */
+ /* FIXME: -hidden --hidden-list -hide-jolie -hide-joliet-list will allow to hide
+ * some files when we will display the contents of a disc we will want to merge */
+ /* FIXME: support preparer publisher options */
+
+ brasero_job_get_flags (BRASERO_JOB (genisoimage), &flags);
+ if (flags & (BRASERO_BURN_FLAG_APPEND|BRASERO_BURN_FLAG_MERGE)) {
+ guint64 last_session = 0, next_wr_add = 0;
+ gchar *startpoint = NULL;
+
+ brasero_job_get_last_session_address (BRASERO_JOB (genisoimage), &last_session);
+ brasero_job_get_next_writable_address (BRASERO_JOB (genisoimage), &next_wr_add);
+ if (last_session == -1 || next_wr_add == -1) {
+ g_free (videodir);
+ BRASERO_JOB_LOG (genisoimage, "Failed to get the start point of the track. Make sure the media allow to add files (it is not closed)");
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("An internal error occured"));
+ return BRASERO_BURN_ERR;
+ }
+
+ startpoint = g_strdup_printf ("%"G_GINT64_FORMAT",%"G_GINT64_FORMAT,
+ last_session,
+ next_wr_add);
+
+ g_ptr_array_add (argv, g_strdup ("-C"));
+ g_ptr_array_add (argv, startpoint);
+
+ if (flags & BRASERO_BURN_FLAG_MERGE) {
+ gchar *device = NULL;
+
+ g_ptr_array_add (argv, g_strdup ("-M"));
+
+ brasero_job_get_device (BRASERO_JOB (genisoimage), &device);
+ g_ptr_array_add (argv, device);
+ }
+ }
+
+ brasero_job_get_action (BRASERO_JOB (genisoimage), &action);
+ if (action == BRASERO_JOB_ACTION_SIZE) {
+ g_ptr_array_add (argv, g_strdup ("-quiet"));
+ g_ptr_array_add (argv, g_strdup ("-print-size"));
+
+ brasero_job_set_current_action (BRASERO_JOB (genisoimage),
+ BRASERO_BURN_ACTION_GETTING_SIZE,
+ NULL,
+ FALSE);
+ brasero_job_start_progress (BRASERO_JOB (genisoimage), FALSE);
+
+ if (videodir) {
+ g_ptr_array_add (argv, g_strdup ("-f"));
+ g_ptr_array_add (argv, videodir);
+ }
+
+ return BRASERO_BURN_OK;
+ }
+
+ if (brasero_job_get_fd_out (BRASERO_JOB (genisoimage), NULL) != BRASERO_BURN_OK) {
+ gchar *output = NULL;
+
+ result = brasero_job_get_image_output (BRASERO_JOB (genisoimage),
+ &output,
+ NULL);
+ if (result != BRASERO_BURN_OK) {
+ g_free (videodir);
+ return result;
+ }
+
+ g_ptr_array_add (argv, g_strdup ("-o"));
+ g_ptr_array_add (argv, output);
+ }
+
+ if (videodir) {
+ g_ptr_array_add (argv, g_strdup ("-f"));
+ g_ptr_array_add (argv, videodir);
+ }
+
+ brasero_job_set_current_action (BRASERO_JOB (genisoimage),
+ BRASERO_BURN_ACTION_CREATING_IMAGE,
+ NULL,
+ FALSE);
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_genisoimage_set_argv (BraseroProcess *process,
+ GPtrArray *argv,
+ GError **error)
+{
+ BraseroGenisoimagePrivate *priv;
+ BraseroGenisoimage *genisoimage;
+ BraseroBurnResult result;
+ BraseroJobAction action;
+ gchar *prog_name;
+
+ genisoimage = BRASERO_GENISOIMAGE (process);
+ priv = BRASERO_GENISOIMAGE_PRIVATE (process);
+
+ prog_name = g_find_program_in_path ("genisoimage");
+ if (prog_name && g_file_test (prog_name, G_FILE_TEST_IS_EXECUTABLE))
+ g_ptr_array_add (argv, prog_name);
+ else
+ g_ptr_array_add (argv, g_strdup ("genisoimage"));
+
+ if (priv->use_utf8) {
+ g_ptr_array_add (argv, g_strdup ("-input-charset"));
+ g_ptr_array_add (argv, g_strdup ("utf8"));
+ }
+
+ brasero_job_get_action (BRASERO_JOB (genisoimage), &action);
+ if (action == BRASERO_JOB_ACTION_SIZE)
+ result = brasero_genisoimage_set_argv_image (genisoimage, argv, error);
+ else if (action == BRASERO_JOB_ACTION_IMAGE)
+ result = brasero_genisoimage_set_argv_image (genisoimage, argv, error);
+ else
+ BRASERO_JOB_NOT_SUPPORTED (genisoimage);
+
+ return result;
+}
+
+static void
+brasero_genisoimage_class_init (BraseroGenisoimageClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ BraseroProcessClass *process_class = BRASERO_PROCESS_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (BraseroGenisoimagePrivate));
+
+ parent_class = g_type_class_peek_parent(klass);
+ object_class->finalize = brasero_genisoimage_finalize;
+
+ process_class->stdout_func = brasero_genisoimage_read_stdout;
+ process_class->stderr_func = brasero_genisoimage_read_stderr;
+ process_class->set_argv = brasero_genisoimage_set_argv;
+}
+
+static void
+brasero_genisoimage_init (BraseroGenisoimage *obj)
+{
+ BraseroGenisoimagePrivate *priv;
+ gchar *standard_error;
+ gboolean res;
+
+ priv = BRASERO_GENISOIMAGE_PRIVATE (obj);
+
+ /* this code used to be ncb_genisoimage_supports_utf8 */
+ res = g_spawn_command_line_sync ("genisoimage -input-charset utf8",
+ NULL,
+ &standard_error,
+ NULL,
+ NULL);
+
+ if (res && !g_strrstr (standard_error, "Unknown charset"))
+ priv->use_utf8 = TRUE;
+ else
+ priv->use_utf8 = FALSE;
+
+ g_free (standard_error);
+}
+
+static void
+brasero_genisoimage_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static BraseroBurnResult
+brasero_genisoimage_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+ BraseroBurnResult result;
+ GSList *output;
+ GSList *input;
+
+ brasero_plugin_define (plugin,
+ "genisoimage",
+ _("Use genisoimage to create images from a file selection"),
+ "Philippe Rouquier",
+ 1);
+
+ /* First see if this plugin can be used */
+ result = brasero_process_check_path ("genisoimage", error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+
+ brasero_plugin_set_flags (plugin,
+ BRASERO_MEDIUM_CDR|
+ BRASERO_MEDIUM_CDRW|
+ BRASERO_MEDIUM_DVDR|
+ BRASERO_MEDIUM_DVDRW|
+ BRASERO_MEDIUM_DUAL_L|
+ BRASERO_MEDIUM_DVDR_PLUS|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_HAS_AUDIO|
+ BRASERO_MEDIUM_HAS_DATA,
+ BRASERO_BURN_FLAG_APPEND|
+ BRASERO_BURN_FLAG_MERGE,
+ BRASERO_BURN_FLAG_NONE);
+
+ brasero_plugin_set_flags (plugin,
+ BRASERO_MEDIUM_DUAL_L|
+ BRASERO_MEDIUM_DVDRW_PLUS|
+ BRASERO_MEDIUM_RESTRICTED|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_CLOSED|
+ BRASERO_MEDIUM_HAS_DATA,
+ BRASERO_BURN_FLAG_APPEND|
+ BRASERO_BURN_FLAG_MERGE,
+ BRASERO_BURN_FLAG_NONE);
+
+ /* Caps */
+ output = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE|
+ BRASERO_PLUGIN_IO_ACCEPT_PIPE,
+ BRASERO_IMAGE_FORMAT_BIN);
+
+ input = brasero_caps_data_new (BRASERO_IMAGE_FS_ISO|
+ BRASERO_IMAGE_FS_UDF|
+ BRASERO_IMAGE_ISO_FS_LEVEL_3|
+ BRASERO_IMAGE_ISO_FS_DEEP_DIRECTORY|
+ BRASERO_IMAGE_FS_JOLIET|
+ BRASERO_IMAGE_FS_VIDEO);
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (input);
+
+ input = brasero_caps_data_new (BRASERO_IMAGE_FS_ISO|
+ BRASERO_IMAGE_ISO_FS_LEVEL_3|
+ BRASERO_IMAGE_ISO_FS_DEEP_DIRECTORY|
+ BRASERO_IMAGE_FS_SYMLINK);
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (input);
+
+ g_slist_free (output);
+
+ brasero_plugin_register_group (plugin, _(CDRKIT_DESCRIPTION));
+
+ return BRASERO_BURN_OK;
+}
diff --git a/plugins/cdrkit/burn-genisoimage.h b/plugins/cdrkit/burn-genisoimage.h
new file mode 100644
index 0000000..ed8c1b4
--- /dev/null
+++ b/plugins/cdrkit/burn-genisoimage.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+ * genisoimage.h
+ *
+ * dim jan 22 15:20:57 2006
+ * Copyright 2006 Rouquier Philippe
+ * brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef GENISOIMAGE_H
+#define GENISOIMAGE_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "burn-process.h"
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_GENISOIMAGE (brasero_genisoimage_get_type ())
+#define BRASERO_GENISOIMAGE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_GENISOIMAGE, BraseroGenisoimage))
+#define BRASERO_GENISOIMAGE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_GENISOIMAGE, BraseroGenisoimageClass))
+#define BRASERO_IS_GENISOIMAGE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_GENISOIMAGE))
+#define BRASERO_IS_GENISOIMAGE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_GENISOIMAGE))
+#define BRASERO_GENISOIMAGE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_GENISOIMAGE, BraseroGenisoimageClass))
+
+G_END_DECLS
+
+#endif /* GENISOIMAGE_H */
diff --git a/plugins/cdrkit/burn-readom.c b/plugins/cdrkit/burn-readom.c
new file mode 100644
index 0000000..60677e8
--- /dev/null
+++ b/plugins/cdrkit/burn-readom.c
@@ -0,0 +1,484 @@
+/***************************************************************************
+ * readom.c
+ *
+ * dim jan 22 18:06:10 2006
+ * Copyright 2006 Rouquier Philippe
+ * brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+#include <gmodule.h>
+
+#include "burn-cdrkit.h"
+#include "burn-readom.h"
+#include "burn-process.h"
+#include "burn-job.h"
+#include "brasero-plugin-registration.h"
+#include "brasero-tags.h"
+#include "brasero-track-disc.h"
+
+#include "burn-volume.h"
+#include "brasero-drive.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroReadom, brasero_readom, BRASERO_TYPE_PROCESS, BraseroProcess);
+static GObjectClass *parent_class = NULL;
+
+static BraseroBurnResult
+brasero_readom_read_stderr (BraseroProcess *process, const gchar *line)
+{
+ BraseroReadom *readom;
+ gint dummy1;
+ gint dummy2;
+ gchar *pos;
+
+ readom = BRASERO_READOM (process);
+
+ if ((pos = strstr (line, "addr:"))) {
+ gint sector;
+ gint64 written;
+ BraseroTrackType *output = NULL;
+
+ pos += strlen ("addr:");
+ sector = strtoll (pos, NULL, 10);
+
+ output = brasero_track_type_new ();
+ brasero_job_get_output_type (BRASERO_JOB (readom), output);
+
+ if (brasero_track_type_get_image_format (output) == BRASERO_IMAGE_FORMAT_BIN)
+ written = (gint64) ((gint64) sector * 2048ULL);
+ else if (brasero_track_type_get_image_format (output) == BRASERO_IMAGE_FORMAT_CLONE)
+ written = (gint64) ((gint64) sector * 2448ULL);
+ else
+ written = (gint64) ((gint64) sector * 2048ULL);
+
+ brasero_job_set_written_track (BRASERO_JOB (readom), written);
+
+ if (sector > 10)
+ brasero_job_start_progress (BRASERO_JOB (readom), FALSE);
+
+ brasero_track_type_free (output);
+ }
+ else if ((pos = strstr (line, "Capacity:"))) {
+ brasero_job_set_current_action (BRASERO_JOB (readom),
+ BRASERO_BURN_ACTION_DRIVE_COPY,
+ NULL,
+ FALSE);
+ }
+ else if (strstr (line, "Device not ready.")) {
+ brasero_job_error (BRASERO_JOB (readom),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_DRIVE_BUSY,
+ _("The drive is busy")));
+ }
+ else if (strstr (line, "Cannot open SCSI driver.")) {
+ brasero_job_error (BRASERO_JOB (readom),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_PERMISSION,
+ _("You do not have the required permissions to use this drive")));
+ }
+ else if (strstr (line, "Cannot send SCSI cmd via ioctl")) {
+ brasero_job_error (BRASERO_JOB (readom),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_PERMISSION,
+ _("You do not have the required permissions to use this drive")));
+ }
+ /* we scan for this error as in this case readcd returns success */
+ else if (sscanf (line, "Input/output error. Error on sector %d not corrected. Total of %d error", &dummy1, &dummy2) == 2) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("An internal error occured")));
+ }
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_readom_argv_set_iso_boundary (BraseroReadom *readom,
+ GPtrArray *argv,
+ GError **error)
+{
+ guint64 nb_blocks;
+ BraseroTrack *track;
+ GValue *value = NULL;
+ BraseroTrackType *output = NULL;
+
+ brasero_job_get_current_track (BRASERO_JOB (readom), &track);
+
+ output = brasero_track_type_new ();
+ brasero_job_get_output_type (BRASERO_JOB (readom), output);
+
+ brasero_track_tag_lookup (track,
+ BRASERO_TRACK_MEDIUM_ADDRESS_START_TAG,
+ &value);
+ if (value) {
+ guint64 start, end;
+
+ /* we were given an address to start */
+ start = g_value_get_uint64 (value);
+
+ /* get the length now */
+ value = NULL;
+ brasero_track_tag_lookup (track,
+ BRASERO_TRACK_MEDIUM_ADDRESS_END_TAG,
+ &value);
+
+ end = g_value_get_uint64 (value);
+
+ BRASERO_JOB_LOG (readom,
+ "reading from sector %lli to %lli",
+ start,
+ end);
+ g_ptr_array_add (argv, g_strdup_printf ("-sectors=%lli-%lli",
+ start,
+ end));
+ }
+ /* 0 means all disc, -1 problem */
+ else if (brasero_track_disc_get_track_num (BRASERO_TRACK_DISC (track)) > 0) {
+ guint64 start;
+ BraseroDrive *drive;
+ BraseroMedium *medium;
+
+ drive = brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track));
+ medium = brasero_drive_get_medium (drive);
+ brasero_medium_get_track_space (medium,
+ brasero_track_disc_get_track_num (BRASERO_TRACK_DISC (track)),
+ NULL,
+ &nb_blocks);
+ brasero_medium_get_track_address (medium,
+ brasero_track_disc_get_track_num (BRASERO_TRACK_DISC (track)),
+ NULL,
+ &start);
+
+ BRASERO_JOB_LOG (readom,
+ "reading %i from sector %lli to %lli",
+ brasero_track_disc_get_track_num (BRASERO_TRACK_DISC (track)),
+ start,
+ start + nb_blocks);
+ g_ptr_array_add (argv, g_strdup_printf ("-sectors=%lli-%lli",
+ start,
+ start + nb_blocks));
+ }
+ /* if it's BIN output just read the last track */
+ else if (brasero_track_type_get_image_format (output) == BRASERO_IMAGE_FORMAT_BIN) {
+ guint64 start;
+ BraseroDrive *drive;
+ BraseroMedium *medium;
+
+ drive = brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track));
+ medium = brasero_drive_get_medium (drive);
+ brasero_medium_get_last_data_track_space (medium,
+ NULL,
+ &nb_blocks);
+ brasero_medium_get_last_data_track_address (medium,
+ NULL,
+ &start);
+ BRASERO_JOB_LOG (readom,
+ "reading last track from sector %lli to %lli",
+ start,
+ start + nb_blocks);
+ g_ptr_array_add (argv, g_strdup_printf ("-sectors=%lli-%lli",
+ start,
+ start + nb_blocks));
+ }
+ else {
+ brasero_track_get_size (track, &nb_blocks, NULL);
+ g_ptr_array_add (argv, g_strdup_printf ("-sectors=0-%lli", nb_blocks));
+ }
+
+ brasero_track_type_free (output);
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_readom_get_size (BraseroReadom *self,
+ GError **error)
+{
+ guint64 blocks;
+ GValue *value = NULL;
+ BraseroTrack *track = NULL;
+ BraseroTrackType *output = NULL;
+
+ brasero_job_get_current_track (BRASERO_JOB (self), &track);
+
+ output = brasero_track_type_new ();
+ brasero_job_get_output_type (BRASERO_JOB (self), output);
+
+ if (!brasero_track_type_get_has_image (output)) {
+ brasero_track_type_free (output);
+ return BRASERO_BURN_ERR;
+ }
+
+ brasero_track_tag_lookup (track,
+ BRASERO_TRACK_MEDIUM_ADDRESS_START_TAG,
+ &value);
+ if (value) {
+ guint64 start, end;
+
+ /* we were given an address to start */
+ start = g_value_get_uint64 (value);
+
+ /* get the length now */
+ value = NULL;
+ brasero_track_tag_lookup (track,
+ BRASERO_TRACK_MEDIUM_ADDRESS_END_TAG,
+ &value);
+
+ end = g_value_get_uint64 (value);
+ blocks = end - start;
+ }
+ else if (brasero_track_disc_get_track_num (BRASERO_TRACK_DISC (track)) > 0) {
+ BraseroDrive *drive;
+ BraseroMedium *medium;
+
+ drive = brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track));
+ medium = brasero_drive_get_medium (drive);
+ brasero_medium_get_track_space (medium,
+ brasero_track_disc_get_track_num (BRASERO_TRACK_DISC (track)),
+ NULL,
+ &blocks);
+ }
+ else if (brasero_track_type_get_image_format (output) == BRASERO_IMAGE_FORMAT_BIN) {
+ BraseroDrive *drive;
+ BraseroMedium *medium;
+
+ drive = brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track));
+ medium = brasero_drive_get_medium (drive);
+ brasero_medium_get_last_data_track_space (medium,
+ NULL,
+ &blocks);
+ }
+ else
+ brasero_track_get_size (track, &blocks, NULL);
+
+ if (brasero_track_type_get_image_format (output) == BRASERO_IMAGE_FORMAT_BIN) {
+ brasero_job_set_output_size_for_current_track (BRASERO_JOB (self),
+ blocks,
+ blocks * 2048ULL);
+ }
+ else if (brasero_track_type_get_image_format (output) == BRASERO_IMAGE_FORMAT_CLONE) {
+ brasero_job_set_output_size_for_current_track (BRASERO_JOB (self),
+ blocks,
+ blocks * 2448ULL);
+ }
+ else {
+ brasero_track_type_free (output);
+ return BRASERO_BURN_NOT_SUPPORTED;
+ }
+
+ brasero_track_type_free (output);
+
+ /* no need to go any further */
+ return BRASERO_BURN_NOT_RUNNING;
+}
+
+static BraseroBurnResult
+brasero_readom_set_argv (BraseroProcess *process,
+ GPtrArray *argv,
+ GError **error)
+{
+ BraseroBurnResult result = FALSE;
+ BraseroTrackType *output = NULL;
+ BraseroImageFormat format;
+ BraseroJobAction action;
+ BraseroReadom *readom;
+ BraseroMedium *medium;
+ BraseroDrive *drive;
+ BraseroTrack *track;
+ BraseroMedia media;
+ gchar *outfile_arg;
+ gchar *dev_str;
+
+ readom = BRASERO_READOM (process);
+
+ /* This is a kind of shortcut */
+ brasero_job_get_action (BRASERO_JOB (process), &action);
+ if (action == BRASERO_JOB_ACTION_SIZE)
+ return brasero_readom_get_size (readom, error);
+
+ g_ptr_array_add (argv, g_strdup ("readom"));
+
+ brasero_job_get_current_track (BRASERO_JOB (readom), &track);
+ drive = brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track));
+ if (!brasero_drive_get_device (drive))
+ return BRASERO_BURN_ERR;
+
+ dev_str = g_strdup_printf ("dev=%s", brasero_drive_get_device (drive));
+ g_ptr_array_add (argv, dev_str);
+
+ g_ptr_array_add (argv, g_strdup ("-nocorr"));
+
+ medium = brasero_drive_get_medium (drive);
+ media = brasero_medium_get_status (medium);
+
+ output = brasero_track_type_new ();
+ brasero_job_get_output_type (BRASERO_JOB (readom), output);
+ format = brasero_track_type_get_image_format (output);
+ brasero_track_type_free (output);
+
+ if ((media & BRASERO_MEDIUM_DVD)
+ && format != BRASERO_IMAGE_FORMAT_BIN) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("An internal error occured"));
+ return BRASERO_BURN_ERR;
+ }
+
+ if (format == BRASERO_IMAGE_FORMAT_CLONE) {
+ /* NOTE: with this option the sector size is 2448
+ * because it is raw96 (2352+96) otherwise it is 2048 */
+ g_ptr_array_add (argv, g_strdup ("-clone"));
+ }
+ else if (format == BRASERO_IMAGE_FORMAT_BIN) {
+ g_ptr_array_add (argv, g_strdup ("-noerror"));
+
+ /* don't do it for clone since we need the entire disc */
+ result = brasero_readom_argv_set_iso_boundary (readom, argv, error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+ }
+ else
+ BRASERO_JOB_NOT_SUPPORTED (readom);
+
+ if (brasero_job_get_fd_out (BRASERO_JOB (readom), NULL) != BRASERO_BURN_OK) {
+ gchar *image;
+
+ if (format != BRASERO_IMAGE_FORMAT_CLONE
+ && format != BRASERO_IMAGE_FORMAT_BIN)
+ BRASERO_JOB_NOT_SUPPORTED (readom);
+
+ result = brasero_job_get_image_output (BRASERO_JOB (readom),
+ &image,
+ NULL);
+ if (result != BRASERO_BURN_OK)
+ return result;
+
+ outfile_arg = g_strdup_printf ("-f=%s", image);
+ g_ptr_array_add (argv, outfile_arg);
+ g_free (image);
+ }
+ else if (format == BRASERO_IMAGE_FORMAT_BIN) {
+ outfile_arg = g_strdup ("-f=-");
+ g_ptr_array_add (argv, outfile_arg);
+ }
+ else /* unfortunately raw images can't be piped out */
+ BRASERO_JOB_NOT_SUPPORTED (readom);
+
+ brasero_job_set_use_average_rate (BRASERO_JOB (process), TRUE);
+ return BRASERO_BURN_OK;
+}
+
+static void
+brasero_readom_class_init (BraseroReadomClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ BraseroProcessClass *process_class = BRASERO_PROCESS_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+ object_class->finalize = brasero_readom_finalize;
+
+ process_class->stderr_func = brasero_readom_read_stderr;
+ process_class->set_argv = brasero_readom_set_argv;
+}
+
+static void
+brasero_readom_init (BraseroReadom *obj)
+{ }
+
+static void
+brasero_readom_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static BraseroBurnResult
+brasero_readom_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+ BraseroBurnResult result;
+ GSList *output;
+ GSList *input;
+
+ brasero_plugin_define (plugin,
+ "readom",
+ _("Use readom to create disc images"),
+ "Philippe Rouquier",
+ 1);
+
+ /* First see if this plugin can be used */
+ result = brasero_process_check_path ("readom", error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+
+ /* that's for clone mode only The only one to copy audio */
+ output = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_IMAGE_FORMAT_CLONE);
+
+ input = brasero_caps_disc_new (BRASERO_MEDIUM_CD|
+ BRASERO_MEDIUM_ROM|
+ BRASERO_MEDIUM_WRITABLE|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_CLOSED|
+ BRASERO_MEDIUM_HAS_AUDIO|
+ BRASERO_MEDIUM_HAS_DATA);
+
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (output);
+ g_slist_free (input);
+
+ /* that's for regular mode: it accepts the previous type of discs
+ * plus the DVDs types as well */
+ output = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE|
+ BRASERO_PLUGIN_IO_ACCEPT_PIPE,
+ BRASERO_IMAGE_FORMAT_BIN);
+
+ input = brasero_caps_disc_new (BRASERO_MEDIUM_CD|
+ BRASERO_MEDIUM_DVD|
+ BRASERO_MEDIUM_DUAL_L|
+ BRASERO_MEDIUM_PLUS|
+ BRASERO_MEDIUM_SEQUENTIAL|
+ BRASERO_MEDIUM_RESTRICTED|
+ BRASERO_MEDIUM_ROM|
+ BRASERO_MEDIUM_WRITABLE|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_CLOSED|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_HAS_DATA);
+
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (output);
+ g_slist_free (input);
+
+ brasero_plugin_register_group (plugin, _(CDRKIT_DESCRIPTION));
+
+ return BRASERO_BURN_OK;
+}
diff --git a/plugins/cdrkit/burn-readom.h b/plugins/cdrkit/burn-readom.h
new file mode 100644
index 0000000..6372ed8
--- /dev/null
+++ b/plugins/cdrkit/burn-readom.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+ * readom.h
+ *
+ * dim jan 22 18:06:10 2006
+ * Copyright 2006 Rouquier Philippe
+ * brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef READOM_H
+#define READOM_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "burn-process.h"
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_READOM (brasero_readom_get_type ())
+#define BRASERO_READOM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_READOM, BraseroReadom))
+#define BRASERO_READOM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_READOM, BraseroReadomClass))
+#define BRASERO_IS_READOM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_READOM))
+#define BRASERO_IS_READOM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_READOM))
+#define BRASERO_READOM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_READOM, BraseroReadomClass))
+
+G_END_DECLS
+
+#endif /* READOM_H */
diff --git a/plugins/cdrkit/burn-wodim.c b/plugins/cdrkit/burn-wodim.c
new file mode 100644
index 0000000..3f0086f
--- /dev/null
+++ b/plugins/cdrkit/burn-wodim.c
@@ -0,0 +1,1380 @@
+/***************************************************************************
+ * wodim.c
+ *
+ * dim jan 22 15:22:52 2006
+ * Copyright 2006 Rouquier Philippe
+ * brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+#include <math.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+#include <gmodule.h>
+
+#include <gconf/gconf-client.h>
+
+#include "brasero-units.h"
+
+#include "burn-job.h"
+#include "burn-process.h"
+#include "brasero-plugin-registration.h"
+#include "burn-cdrkit.h"
+#include "burn-wodim.h"
+
+#include "brasero-tags.h"
+#include "brasero-track-image.h"
+#include "brasero-track-stream.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroWodim, brasero_wodim, BRASERO_TYPE_PROCESS, BraseroProcess);
+
+struct _BraseroWodimPrivate {
+ gint64 current_track_end_pos;
+ gint64 current_track_written;
+
+ gint current_track_num;
+ gint track_count;
+
+ gint minbuf;
+
+ GSList *infs;
+
+ guint immediate:1;
+};
+typedef struct _BraseroWodimPrivate BraseroWodimPrivate;
+#define BRASERO_WODIM_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_WODIM, BraseroWodimPrivate))
+
+static GObjectClass *parent_class = NULL;
+
+#define GCONF_KEY_IMMEDIATE_FLAG "/apps/brasero/config/immed_flag"
+#define GCONF_KEY_MINBUF_VALUE "/apps/brasero/config/minbuf_value"
+
+static BraseroBurnResult
+brasero_wodim_stderr_read (BraseroProcess *process, const gchar *line)
+{
+ BraseroBurnFlag flags;
+
+ brasero_job_get_flags (BRASERO_JOB (process), &flags);
+
+ if (strstr (line, "Cannot open SCSI driver.")
+ || strstr (line, "Operation not permitted. Cannot send SCSI cmd via ioctl")
+ || strstr (line, "Cannot open or use SCSI driver")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_PERMISSION,
+ _("You do not have the required permissions to use this drive")));
+ }
+ else if (!(flags & BRASERO_BURN_FLAG_OVERBURN)
+ && strstr (line, "Data may not fit on current disk")) {
+ /* we don't error out if overburn was chosen */
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_MEDIUM_SPACE,
+ _("Not enough space available on the disc")));
+ }
+ else if (strstr (line ,"cdrecord: A write error occured")
+ || strstr (line, "Could not write Lead-in")
+ || strstr (line, "Cannot fixate disk")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_WRITE_MEDIUM,
+ _("An error occured while writing to disc")));
+ }
+ else if (strstr (line, "DMA speed too slow") != NULL) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_SLOW_DMA,
+ _("The system is too slow to write the disc at this speed. Try a lower speed")));
+ }
+ else if (strstr (line, "Device or resource busy")) {
+ if (!strstr (line, "retrying in")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_DRIVE_BUSY,
+ _("The drive is busy")));
+ }
+ }
+ else if (strstr (line, "Illegal write mode for this drive")) {
+ /* NOTE : when it happened I had to unlock the
+ * drive with cdrdao and eject it. Should we ? */
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_DRIVE_BUSY,
+ _("The drive is busy")));
+ }
+
+ /* REMINDER: these should not be necessary as we checked that already */
+ /**
+ else if (strstr (line, "cannot write medium - incompatible format") != NULL) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_INPUT_INVALID,
+ _("The image does not seem to be a proper iso9660 file system")));
+ }
+ else if (strstr (line, "This means that we are checking recorded media.") != NULL) {
+ **/ /* NOTE: defer the consequence of this error as it is not always
+ * fatal. So send a warning but don't stop the process. */
+ /** brasero_process_deferred_error (process,
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_MEDIUM_INVALID,
+ _("The disc is already burnt")));
+ }
+ else if (strstr (line, "Cannot blank disk, aborting.") != NULL) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_MEDIUM_INVALID,
+ _("The disc could not be blanked")));
+ }
+ else if (strstr (line, "Bad audio track size")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("The audio tracks are too short or not a multiple of 2352")));
+ }
+ else if (strstr (line, "cdrecord: No such file or directory. Cannot open")
+ || strstr (line, "No tracks specified. Need at least one.")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_INPUT,
+ _("The image file cannot be found")));
+ }
+ else if (strstr (line, "Inappropriate audio coding")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_INPUT_INVALID,
+ _("All audio files must be stereo, 16-bit digital audio with 44100Hz samples")));
+ }
+ else if (strstr (line, "No disk / Wrong disk!") != NULL) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_MEDIA_NONE,
+ _("There seems to be no disc in the drive")));
+ }
+
+ **/
+
+ /** For these we'd rather have a message saying "cdrecord failed"
+ * as an internal error occured says nothing/even less
+ else if (strstr (line, "Bad file descriptor. read error on input file")
+ || strstr (line, "Input buffer error, aborting")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("An internal error occured")));
+ }
+
+ **/
+
+ return BRASERO_BURN_OK;
+}
+
+static void
+brasero_wodim_compute (BraseroWodim *wodim,
+ gint mb_written,
+ gint mb_total,
+ gint track_num)
+{
+ gboolean track_num_changed = FALSE;
+ BraseroWodimPrivate *priv;
+ BraseroJobAction action;
+ gint64 this_remain;
+ gint64 bytes;
+ gint64 total;
+
+ priv = BRASERO_WODIM_PRIVATE (wodim);
+ if (mb_total <= 0)
+ return;
+
+ total = mb_total * 1048576;
+
+ if (track_num > priv->current_track_num) {
+ track_num_changed = TRUE;
+ priv->current_track_num = track_num;
+ priv->current_track_end_pos += mb_total * 1048576;
+ }
+
+ this_remain = (mb_total - mb_written) * 1048576;
+ bytes = (total - priv->current_track_end_pos) + this_remain;
+ brasero_job_set_written_session (BRASERO_JOB (wodim), total - bytes);
+
+ brasero_job_get_action (BRASERO_JOB (wodim), &action);
+ if (action == BRASERO_JOB_ACTION_RECORD) {
+ gchar *action_string;
+
+ action_string = g_strdup_printf ("Writing track %02i", track_num);
+ brasero_job_set_current_action (BRASERO_JOB (wodim),
+ BRASERO_BURN_ACTION_RECORDING,
+ action_string,
+ track_num_changed);
+ g_free (action_string);
+ }
+ else if (action == BRASERO_JOB_ACTION_ERASE) {
+ brasero_job_set_progress (BRASERO_JOB (wodim), (gfloat) mb_written / (gfloat) mb_total);
+ brasero_job_set_current_action (BRASERO_JOB (wodim),
+ BRASERO_BURN_ACTION_BLANKING,
+ NULL,
+ FALSE);
+ }
+}
+
+static BraseroBurnResult
+brasero_wodim_stdout_read (BraseroProcess *process, const gchar *line)
+{
+ guint track;
+ guint speed_1, speed_2;
+ BraseroWodim *wodim;
+ BraseroWodimPrivate *priv;
+ int mb_written = 0, mb_total = 0, fifo = 0, buf = 0;
+
+ wodim = BRASERO_WODIM (process);
+ priv = BRASERO_WODIM_PRIVATE (wodim);
+
+ if (sscanf (line, "Track %2u: %d of %d MB written (fifo %d%%) [buf %d%%] %d.%dx.",
+ &track, &mb_written, &mb_total, &fifo, &buf, &speed_1, &speed_2) == 7) {
+ gdouble current_rate;
+
+ current_rate = (gdouble) ((gdouble) speed_1 +
+ (gdouble) speed_2 / 10.0) *
+ (gdouble) CD_RATE;
+ brasero_job_set_rate (BRASERO_JOB (wodim), current_rate);
+
+ priv->current_track_written = mb_written * 1048576;
+ brasero_wodim_compute (wodim,
+ mb_written,
+ mb_total,
+ track);
+
+ brasero_job_start_progress (BRASERO_JOB (wodim), FALSE);
+ }
+ else if (sscanf (line, "Track %2u: %d MB written (fifo %d%%) [buf %d%%] %d.%dx.",
+ &track, &mb_written, &fifo, &buf, &speed_1, &speed_2) == 6) {
+ gdouble current_rate;
+
+ /* this line is printed when wodim writes on the fly */
+ current_rate = (gdouble) ((gdouble) speed_1 +
+ (gdouble) speed_2 / 10.0) *
+ (gdouble) CD_RATE;
+ brasero_job_set_rate (BRASERO_JOB (wodim), current_rate);
+
+ priv->current_track_written = mb_written * 1048576;
+ if (brasero_job_get_fd_in (BRASERO_JOB (wodim), NULL) == BRASERO_BURN_OK) {
+ guint64 bytes = 0;
+
+ /* we must ask the imager what is the total size */
+ brasero_job_get_session_output_size (BRASERO_JOB (wodim),
+ NULL,
+ &bytes);
+ mb_total = bytes / 1048576;
+ brasero_wodim_compute (wodim,
+ mb_written,
+ mb_total,
+ track);
+ }
+
+ brasero_job_start_progress (BRASERO_JOB (wodim), FALSE);
+ }
+ else if (sscanf (line, "Formating in progress: %d.%d %% done", &mb_written, &mb_total) == 2) {
+ brasero_job_set_current_action (BRASERO_JOB (process),
+ BRASERO_BURN_ACTION_BLANKING,
+ _("Formatting disc"),
+ FALSE);
+
+ brasero_job_start_progress (BRASERO_JOB (wodim), FALSE);
+ brasero_job_set_progress (BRASERO_JOB (wodim),
+ (gdouble) ((gdouble) mb_written + ((gdouble) mb_total) / 10.0) / 100.0);
+ }
+ else if (sscanf (line, "Track %*d: %*s %d MB ", &mb_total) == 1) {
+/* if (mb_total > 0)
+ priv->tracks_total_bytes += mb_total * 1048576;
+*/ }
+ else if (strstr (line, "Sending CUE sheet")) {
+ BraseroTrackType *type = NULL;
+
+ /* See if we are in an audio case which would mean we're writing
+ * CD-TEXT */
+ type = brasero_track_type_new ();
+ brasero_job_get_input_type (BRASERO_JOB (wodim), type);
+ brasero_job_set_current_action (BRASERO_JOB (process),
+ BRASERO_BURN_ACTION_RECORDING_CD_TEXT,
+ brasero_track_type_get_has_stream (type) ? NULL:_("Writing cue sheet"),
+ FALSE);
+ brasero_track_type_free (type);
+ }
+ else if (g_str_has_prefix (line, "Re-load disk and hit <CR>")
+ || g_str_has_prefix (line, "send SIGUSR1 to continue")) {
+ BraseroBurnAction action = BRASERO_BURN_ACTION_NONE;
+
+ brasero_job_get_current_action (BRASERO_JOB (process), &action);
+
+ /* NOTE: There seems to be a BUG somewhere when writing raw images
+ * with clone mode. After disc has been written and fixated wodim
+ * asks the media to be reloaded. So we simply ignore this message
+ * and returns that everything went well. Which is indeed the case */
+ if (action == BRASERO_BURN_ACTION_FIXATING) {
+ brasero_job_finished_session (BRASERO_JOB (process));
+ return BRASERO_BURN_OK;
+ }
+
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_MEDIUM_NEED_RELOADING,
+ _("The disc needs to be reloaded before being recorded")));
+ }
+ else if (g_str_has_prefix (line, "Fixating...")
+ || g_str_has_prefix (line, "Writing Leadout...")) {
+ brasero_job_set_current_action (BRASERO_JOB (process),
+ BRASERO_BURN_ACTION_FIXATING,
+ NULL,
+ FALSE);
+ }
+ else if (g_str_has_prefix (line, "Last chance to quit, ")) {
+ brasero_job_set_dangerous (BRASERO_JOB (process), TRUE);
+ }
+ else if (g_str_has_prefix (line, "Blanking PMA, TOC, pregap")
+ || strstr (line, "Blanking entire disk")) {
+
+ }
+ /* This should not happen */
+ /* else if (strstr (line, "Use tsize= option in SAO mode to specify track size")) */
+
+ return BRASERO_BURN_OK;
+}
+
+static gboolean
+brasero_wodim_write_inf (BraseroWodim *wodim,
+ GPtrArray *argv,
+ BraseroTrack *track,
+ const gchar *tmpdir,
+ const gchar *album,
+ gint index,
+ gint start,
+ gboolean last_track,
+ GError **error)
+{
+ gint fd;
+ int isrc;
+ gint size;
+ int errsv;
+ gchar *path;
+ guint64 length;
+ gchar *string;
+ gint b_written;
+ gint64 sectors;
+ gchar buffer [128];
+ const gchar *info;
+ BraseroWodimPrivate *priv;
+
+ priv = BRASERO_WODIM_PRIVATE (wodim);
+
+ /* NOTE: about the .inf files: they should have the exact same path
+ * but the ending suffix file is replaced by inf:
+ * example : /path/to/file.mp3 => /path/to/file.inf */
+ if (brasero_job_get_fd_in (BRASERO_JOB (wodim), NULL) != BRASERO_BURN_OK) {
+ gchar *dot, *separator;
+
+ path = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (track), FALSE);
+
+ dot = strrchr (path, '.');
+ separator = strrchr (path, G_DIR_SEPARATOR);
+
+ if (dot && dot > separator)
+ path = g_strdup_printf ("%.*s.inf", dot - path, path);
+ else
+ path = g_strdup_printf ("%s.inf", path);
+
+ /* since this file was not returned by brasero_job_get_tmp_file
+ * it won't be erased when session is unrefed so we have to do
+ * it ourselves */
+ priv->infs = g_slist_prepend (priv->infs, g_strdup (path));
+ }
+ else {
+ BraseroBurnResult result;
+
+ /* in this case don't care about the name since stdin is used */
+ result = brasero_job_get_tmp_file (BRASERO_JOB (wodim),
+ ".inf",
+ &path,
+ error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+ }
+
+ fd = open (path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
+ if (fd < 0)
+ goto error;
+
+ BRASERO_JOB_LOG (wodim, "writing inf (%s)", path);
+
+ /* The problem here is that when writing CD-TEXT from .inf files, wodim
+ * uses only one charset (and don't let us specify which one) which is
+ * ISO-8859-1. (NOTE: don't believe the doc claiming it requires ASCII
+ * and see cdrecord/cdtext.c line 309).
+ * So we have to convert our UTF-8 input into such a charset.
+ * NOTE: according to docs ASCII should be used for text packs other
+ * than disc/track title.
+ * It might be good in the end to write and pack CD-TEXT pack data
+ * ourselves so we can set a different charset from English like
+ * Chinese for example. */
+ strcpy (buffer, "# created by brasero\n");
+ size = strlen (buffer);
+ b_written = write (fd, buffer, size);
+ if (b_written != size)
+ goto error;
+
+ strcpy (buffer, "MCN=\t\n");
+ size = strlen (buffer);
+ b_written = write (fd, buffer, size);
+ if (b_written != size)
+ goto error;
+
+ /* ISRC */
+ isrc = brasero_track_tag_lookup_int (BRASERO_TRACK (track), BRASERO_TRACK_STREAM_ISRC_TAG);
+ if (isrc > 0)
+ string = g_strdup_printf ("ISRC=\t%i\n", isrc);
+ else
+ string = g_strdup ("ISRC=\t\n");
+ size = strlen (string);
+ b_written = write (fd, string, size);
+ g_free (string);
+ if (b_written != size)
+ goto error;
+
+ strcpy (buffer, "Albumperformer=\t\n");
+ size = strlen (buffer);
+ b_written = write (fd, buffer, size);
+ if (b_written != size)
+ goto error;
+
+ if (album) {
+ gchar *encoded;
+
+ encoded = g_convert_with_fallback (album,
+ -1,
+ "ISO-8859-1",
+ "UTF-8",
+ "_", /* Fallback for non convertible characters */
+ NULL,
+ NULL,
+ NULL);
+ string = g_strdup_printf ("Albumtitle=\t%s\n", encoded);
+ g_free (encoded);
+ }
+ else
+ string = strdup ("Albumtitle=\t\n");
+ size = strlen (string);
+ b_written = write (fd, string, size);
+ g_free (string);
+ if (b_written != size)
+ goto error;
+
+ /* ARTIST */
+ info = brasero_track_tag_lookup_string (BRASERO_TRACK (track),
+ BRASERO_TRACK_STREAM_ARTIST_TAG);
+ if (info) {
+ gchar *encoded;
+
+ encoded = g_convert_with_fallback (info,
+ -1,
+ "ISO-8859-1",
+ "UTF-8",
+ "_", /* Fallback for non convertible characters */
+ NULL,
+ NULL,
+ NULL);
+ string = g_strdup_printf ("Performer=\t%s\n", encoded);
+ g_free (encoded);
+ }
+ else
+ string = strdup ("Performer=\t\n");
+ size = strlen (string);
+ b_written = write (fd, string, size);
+ g_free (string);
+ if (b_written != size)
+ goto error;
+
+ /* COMPOSER */
+ info = brasero_track_tag_lookup_string (BRASERO_TRACK (track),
+ BRASERO_TRACK_STREAM_COMPOSER_TAG);
+ if (info) {
+ gchar *encoded;
+
+ encoded = g_convert_with_fallback (info,
+ -1,
+ "ISO-8859-1",
+ "UTF-8",
+ "_", /* Fallback for non convertible characters */
+ NULL,
+ NULL,
+ NULL);
+ string = g_strdup_printf ("Composer=\t%s\n", encoded);
+ g_free (encoded);
+ }
+ else
+ string = strdup ("Composer=\t\n");
+ size = strlen (string);
+ b_written = write (fd, string, size);
+ g_free (string);
+ if (b_written != size)
+ goto error;
+
+ /* TITLE */
+ info = brasero_track_tag_lookup_string (BRASERO_TRACK (track),
+ BRASERO_TRACK_STREAM_TITLE_TAG);
+ if (info) {
+ gchar *encoded;
+
+ encoded = g_convert_with_fallback (info,
+ -1,
+ "ISO-8859-1",
+ "UTF-8",
+ "_", /* Fallback for non convertible characters */
+ NULL,
+ NULL,
+ NULL);
+ string = g_strdup_printf ("Tracktitle=\t%s\n", encoded);
+ g_free (encoded);
+ }
+ else
+ string = strdup ("Tracktitle=\t\n");
+ size = strlen (string);
+ b_written = write (fd, string, size);
+ g_free (string);
+ if (b_written != size)
+ goto error;
+
+ string = g_strdup_printf ("Tracknumber=\t%i\n", index);
+ size = strlen (string);
+ b_written = write (fd, string, size);
+ g_free (string);
+ if (b_written != size)
+ goto error;
+
+ string = g_strdup_printf ("Trackstart=\t%i\n", start);
+ size = strlen (string);
+ b_written = write (fd, string, size);
+ g_free (string);
+ if (b_written != size)
+ goto error;
+
+ length = 0;
+ brasero_track_stream_get_length (BRASERO_TRACK_STREAM (track), &length);
+ sectors = BRASERO_DURATION_TO_SECTORS (length);
+
+ BRASERO_JOB_LOG (wodim, "got track length %lli %lli", length, sectors);
+ string = g_strdup_printf ("Tracklength=\t%"G_GINT64_FORMAT", 0\n", sectors);
+ size = strlen (string);
+ b_written = write (fd, string, size);
+ g_free (string);
+ if (b_written != size)
+ goto error;
+
+ strcpy (buffer, "Pre-emphasis=\tno\n");
+ size = strlen (buffer);
+ b_written = write (fd, buffer, size);
+ if (b_written != size)
+ goto error;
+
+ strcpy (buffer, "Channels=\t2\n");
+ size = strlen (buffer);
+ b_written = write (fd, buffer, size);
+ if (b_written != size)
+ goto error;
+
+ strcpy (buffer, "Copy_permitted=\tyes\n");
+ size = strlen (buffer);
+ b_written = write (fd, buffer, size);
+ if (b_written != size)
+ goto error;
+
+ strcpy (buffer, "Endianess=\tlittle\n");
+ size = strlen (buffer);
+ b_written = write (fd, buffer, size);
+ if (b_written != size)
+ goto error;
+
+ strcpy (buffer, "Index=\t\t0\n");
+ size = strlen (buffer);
+ b_written = write (fd, buffer, size);
+ if (b_written != size)
+ goto error;
+
+ /* NOTE: -1 here means no pregap */
+ if (!last_track) {
+ /* K3b does this (possibly to remove silence) */
+ string = g_strdup_printf ("Index0=\t\t%"G_GINT64_FORMAT"\n",
+ sectors - 150);
+ }
+ else
+ string = g_strdup_printf ("Index0=\t\t-1\n");
+
+ size = strlen (string);
+ b_written = write (fd, string, size);
+ g_free (string);
+
+ if (b_written != size)
+ goto error;
+
+ close (fd);
+
+ if (argv)
+ g_ptr_array_add (argv, path);
+ else
+ g_free (path);
+
+ return BRASERO_BURN_OK;
+
+
+error:
+ errsv = errno;
+
+ g_remove (path);
+ g_free (path);
+
+ BRASERO_JOB_LOG (wodim,
+ "The inf file can't be written : %s",
+ g_strerror (errsv));
+
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("An internal error occured"));
+
+ return BRASERO_BURN_ERR;
+}
+
+static BraseroBurnResult
+brasero_wodim_write_infs (BraseroWodim *wodim,
+ GPtrArray *argv,
+ GError **error)
+{
+ BraseroWodimPrivate *priv;
+ BraseroBurnResult result;
+ gchar *tmpdir = NULL;
+ GSList *tracks;
+ GSList *iter;
+ gchar *album;
+ gint index;
+ gint start;
+
+ priv = BRASERO_WODIM_PRIVATE (wodim);
+
+ brasero_job_get_audio_title (BRASERO_JOB (wodim), &album);
+ brasero_job_get_tracks (BRASERO_JOB (wodim), &tracks);
+ index = 1;
+ start = 0;
+
+ for (iter = tracks; iter; iter = iter->next) {
+ guint64 sectors;
+ BraseroTrack *track;
+
+ track = iter->data;
+ result = brasero_wodim_write_inf (wodim,
+ argv,
+ track,
+ tmpdir,
+ album,
+ index,
+ start,
+ (iter->next == NULL),
+ error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+
+ index ++;
+ sectors = 0;
+
+ brasero_track_get_size (track, §ors, NULL);
+ start += sectors;
+ }
+
+ g_free (album);
+ g_free (tmpdir);
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_wodim_set_argv_record (BraseroWodim *wodim,
+ GPtrArray *argv,
+ GError **error)
+{
+ guint speed;
+ BraseroBurnFlag flags;
+ BraseroWodimPrivate *priv;
+ BraseroTrackType *type = NULL;
+
+ priv = BRASERO_WODIM_PRIVATE (wodim);
+
+ if (priv->immediate) {
+ g_ptr_array_add (argv, g_strdup ("-immed"));
+ g_ptr_array_add (argv, g_strdup_printf ("minbuf=%i", priv->minbuf));
+ }
+
+ if (brasero_job_get_speed (BRASERO_JOB (wodim), &speed) == BRASERO_BURN_OK) {
+ gchar *speed_str;
+
+ speed_str = g_strdup_printf ("speed=%d", speed);
+ g_ptr_array_add (argv, speed_str);
+ }
+
+ brasero_job_get_flags (BRASERO_JOB (wodim), &flags);
+ if (flags & BRASERO_BURN_FLAG_OVERBURN)
+ g_ptr_array_add (argv, g_strdup ("-overburn"));
+ if (flags & BRASERO_BURN_FLAG_BURNPROOF)
+ g_ptr_array_add (argv, g_strdup ("driveropts=burnfree"));
+ if (flags & BRASERO_BURN_FLAG_MULTI)
+ g_ptr_array_add (argv, g_strdup ("-multi"));
+
+ /* NOTE: This write mode is necessary for all CLONE images burning */
+ if (flags & BRASERO_BURN_FLAG_RAW)
+ g_ptr_array_add (argv, g_strdup ("-raw96r"));
+
+ /* NOTE1: DAO can't be used if we're appending to a disc */
+ /* NOTE2: CD-text cannot be written in tao mode (which is the default)
+ * NOTE3: when we don't want wodim to use stdin then we give the audio
+ * file on the command line. Otherwise we use the .inf */
+ if (flags & BRASERO_BURN_FLAG_DAO)
+ g_ptr_array_add (argv, g_strdup ("-dao"));
+
+ type = brasero_track_type_new ();
+ brasero_job_get_input_type (BRASERO_JOB (wodim), type);
+ if (brasero_job_get_fd_in (BRASERO_JOB (wodim), NULL) == BRASERO_BURN_OK) {
+ BraseroBurnResult result;
+ int buffer_size;
+ guint64 sectors;
+
+ /* we need to know what is the type of the track (audio / data) */
+ result = brasero_job_get_input_type (BRASERO_JOB (wodim), type);
+ if (result != BRASERO_BURN_OK) {
+ brasero_track_type_free (type);
+
+ BRASERO_JOB_LOG (wodim, "Imager doesn't seem to be ready");
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("An internal error occured"));
+ return BRASERO_BURN_ERR;
+ }
+
+ /* ask the size */
+ result = brasero_job_get_session_output_size (BRASERO_JOB (wodim),
+ §ors,
+ NULL);
+ if (result != BRASERO_BURN_OK) {
+ brasero_track_type_free (type);
+
+ BRASERO_JOB_LOG (wodim, "The size of the session cannot be retrieved");
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("An internal error occured"));
+ return BRASERO_BURN_ERR;
+ }
+
+ /* we create a buffer depending on the size
+ * buffer 4m> < 64m and is 1/25th of size otherwise */
+ buffer_size = sectors * 2352 / 1024 / 1024 / 25;
+ if (buffer_size > 32)
+ buffer_size = 32;
+ else if (buffer_size < 4)
+ buffer_size = 4;
+
+ g_ptr_array_add (argv, g_strdup_printf ("fs=%im", buffer_size));
+ if (brasero_track_type_get_has_image (type)) {
+ if (brasero_track_type_get_image_format (type) == BRASERO_IMAGE_FORMAT_BIN) {
+ g_ptr_array_add (argv, g_strdup_printf ("tsize=%Lis", sectors));
+
+ g_ptr_array_add (argv, g_strdup ("-data"));
+ g_ptr_array_add (argv, g_strdup ("-nopad"));
+ g_ptr_array_add (argv, g_strdup ("-"));
+ }
+ else {
+ brasero_track_type_free (type);
+ BRASERO_JOB_NOT_SUPPORTED (wodim);
+ }
+ }
+ else if (brasero_track_type_get_has_stream (type)) {
+ /* NOTE: when we don't want wodim to use stdin then we
+ * give the audio file on the command line. Otherwise we
+ * use the .inf */
+ g_ptr_array_add (argv, g_strdup ("-swab"));
+ g_ptr_array_add (argv, g_strdup ("-audio"));
+ g_ptr_array_add (argv, g_strdup ("-useinfo"));
+ g_ptr_array_add (argv, g_strdup ("-text"));
+
+ result = brasero_wodim_write_infs (wodim,
+ argv,
+ error);
+ if (result != BRASERO_BURN_OK) {
+ brasero_track_type_free (type);
+ return result;
+ }
+ }
+ else {
+ brasero_track_type_free (type);
+ BRASERO_JOB_NOT_SUPPORTED (wodim);
+ }
+ }
+ else if (brasero_track_type_get_has_stream (type)) {
+ BraseroBurnResult result;
+ GSList *tracks;
+
+ g_ptr_array_add (argv, g_strdup ("fs=16m"));
+ g_ptr_array_add (argv, g_strdup ("-audio"));
+ g_ptr_array_add (argv, g_strdup ("-swab"));
+ g_ptr_array_add (argv, g_strdup ("-pad"));
+
+ g_ptr_array_add (argv, g_strdup ("-useinfo"));
+ g_ptr_array_add (argv, g_strdup ("-text"));
+
+ result = brasero_wodim_write_infs (wodim,
+ NULL,
+ error);
+ if (result != BRASERO_BURN_OK) {
+ brasero_track_type_free (type);
+ return result;
+ }
+
+ tracks = NULL;
+ brasero_job_get_tracks (BRASERO_JOB (wodim), &tracks);
+ for (; tracks; tracks = tracks->next) {
+ BraseroTrack *track;
+ gchar *path;
+
+ track = tracks->data;
+ path = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (track), FALSE);
+ g_ptr_array_add (argv, path);
+ }
+ }
+ else if (brasero_track_type_get_has_image (type)) {
+ BraseroTrack *track = NULL;
+ BraseroImageFormat format;
+
+ brasero_job_get_current_track (BRASERO_JOB (wodim), &track);
+ if (!track) {
+ brasero_track_type_free (type);
+ BRASERO_JOB_NOT_READY (wodim);
+ }
+
+ format = brasero_track_type_get_image_format (type);
+ if (format == BRASERO_IMAGE_FORMAT_NONE) {
+ gchar *image_path;
+
+ image_path = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (track), FALSE);
+ if (!image_path) {
+ brasero_track_type_free (type);
+ BRASERO_JOB_NOT_READY (wodim);
+ }
+
+ g_ptr_array_add (argv, g_strdup ("fs=16m"));
+ g_ptr_array_add (argv, g_strdup ("-data"));
+ g_ptr_array_add (argv, g_strdup ("-nopad"));
+ g_ptr_array_add (argv, image_path);
+ }
+ else if (format == BRASERO_IMAGE_FORMAT_BIN) {
+ gchar *isopath;
+
+ isopath = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (track), FALSE);
+ if (!isopath) {
+ brasero_track_type_free (type);
+ BRASERO_JOB_NOT_READY (wodim);
+ }
+
+ g_ptr_array_add (argv, g_strdup ("fs=16m"));
+ g_ptr_array_add (argv, g_strdup ("-data"));
+ g_ptr_array_add (argv, g_strdup ("-nopad"));
+ g_ptr_array_add (argv, isopath);
+ }
+ else if (format == BRASERO_IMAGE_FORMAT_CLONE) {
+ gchar *rawpath;
+
+ rawpath = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (track), FALSE);
+ if (!rawpath) {
+ brasero_track_type_free (type);
+ BRASERO_JOB_NOT_READY (wodim);
+ }
+
+ g_ptr_array_add (argv, g_strdup ("fs=16m"));
+ g_ptr_array_add (argv, g_strdup ("-clone"));
+ g_ptr_array_add (argv, rawpath);
+ }
+ else if (format == BRASERO_IMAGE_FORMAT_CUE) {
+ gchar *cue_str;
+ gchar *cuepath;
+
+ cuepath = brasero_track_image_get_toc_source (BRASERO_TRACK_IMAGE (track), FALSE);
+ if (!cuepath) {
+ brasero_track_type_free (type);
+ BRASERO_JOB_NOT_READY (wodim);
+ }
+
+ g_ptr_array_add (argv, g_strdup ("fs=16m"));
+
+ cue_str = g_strdup_printf ("cuefile=%s", cuepath);
+ g_ptr_array_add (argv, cue_str);
+ g_free (cuepath);
+ }
+ else {
+ brasero_track_type_free (type);
+ BRASERO_JOB_NOT_SUPPORTED (wodim);
+ }
+ }
+ else {
+ brasero_track_type_free (type);
+ BRASERO_JOB_NOT_SUPPORTED (wodim);
+ }
+
+ brasero_track_type_free (type);
+ brasero_job_set_current_action (BRASERO_JOB (wodim),
+ BRASERO_BURN_ACTION_START_RECORDING,
+ NULL,
+ FALSE);
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_wodim_set_argv_blank (BraseroWodim *wodim, GPtrArray *argv)
+{
+ BraseroBurnResult result;
+ BraseroBurnFlag flags;
+ BraseroMedia media;
+
+ brasero_job_get_flags (BRASERO_JOB (wodim), &flags);
+
+ result = brasero_job_get_media (BRASERO_JOB (wodim), &media);
+ if (result != BRASERO_BURN_OK)
+ return result;
+
+ if (!BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_DVDRW_PLUS)) {
+ gchar *blank_str;
+
+ blank_str = g_strdup_printf ("blank=%s",
+ (flags & BRASERO_BURN_FLAG_FAST_BLANK) ? "fast" : "all");
+ g_ptr_array_add (argv, blank_str);
+ }
+ else if (media & BRASERO_MEDIUM_UNFORMATTED) {
+ g_ptr_array_add (argv, g_strdup ("-format"));
+
+ /* There are many options for this given by an option that is
+ * not documented: formattype=#type where type can be:
+ * - force: to force reformatting => problem cannot/doesn't want to reformat a disc already formated
+ * - full: to do a full formatting => problem only reformats what is not done yet
+ * - background: formatting in the background => problem cannot/doesn't want to reformat a disc already formated
+ * conclusion: we can only accept unformated media.
+ * The following option allows to do it more quickly:
+ * g_ptr_array_add (argv, g_strdup ("formattype=background");
+ */
+
+ }
+ else {
+ guint speed;
+ BraseroWodimPrivate *priv;
+
+ priv = BRASERO_WODIM_PRIVATE (wodim);
+
+ /* Since we can't reformat any already formatted DVD+RW, we
+ * write 0s to it to blank. */
+ if (priv->immediate) {
+ g_ptr_array_add (argv, g_strdup ("-immed"));
+ g_ptr_array_add (argv, g_strdup_printf ("minbuf=%i", priv->minbuf));
+ }
+
+ if (brasero_job_get_speed (BRASERO_JOB (wodim), &speed) == BRASERO_BURN_OK) {
+ gchar *speed_str;
+
+ speed_str = g_strdup_printf ("speed=%d", speed);
+ g_ptr_array_add (argv, speed_str);
+ }
+
+ if (!(flags & BRASERO_BURN_FLAG_FAST_BLANK)) {
+ gint64 sectors = 0;
+ BraseroMedium *medium;
+
+ brasero_job_get_medium (BRASERO_JOB (wodim), &medium);
+ brasero_medium_get_data_size (medium, NULL, §ors);
+ if (!sectors)
+ brasero_medium_get_capacity (medium, NULL, §ors);
+
+ g_ptr_array_add (argv, g_strdup_printf ("tsize=%Lis", sectors));
+ }
+ else /* we set 512s because wodim complains otherwise */
+ g_ptr_array_add (argv, g_strdup_printf ("tsize=512s"));
+
+ g_ptr_array_add (argv, g_strdup ("fs=16m"));
+ g_ptr_array_add (argv, g_strdup ("-data"));
+ g_ptr_array_add (argv, g_strdup ("-nopad"));
+ g_ptr_array_add (argv, g_strdup ("/dev/zero"));
+ }
+
+ brasero_job_set_current_action (BRASERO_JOB (wodim),
+ BRASERO_BURN_ACTION_BLANKING,
+ NULL,
+ FALSE);
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_wodim_set_argv (BraseroProcess *process,
+ GPtrArray *argv,
+ GError **error)
+{
+ BraseroWodimPrivate *priv;
+ BraseroBurnResult result;
+ BraseroJobAction action;
+ BraseroWodim *wodim;
+ BraseroBurnFlag flags;
+ gchar *dev_str;
+ gchar *device;
+
+ wodim = BRASERO_WODIM (process);
+ priv = BRASERO_WODIM_PRIVATE (wodim);
+
+ brasero_job_get_action (BRASERO_JOB (wodim), &action);
+ if (action == BRASERO_JOB_ACTION_SIZE)
+ return BRASERO_BURN_NOT_SUPPORTED;
+
+ g_ptr_array_add (argv, g_strdup ("wodim"));
+ g_ptr_array_add (argv, g_strdup ("-v"));
+
+ brasero_job_get_device (BRASERO_JOB (wodim), &device);
+ dev_str = g_strdup_printf ("dev=%s", device);
+ g_ptr_array_add (argv, dev_str);
+ g_free (device);
+
+ brasero_job_get_flags (BRASERO_JOB (wodim), &flags);
+ if (flags & BRASERO_BURN_FLAG_DUMMY)
+ g_ptr_array_add (argv, g_strdup ("-dummy"));
+
+ /* There is a bug in wodim where if we set that it takes 15 more so
+ * disable it as long as the bug remains. */
+
+ /* if (flags & BRASERO_BURN_FLAG_NOGRACE)
+ * g_ptr_array_add (argv, g_strdup ("gracetime=0"));
+ */
+
+ if (action == BRASERO_JOB_ACTION_RECORD)
+ result = brasero_wodim_set_argv_record (wodim, argv, error);
+ else if (action == BRASERO_JOB_ACTION_ERASE)
+ result = brasero_wodim_set_argv_blank (wodim, argv);
+ else
+ BRASERO_JOB_NOT_SUPPORTED (wodim);
+
+ return result;
+}
+
+static BraseroBurnResult
+brasero_wodim_post (BraseroJob *job)
+{
+ BraseroWodimPrivate *priv;
+ GSList *iter;
+
+ priv = BRASERO_WODIM_PRIVATE (job);
+ for (iter = priv->infs; iter; iter = iter->next) {
+ gchar *path;
+
+ path = iter->data;
+ g_remove (path);
+ g_free (path);
+ }
+
+ g_slist_free (priv->infs);
+ priv->infs = NULL;
+
+ return brasero_job_finished_session (job);
+}
+
+static void
+brasero_wodim_class_init (BraseroWodimClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ BraseroProcessClass *process_class = BRASERO_PROCESS_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (BraseroWodimPrivate));
+
+ parent_class = g_type_class_peek_parent (klass);
+ object_class->finalize = brasero_wodim_finalize;
+
+ process_class->stderr_func = brasero_wodim_stderr_read;
+ process_class->stdout_func = brasero_wodim_stdout_read;
+ process_class->set_argv = brasero_wodim_set_argv;
+ process_class->post = brasero_wodim_post;
+}
+
+static void
+brasero_wodim_init (BraseroWodim *obj)
+{
+ GConfClient *client;
+ BraseroWodimPrivate *priv;
+
+ /* load our "configuration" */
+ priv = BRASERO_WODIM_PRIVATE (obj);
+
+ client = gconf_client_get_default ();
+ priv->immediate = gconf_client_get_bool (client,
+ GCONF_KEY_IMMEDIATE_FLAG,
+ NULL);
+ priv->minbuf = gconf_client_get_int (client,
+ GCONF_KEY_MINBUF_VALUE,
+ NULL);
+ if (priv->minbuf > 95 || priv->minbuf < 25)
+ priv->minbuf = 30;
+
+ g_object_unref (client);
+}
+
+static void
+brasero_wodim_finalize (GObject *object)
+{
+ BraseroWodimPrivate *priv;
+ GSList *iter;
+
+ priv = BRASERO_WODIM_PRIVATE (object);
+
+ for (iter = priv->infs; iter; iter = iter->next) {
+ gchar *path;
+
+ path = iter->data;
+ g_remove (path);
+ g_free (path);
+ }
+
+ g_slist_free (priv->infs);
+ priv->infs = NULL;
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static BraseroBurnResult
+brasero_wodim_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+ BraseroPluginConfOption *immed, *minbuf;
+ const BraseroMedia media = BRASERO_MEDIUM_CD|
+ BRASERO_MEDIUM_WRITABLE|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_BLANK|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_HAS_AUDIO|
+ BRASERO_MEDIUM_HAS_DATA;
+
+ /* tests failed with DVD-RW in restricted overwrite mode */
+ const BraseroMedia dvd_media = BRASERO_MEDIUM_DVD|
+ BRASERO_MEDIUM_PLUS|
+ BRASERO_MEDIUM_SEQUENTIAL|
+ BRASERO_MEDIUM_WRITABLE|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_BLANK|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_HAS_DATA;
+ const BraseroMedia media_rw = BRASERO_MEDIUM_CD|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_CLOSED|
+ BRASERO_MEDIUM_HAS_AUDIO|
+ BRASERO_MEDIUM_HAS_DATA|
+ BRASERO_MEDIUM_BLANK;
+ BraseroBurnResult result;
+ GSList *output;
+ GSList *input;
+
+ /* NOTE: it seems that cdrecord can burn cue files on the fly */
+ brasero_plugin_define (plugin,
+ "wodim",
+ _("Use wodim to burn CDs and DVDs"),
+ "Philippe Rouquier",
+ 0);
+
+ /* First see if this plugin can be used */
+ result = brasero_process_check_path ("wodim", error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+
+ /* for recording */
+ input = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_PIPE|
+ BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_IMAGE_FORMAT_BIN);
+
+ /* wodim can burn all DVDs (except DVD-RW restricted) when it's ISOs */
+ output = brasero_caps_disc_new (dvd_media);
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (output);
+
+ /* All CD-R(W) */
+ output = brasero_caps_disc_new (media);
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (input);
+
+ input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_PIPE|
+ BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_AUDIO_FORMAT_RAW|
+ BRASERO_AUDIO_FORMAT_44100|
+ BRASERO_METADATA_INFO);
+
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (input);
+
+ input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_PIPE|
+ BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_AUDIO_FORMAT_RAW|
+ BRASERO_AUDIO_FORMAT_44100);
+
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (output);
+ g_slist_free (input);
+
+ /* for CLONE and CUE type images, we only want blank CD-R(W) */
+ output = brasero_caps_disc_new (BRASERO_MEDIUM_CD|
+ BRASERO_MEDIUM_WRITABLE|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_BLANK);
+
+ input = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_IMAGE_FORMAT_CUE|
+ BRASERO_IMAGE_FORMAT_CLONE);
+
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (output);
+ g_slist_free (input);
+
+ /* Flags for CD (RW)s */
+ BRASERO_PLUGIN_ADD_STANDARD_CDR_FLAGS (plugin, BRASERO_BURN_FLAG_NONE);
+ BRASERO_PLUGIN_ADD_STANDARD_CDRW_FLAGS (plugin, BRASERO_BURN_FLAG_NONE);
+
+ /* Apart from DAO it also supports RAW mode to burn CLONE images. This
+ * is a special mode for which there isn't any DUMMY burn possible */
+ brasero_plugin_set_flags (plugin,
+ BRASERO_MEDIUM_CD|
+ BRASERO_MEDIUM_WRITABLE|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_BLANK,
+ BRASERO_BURN_FLAG_RAW|
+ BRASERO_BURN_FLAG_BURNPROOF|
+ BRASERO_BURN_FLAG_OVERBURN|
+ BRASERO_BURN_FLAG_NOGRACE,
+ BRASERO_BURN_FLAG_NONE);
+
+ /* For DVD-W and DVD-RW sequential
+ * NOTE: given the performed tests it seems that wodim should not be
+ * used to start a multisession DVD-RW or even continue one. */
+ brasero_plugin_set_flags (plugin,
+ BRASERO_MEDIUM_DVD|
+ BRASERO_MEDIUM_SEQUENTIAL|
+ BRASERO_MEDIUM_WRITABLE|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_BLANK,
+ BRASERO_BURN_FLAG_DAO|
+ BRASERO_BURN_FLAG_BURNPROOF|
+ BRASERO_BURN_FLAG_OVERBURN|
+ BRASERO_BURN_FLAG_DUMMY|
+ BRASERO_BURN_FLAG_NOGRACE,
+ BRASERO_BURN_FLAG_NONE);
+
+ /* For DVD+R limited capabilites to blank media */
+ brasero_plugin_set_flags (plugin,
+ BRASERO_MEDIUM_DVDR_PLUS|
+ BRASERO_MEDIUM_BLANK,
+ BRASERO_BURN_FLAG_BURNPROOF|
+ BRASERO_BURN_FLAG_OVERBURN|
+ BRASERO_BURN_FLAG_MULTI|
+ BRASERO_BURN_FLAG_NOGRACE,
+ BRASERO_BURN_FLAG_NONE);
+
+ /* For DVD+RW: limited capabilities there are no MULTI possible
+ * NOTE: no UNFORMATTED here since wodim doesn't format them before*/
+ brasero_plugin_set_flags (plugin,
+ BRASERO_MEDIUM_DVDRW_PLUS|
+ BRASERO_MEDIUM_BLANK,
+ BRASERO_BURN_FLAG_OVERBURN|
+ BRASERO_BURN_FLAG_NOGRACE,
+ BRASERO_BURN_FLAG_NONE);
+
+ brasero_plugin_set_flags (plugin,
+ BRASERO_MEDIUM_DVDRW_PLUS|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_CLOSED|
+ BRASERO_MEDIUM_HAS_DATA,
+ BRASERO_BURN_FLAG_OVERBURN|
+ BRASERO_BURN_FLAG_NOGRACE,
+ BRASERO_BURN_FLAG_NONE);
+
+ /* blanking/formatting caps and flags for +/sequential RW
+ * NOTE: restricted overwrite DVD-RW can't be formatted.
+ * moreover DVD+RW are formatted while DVD-RW sequential are blanked.
+ * NOTE: blanking DVD-RW doesn't work */
+ output = brasero_caps_disc_new (BRASERO_MEDIUM_DVDRW_PLUS|
+ BRASERO_MEDIUM_CLOSED|
+ BRASERO_MEDIUM_HAS_DATA|
+ BRASERO_MEDIUM_UNFORMATTED|
+ BRASERO_MEDIUM_BLANK);
+ brasero_plugin_blank_caps (plugin, output);
+ g_slist_free (output);
+
+ /* again DVD+RW don't support dummy */
+ /* NOTE: wodim doesn't support formating already formated DVD+RWs. That
+ * is an error for it (stupid!). So sets only unformated DVDs. */
+ brasero_plugin_set_blank_flags (plugin,
+ BRASERO_MEDIUM_DVDRW_PLUS|
+ BRASERO_MEDIUM_CLOSED|
+ BRASERO_MEDIUM_HAS_DATA|
+ BRASERO_MEDIUM_UNFORMATTED|
+ BRASERO_MEDIUM_BLANK,
+ BRASERO_BURN_FLAG_NOGRACE|
+ BRASERO_BURN_FLAG_FAST_BLANK,
+ BRASERO_BURN_FLAG_NONE);
+
+ /* for blanking (CDRWs) */
+ output = brasero_caps_disc_new (media_rw);
+ brasero_plugin_blank_caps (plugin, output);
+ g_slist_free (output);
+
+ brasero_plugin_set_blank_flags (plugin,
+ media_rw,
+ BRASERO_BURN_FLAG_NOGRACE|
+ BRASERO_BURN_FLAG_FAST_BLANK,
+ BRASERO_BURN_FLAG_NONE);
+
+ /* add some configure options */
+ immed = brasero_plugin_conf_option_new (GCONF_KEY_IMMEDIATE_FLAG,
+ _("Enable \"-immed\" flag (see wodim manual)"),
+ BRASERO_PLUGIN_OPTION_BOOL);
+ minbuf = brasero_plugin_conf_option_new (GCONF_KEY_MINBUF_VALUE,
+ _("Minimum drive buffer fill ratio (in %) (see wodim manual):"),
+ BRASERO_PLUGIN_OPTION_INT);
+ brasero_plugin_conf_option_int_set_range (minbuf, 25, 95);
+
+ brasero_plugin_conf_option_bool_add_suboption (immed, minbuf);
+ brasero_plugin_add_conf_option (plugin, immed);
+
+ brasero_plugin_register_group (plugin, _(CDRKIT_DESCRIPTION));
+ return BRASERO_BURN_OK;
+}
diff --git a/plugins/cdrkit/burn-wodim.h b/plugins/cdrkit/burn-wodim.h
new file mode 100644
index 0000000..78c2c32
--- /dev/null
+++ b/plugins/cdrkit/burn-wodim.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ * wodim.h
+ *
+ * dim jan 22 15:22:52 2006
+ * Copyright 2006 Rouquier Philippe
+ * brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef WODIM_H
+#define WODIM_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_WODIM (brasero_wodim_get_type ())
+#define BRASERO_WODIM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_WODIM, BraseroWodim))
+#define BRASERO_WODIM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_WODIM, BraseroWodimClass))
+#define BRASERO_IS_WODIM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_WODIM))
+#define BRASERO_IS_WODIM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_WODIM))
+#define BRASERO_WODIM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_WODIM, BraseroWodimClass))
+
+G_END_DECLS
+
+#endif /* WODIM_H */
diff --git a/plugins/cdrtools/Makefile.am b/plugins/cdrtools/Makefile.am
new file mode 100644
index 0000000..a5e2ebb
--- /dev/null
+++ b/plugins/cdrtools/Makefile.am
@@ -0,0 +1,39 @@
+
+INCLUDES = \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/libbrasero-media/ \
+ -I$(top_builddir)/libbrasero-media/ \
+ -I$(top_srcdir)/libbrasero-burn \
+ -I$(top_builddir)/libbrasero-burn/ \
+ -DBRASERO_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
+ -DBRASERO_PREFIX=\"$(prefix)\" \
+ -DBRASERO_SYSCONFDIR=\"$(sysconfdir)\" \
+ -DBRASERO_DATADIR=\"$(datadir)/brasero\" \
+ -DBRASERO_LIBDIR=\"$(libdir)\" \
+ $(DISABLE_DEPRECATED) \
+ $(BRASERO_GLIB_CFLAGS) \
+ $(BRASERO_GCONF_CFLAGS)
+
+#cdrecord
+cdrecorddir = $(libdir)/brasero/plugins
+cdrecord_LTLIBRARIES = libbrasero-cdrecord.la
+libbrasero_cdrecord_la_SOURCES = burn-cdrecord.c burn-cdrecord.h \
+ burn-cdrtools.h
+libbrasero_cdrecord_la_LIBADD = $(BRASERO_GLIB_LIBS) $(BRASERO_GCONF_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_cdrecord_la_LDFLAGS = -module -avoid-version
+
+#mkisofs
+mkisofsdir = $(libdir)/brasero/plugins
+mkisofs_LTLIBRARIES = libbrasero-mkisofs.la
+libbrasero_mkisofs_la_SOURCES = burn-mkisofs.c burn-mkisofs.h \
+ burn-cdrtools.h
+libbrasero_mkisofs_la_LIBADD = $(BRASERO_GLIB_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_mkisofs_la_LDFLAGS = -module -avoid-version
+
+#readcd
+readcddir = $(libdir)/brasero/plugins
+readcd_LTLIBRARIES = libbrasero-readcd.la
+libbrasero_readcd_la_SOURCES = burn-readcd.c burn-readcd.h \
+ burn-cdrtools.h
+libbrasero_readcd_la_LIBADD = $(BRASERO_GLIB_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_readcd_la_LDFLAGS = -module -avoid-version
diff --git a/plugins/cdrtools/burn-cdrecord.c b/plugins/cdrtools/burn-cdrecord.c
new file mode 100644
index 0000000..0af98d4
--- /dev/null
+++ b/plugins/cdrtools/burn-cdrecord.c
@@ -0,0 +1,1371 @@
+/***************************************************************************
+ * cdrecord.c
+ *
+ * dim jan 22 15:22:52 2006
+ * Copyright 2006 Rouquier Philippe
+ * brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+#include <math.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+#include <gmodule.h>
+
+#include <gconf/gconf-client.h>
+
+#include "brasero-units.h"
+
+#include "burn-job.h"
+#include "burn-process.h"
+#include "brasero-plugin-registration.h"
+#include "burn-cdrtools.h"
+#include "burn-cdrecord.h"
+
+#include "brasero-tags.h"
+#include "brasero-track-image.h"
+#include "brasero-track-stream.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroCDRecord, brasero_cdrecord, BRASERO_TYPE_PROCESS, BraseroProcess);
+
+struct _BraseroCDRecordPrivate {
+ gint64 current_track_end_pos;
+ gint64 current_track_written;
+
+ gint current_track_num;
+ gint track_count;
+
+ gint minbuf;
+
+ GSList *infs;
+
+ guint immediate:1;
+};
+typedef struct _BraseroCDRecordPrivate BraseroCDRecordPrivate;
+#define BRASERO_CD_RECORD_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_CD_RECORD, BraseroCDRecordPrivate))
+
+static GObjectClass *parent_class = NULL;
+
+#define GCONF_KEY_IMMEDIATE_FLAG "/apps/brasero/config/immed_flag"
+#define GCONF_KEY_MINBUF_VALUE "/apps/brasero/config/minbuf_value"
+
+static BraseroBurnResult
+brasero_cdrecord_stderr_read (BraseroProcess *process, const gchar *line)
+{
+ BraseroBurnFlag flags;
+
+ brasero_job_get_flags (BRASERO_JOB (process), &flags);
+
+ if (strstr (line, "Cannot open SCSI driver.")
+ || strstr (line, "Operation not permitted. Cannot send SCSI cmd via ioctl")
+ || strstr (line, "Cannot open or use SCSI driver")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_PERMISSION,
+ _("You do not have the required permissions to use this drive")));
+ }
+ else if (!(flags & BRASERO_BURN_FLAG_OVERBURN)
+ && strstr (line, "Data may not fit on current disk")) {
+ /* we don't error out if overburn was chosen */
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_MEDIUM_SPACE,
+ _("Not enough space available on the disc")));
+ }
+ else if (strstr (line ,"cdrecord: A write error occured")
+ || strstr (line, "Could not write Lead-in")
+ || strstr (line, "Cannot fixate disk")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_WRITE_MEDIUM,
+ _("An error occured while writing to disc")));
+ }
+ else if (strstr (line, "DMA speed too slow") != NULL) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_SLOW_DMA,
+ _("The system is too slow to write the disc at this speed. Try a lower speed")));
+ }
+ else if (strstr (line, "Device or resource busy")) {
+ if (!strstr (line, "retrying in")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_DRIVE_BUSY,
+ _("The drive is busy")));
+ }
+ }
+ else if (strstr (line, "Illegal write mode for this drive")) {
+ /* NOTE : when it happened I had to unlock the
+ * drive with cdrdao and eject it. Should we ? */
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_DRIVE_BUSY,
+ _("The drive is busy")));
+ }
+
+ /* REMINDER: these should not be necessary as we checked that already */
+ /**
+ else if (strstr (line, "cannot write medium - incompatible format") != NULL) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_INPUT_INVALID,
+ _("The image does not seem to be a proper iso9660 file system")));
+ }
+ else if (strstr (line, "This means that we are checking recorded media.") != NULL) {
+ **/ /* NOTE: defer the consequence of this error as it is not always
+ * fatal. So send a warning but don't stop the process. */
+ /** brasero_process_deferred_error (process,
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_MEDIUM_INVALID,
+ _("The disc is already burnt")));
+ }
+ else if (strstr (line, "Cannot blank disk, aborting.") != NULL) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_MEDIUM_INVALID,
+ _("The disc could not be blanked")));
+ }
+ else if (strstr (line, "Bad audio track size")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("The audio tracks are too short or not a multiple of 2352")));
+ }
+ else if (strstr (line, "cdrecord: No such file or directory. Cannot open")
+ || strstr (line, "No tracks specified. Need at least one.")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_INPUT,
+ _("The image file cannot be found")));
+ }
+ else if (strstr (line, "Inappropriate audio coding")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_INPUT_INVALID,
+ _("All audio files must be stereo, 16-bit digital audio with 44100Hz samples")));
+ }
+ else if (strstr (line, "No disk / Wrong disk!") != NULL) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_MEDIA_NONE,
+ _("There seems to be no disc in the drive")));
+ }
+
+ **/
+
+ /** For these we'd rather have a message saying "cdrecord failed"
+ * as an internal error occured says nothing/even less
+ else if (strstr (line, "Bad file descriptor. read error on input file")
+ || strstr (line, "Input buffer error, aborting")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("An internal error occured")));
+ }
+
+ **/
+
+ return BRASERO_BURN_OK;
+}
+
+static void
+brasero_cdrecord_compute (BraseroCDRecord *cdrecord,
+ gint mb_written,
+ gint mb_total,
+ gint track_num)
+{
+ gboolean track_num_changed = FALSE;
+ BraseroCDRecordPrivate *priv;
+ gchar *action_string;
+ gint64 this_remain;
+ gint64 bytes;
+ gint64 total;
+
+ priv = BRASERO_CD_RECORD_PRIVATE (cdrecord);
+ if (mb_total <= 0)
+ return;
+
+ total = mb_total * 1048576;
+
+ if (track_num > priv->current_track_num) {
+ track_num_changed = TRUE;
+ priv->current_track_num = track_num;
+ priv->current_track_end_pos += mb_total * 1048576;
+ }
+
+ this_remain = (mb_total - mb_written) * 1048576;
+ bytes = (total - priv->current_track_end_pos) + this_remain;
+ brasero_job_set_written_session (BRASERO_JOB (cdrecord), total - bytes);
+
+ action_string = g_strdup_printf ("Writing track %02i", track_num);
+ brasero_job_set_current_action (BRASERO_JOB (cdrecord),
+ BRASERO_BURN_ACTION_RECORDING,
+ action_string,
+ track_num_changed);
+ g_free (action_string);
+}
+
+static BraseroBurnResult
+brasero_cdrecord_stdout_read (BraseroProcess *process, const gchar *line)
+{
+ guint track;
+ guint speed_1, speed_2;
+ BraseroCDRecord *cdrecord;
+ BraseroCDRecordPrivate *priv;
+ int mb_written = 0, mb_total = 0, fifo = 0, buf = 0;
+
+ cdrecord = BRASERO_CD_RECORD (process);
+ priv = BRASERO_CD_RECORD_PRIVATE (cdrecord);
+
+ if (sscanf (line, "Track %2u: %d of %d MB written (fifo %d%%) [buf %d%%] %d.%dx.",
+ &track, &mb_written, &mb_total, &fifo, &buf, &speed_1, &speed_2) == 7) {
+ gdouble current_rate;
+
+ current_rate = (gdouble) ((gdouble) speed_1 +
+ (gdouble) speed_2 / 10.0) *
+ (gdouble) CD_RATE;
+ brasero_job_set_rate (BRASERO_JOB (cdrecord), current_rate);
+
+ priv->current_track_written = mb_written * 1048576;
+ brasero_cdrecord_compute (cdrecord,
+ mb_written,
+ mb_total,
+ track);
+
+ brasero_job_start_progress (BRASERO_JOB (cdrecord), FALSE);
+ }
+ else if (sscanf (line, "Track %2u: %d MB written (fifo %d%%) [buf %d%%] %d.%dx.",
+ &track, &mb_written, &fifo, &buf, &speed_1, &speed_2) == 6) {
+ gdouble current_rate;
+
+ /* this line is printed when cdrecord writes on the fly */
+ current_rate = (gdouble) ((gdouble) speed_1 +
+ (gdouble) speed_2 / 10.0) *
+ (gdouble) CD_RATE;
+ brasero_job_set_rate (BRASERO_JOB (cdrecord), current_rate);
+
+ priv->current_track_written = mb_written * 1048576;
+ if (brasero_job_get_fd_in (BRASERO_JOB (cdrecord), NULL) == BRASERO_BURN_OK) {
+ guint64 bytes = 0;
+
+ /* we must ask the imager what is the total size */
+ brasero_job_get_session_output_size (BRASERO_JOB (cdrecord),
+ NULL,
+ &bytes);
+ mb_total = bytes / 1048576;
+ brasero_cdrecord_compute (cdrecord,
+ mb_written,
+ mb_total,
+ track);
+ }
+
+ brasero_job_start_progress (BRASERO_JOB (cdrecord), FALSE);
+ }
+ else if (sscanf (line, "Track %*d: %*s %d MB ", &mb_total) == 1) {
+/* if (mb_total > 0)
+ priv->tracks_total_bytes += mb_total * 1048576;
+*/ }
+ else if (strstr (line, "Formatting media")) {
+ brasero_job_set_current_action (BRASERO_JOB (process),
+ BRASERO_BURN_ACTION_BLANKING,
+ _("Formatting disc"),
+ FALSE);
+ }
+ else if (strstr (line, "Sending CUE sheet")) {
+ BraseroTrackType *type = NULL;
+
+ /* See if we are in an audio case which would mean we're writing
+ * CD-TEXT */
+ type = brasero_track_type_new ();
+ brasero_job_get_input_type (BRASERO_JOB (cdrecord), type);
+ brasero_job_set_current_action (BRASERO_JOB (process),
+ BRASERO_BURN_ACTION_RECORDING_CD_TEXT,
+ brasero_track_type_get_has_stream (type) ? NULL:_("Writing cue sheet"),
+ FALSE);
+ brasero_track_type_free (type);
+ }
+ else if (g_str_has_prefix (line, "Re-load disk and hit <CR>")
+ || g_str_has_prefix (line, "send SIGUSR1 to continue")) {
+ BraseroBurnAction action = BRASERO_BURN_ACTION_NONE;
+
+ brasero_job_get_current_action (BRASERO_JOB (process), &action);
+
+ /* NOTE: There seems to be a BUG somewhere when writing raw images
+ * with clone mode. After disc has been written and fixated cdrecord
+ * asks the media to be reloaded. So we simply ignore this message
+ * and returns that everything went well. Which is indeed the case */
+ if (action == BRASERO_BURN_ACTION_FIXATING) {
+ brasero_job_finished_session (BRASERO_JOB (process));
+ return BRASERO_BURN_OK;
+ }
+
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_MEDIUM_NEED_RELOADING,
+ _("The disc needs to be reloaded before being recorded")));
+ }
+ else if (g_str_has_prefix (line, "Fixating...")
+ || g_str_has_prefix (line, "Writing Leadout...")) {
+ brasero_job_set_current_action (BRASERO_JOB (process),
+ BRASERO_BURN_ACTION_FIXATING,
+ NULL,
+ FALSE);
+ }
+ else if (g_str_has_prefix (line, "Last chance to quit, ")) {
+ brasero_job_set_dangerous (BRASERO_JOB (process), TRUE);
+ }
+ else if (g_str_has_prefix (line, "Blanking PMA, TOC, pregap")
+ || strstr (line, "Blanking entire disk")) {
+
+ }
+ /* This should not happen */
+ /* else if (strstr (line, "Use tsize= option in SAO mode to specify track size")) */
+
+ return BRASERO_BURN_OK;
+}
+
+static gboolean
+brasero_cdrecord_write_inf (BraseroCDRecord *cdrecord,
+ GPtrArray *argv,
+ BraseroTrack *track,
+ const gchar *tmpdir,
+ const gchar *album,
+ gint index,
+ gint start,
+ gboolean last_track,
+ GError **error)
+{
+ gint fd;
+ int isrc;
+ int errsv;
+ gint size;
+ gchar *path;
+ guint64 length;
+ gchar *string;
+ gint b_written;
+ gint64 sectors;
+ const gchar *info;
+ gchar buffer [128];
+ BraseroCDRecordPrivate *priv;
+
+ priv = BRASERO_CD_RECORD_PRIVATE (cdrecord);
+
+ /* NOTE: about the .inf files: they should have the exact same path
+ * but the ending suffix file is replaced by inf:
+ * example : /path/to/file.mp3 => /path/to/file.inf */
+ if (brasero_job_get_fd_in (BRASERO_JOB (cdrecord), NULL) != BRASERO_BURN_OK) {
+ gchar *dot, *separator;
+
+ path = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (track), FALSE);
+
+ dot = strrchr (path, '.');
+ separator = strrchr (path, G_DIR_SEPARATOR);
+
+ if (dot && dot > separator)
+ path = g_strdup_printf ("%.*s.inf",
+ dot - path,
+ path);
+ else
+ path = g_strdup_printf ("%s.inf",
+ path);
+
+ /* since this file was not returned by brasero_job_get_tmp_file
+ * it won't be erased when session is unrefed so we have to do
+ * it ourselves */
+ priv->infs = g_slist_prepend (priv->infs, g_strdup (path));
+ }
+ else {
+ BraseroBurnResult result;
+
+ /* in this case don't care about the name since stdin is used */
+ result = brasero_job_get_tmp_file (BRASERO_JOB (cdrecord),
+ ".inf",
+ &path,
+ error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+ }
+
+ fd = open (path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
+ if (fd < 0)
+ goto error;
+
+ BRASERO_JOB_LOG (cdrecord, "writing inf (%s)", path);
+
+ /* The problem here is that when writing CD-TEXT from .inf files, wodim
+ * uses only one charset (and don't let us specify which one) which is
+ * ISO-8859-1. (NOTE: don't believe the doc claiming it requires ASCII
+ * and see cdrecord/cdtext.c line 309).
+ * So we have to convert our UTF-8 input into such a charset.
+ * NOTE: according to docs ASCII should be used for text packs other
+ * than disc/track title.
+ * It might be good in the end to write and pack CD-TEXT pack data
+ * ourselves so we can set a different charset from English like
+ * Chinese for example. */
+ strcpy (buffer, "# created by brasero\n");
+ size = strlen (buffer);
+ b_written = write (fd, buffer, size);
+ if (b_written != size)
+ goto error;
+
+ strcpy (buffer, "MCN=\t\n");
+ size = strlen (buffer);
+ b_written = write (fd, buffer, size);
+ if (b_written != size)
+ goto error;
+
+ /* ISRC */
+ isrc = brasero_track_tag_lookup_int (BRASERO_TRACK (track), BRASERO_TRACK_STREAM_ISRC_TAG);
+ if (isrc > 0)
+ string = g_strdup_printf ("ISRC=\t%i\n", isrc);
+ else
+ string = g_strdup ("ISRC=\t\n");
+ size = strlen (string);
+ b_written = write (fd, string, size);
+ g_free (string);
+ if (b_written != size)
+ goto error;
+
+ strcpy (buffer, "Albumperformer=\t\n");
+ size = strlen (buffer);
+ b_written = write (fd, buffer, size);
+ if (b_written != size)
+ goto error;
+
+ if (album) {
+ gchar *encoded;
+
+ encoded = g_convert_with_fallback (album,
+ -1,
+ "ISO-8859-1",
+ "UTF-8",
+ "_", /* Fallback for non convertible characters */
+ NULL,
+ NULL,
+ NULL);
+ string = g_strdup_printf ("Albumtitle=\t%s\n", encoded);
+ g_free (encoded);
+ }
+ else
+ string = strdup ("Albumtitle=\t\n");
+ size = strlen (string);
+ b_written = write (fd, string, size);
+ g_free (string);
+ if (b_written != size)
+ goto error;
+
+ /* ARTIST */
+ info = brasero_track_tag_lookup_string (BRASERO_TRACK (track),
+ BRASERO_TRACK_STREAM_ARTIST_TAG);
+ if (info) {
+ gchar *encoded;
+
+ encoded = g_convert_with_fallback (info,
+ -1,
+ "ISO-8859-1",
+ "UTF-8",
+ "_", /* Fallback for non convertible characters */
+ NULL,
+ NULL,
+ NULL);
+ string = g_strdup_printf ("Performer=\t%s\n", encoded);
+ g_free (encoded);
+ }
+ else
+ string = strdup ("Performer=\t\n");
+ size = strlen (string);
+ b_written = write (fd, string, size);
+ g_free (string);
+ if (b_written != size)
+ goto error;
+
+ /* COMPOSER */
+ info = brasero_track_tag_lookup_string (BRASERO_TRACK (track),
+ BRASERO_TRACK_STREAM_COMPOSER_TAG);
+ if (info) {
+ gchar *encoded;
+
+ encoded = g_convert_with_fallback (info,
+ -1,
+ "ISO-8859-1",
+ "UTF-8",
+ "_", /* Fallback for non convertible characters */
+ NULL,
+ NULL,
+ NULL);
+ string = g_strdup_printf ("Composer=\t%s\n", encoded);
+ g_free (encoded);
+ }
+ else
+ string = strdup ("Composer=\t\n");
+ size = strlen (string);
+ b_written = write (fd, string, size);
+ g_free (string);
+ if (b_written != size)
+ goto error;
+
+ /* TITLE */
+ info = brasero_track_tag_lookup_string (BRASERO_TRACK (track),
+ BRASERO_TRACK_STREAM_TITLE_TAG);
+ if (info) {
+ gchar *encoded;
+
+ encoded = g_convert_with_fallback (info,
+ -1,
+ "ISO-8859-1",
+ "UTF-8",
+ "_", /* Fallback for non convertible characters */
+ NULL,
+ NULL,
+ NULL);
+ string = g_strdup_printf ("Tracktitle=\t%s\n", encoded);
+ g_free (encoded);
+ }
+ else
+ string = strdup ("Tracktitle=\t\n");
+ size = strlen (string);
+ b_written = write (fd, string, size);
+ g_free (string);
+ if (b_written != size)
+ goto error;
+
+ string = g_strdup_printf ("Tracknumber=\t%i\n", index);
+ size = strlen (string);
+ b_written = write (fd, string, size);
+ g_free (string);
+ if (b_written != size)
+ goto error;
+
+ string = g_strdup_printf ("Trackstart=\t%i\n", start);
+ size = strlen (string);
+ b_written = write (fd, string, size);
+ g_free (string);
+ if (b_written != size)
+ goto error;
+
+ length = 0;
+ brasero_track_stream_get_length (BRASERO_TRACK_STREAM (track), &length);
+ sectors = BRASERO_DURATION_TO_SECTORS (length);
+
+ BRASERO_JOB_LOG (cdrecord, "got track length %lli", length);
+ string = g_strdup_printf ("Tracklength=\t%"G_GINT64_FORMAT", 0\n", sectors);
+ size = strlen (string);
+ b_written = write (fd, string, size);
+ g_free (string);
+ if (b_written != size)
+ goto error;
+
+ strcpy (buffer, "Pre-emphasis=\tno\n");
+ size = strlen (buffer);
+ b_written = write (fd, buffer, size);
+ if (b_written != size)
+ goto error;
+
+ strcpy (buffer, "Channels=\t2\n");
+ size = strlen (buffer);
+ b_written = write (fd, buffer, size);
+ if (b_written != size)
+ goto error;
+
+ strcpy (buffer, "Copy_permitted=\tyes\n");
+ size = strlen (buffer);
+ b_written = write (fd, buffer, size);
+ if (b_written != size)
+ goto error;
+
+ strcpy (buffer, "Endianess=\tlittle\n");
+ size = strlen (buffer);
+ b_written = write (fd, buffer, size);
+ if (b_written != size)
+ goto error;
+
+ strcpy (buffer, "Index=\t\t0\n");
+ size = strlen (buffer);
+ b_written = write (fd, buffer, size);
+ if (b_written != size)
+ goto error;
+
+ /* NOTE: -1 here means no pregap */
+ if (!last_track) {
+ /* K3b does this (possibly to remove silence) */
+ string = g_strdup_printf ("Index0=\t\t%"G_GINT64_FORMAT"\n",
+ sectors - 150);
+ }
+ else
+ string = g_strdup_printf ("Index0=\t\t-1\n");
+
+ size = strlen (string);
+ b_written = write (fd, string, size);
+ g_free (string);
+ if (b_written != size)
+ goto error;
+
+ close (fd);
+
+ if (argv)
+ g_ptr_array_add (argv, path);
+ else
+ g_free (path);
+
+ return BRASERO_BURN_OK;
+
+
+error:
+ errsv = errno;
+
+ g_remove (path);
+ g_free (path);
+
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("An internal error occured (%s)"),
+ g_strerror (errsv));
+
+ return BRASERO_BURN_ERR;
+}
+
+static BraseroBurnResult
+brasero_cdrecord_write_infs (BraseroCDRecord *cdrecord,
+ GPtrArray *argv,
+ GError **error)
+{
+ BraseroCDRecordPrivate *priv;
+ BraseroBurnResult result;
+ gchar *tmpdir = NULL;
+ GSList *tracks;
+ GSList *iter;
+ gchar *album;
+ gint index;
+ gint start;
+
+ priv = BRASERO_CD_RECORD_PRIVATE (cdrecord);
+
+ brasero_job_get_audio_title (BRASERO_JOB (cdrecord), &album);
+ brasero_job_get_tracks (BRASERO_JOB (cdrecord), &tracks);
+ index = 1;
+ start = 0;
+
+ for (iter = tracks; iter; iter = iter->next) {
+ guint64 sectors;
+ BraseroTrack *track;
+
+ track = iter->data;
+ result = brasero_cdrecord_write_inf (cdrecord,
+ argv,
+ track,
+ tmpdir,
+ album,
+ index,
+ start,
+ (iter->next == NULL),
+ error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+
+ index ++;
+ sectors = 0;
+
+ brasero_track_get_size (track, §ors, NULL);
+ start += sectors;
+ }
+
+ g_free (album);
+ g_free (tmpdir);
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_cdrecord_set_argv_record (BraseroCDRecord *cdrecord,
+ GPtrArray *argv,
+ GError **error)
+{
+ guint speed;
+ BraseroBurnFlag flags;
+ BraseroCDRecordPrivate *priv;
+ BraseroTrackType *type = NULL;
+
+ priv = BRASERO_CD_RECORD_PRIVATE (cdrecord);
+
+ if (priv->immediate) {
+ g_ptr_array_add (argv, g_strdup ("-immed"));
+ g_ptr_array_add (argv, g_strdup_printf ("minbuf=%i", priv->minbuf));
+ }
+
+ if (brasero_job_get_speed (BRASERO_JOB (cdrecord), &speed) == BRASERO_BURN_OK) {
+ gchar *speed_str;
+
+ speed_str = g_strdup_printf ("speed=%d", speed);
+ g_ptr_array_add (argv, speed_str);
+ }
+
+ brasero_job_get_flags (BRASERO_JOB (cdrecord), &flags);
+ if (flags & BRASERO_BURN_FLAG_OVERBURN)
+ g_ptr_array_add (argv, g_strdup ("-overburn"));
+ if (flags & BRASERO_BURN_FLAG_BURNPROOF)
+ g_ptr_array_add (argv, g_strdup ("driveropts=burnfree"));
+ if (flags & BRASERO_BURN_FLAG_MULTI)
+ g_ptr_array_add (argv, g_strdup ("-multi"));
+
+ /* NOTE: This write mode is necessary for all CLONE images burning */
+ if (flags & BRASERO_BURN_FLAG_RAW)
+ g_ptr_array_add (argv, g_strdup ("-raw96r"));
+
+ /* NOTE1: DAO can't be used if we're appending to a disc */
+ /* NOTE2: CD-text cannot be written in tao mode (which is the default)
+ * NOTE3: when we don't want wodim to use stdin then we give the audio
+ * file on the command line. Otherwise we use the .inf */
+ if (flags & BRASERO_BURN_FLAG_DAO)
+ g_ptr_array_add (argv, g_strdup ("-dao"));
+
+ type = brasero_track_type_new ();
+ brasero_job_get_input_type (BRASERO_JOB (cdrecord), type);
+
+ if (brasero_job_get_fd_in (BRASERO_JOB (cdrecord), NULL) == BRASERO_BURN_OK) {
+ BraseroBurnResult result;
+ int buffer_size;
+ guint64 sectors;
+
+ /* we need to know what is the type of the track (audio / data) */
+ result = brasero_job_get_input_type (BRASERO_JOB (cdrecord), type);
+ if (result != BRASERO_BURN_OK) {
+ brasero_track_type_free (type);
+
+ BRASERO_JOB_LOG (cdrecord, "Imager doesn't seem to be ready")
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("An internal error occured"));
+ return BRASERO_BURN_ERR;
+ }
+
+ /* ask the size */
+ result = brasero_job_get_session_output_size (BRASERO_JOB (cdrecord),
+ §ors,
+ NULL);
+ if (result != BRASERO_BURN_OK) {
+ brasero_track_type_free (type);
+
+ BRASERO_JOB_LOG (cdrecord, "The size of the session cannot be retrieved")
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("An internal error occured"));
+ return BRASERO_BURN_ERR;
+ }
+
+ /* we create a buffer depending on the size
+ * buffer 4m> < 64m and is 1/25th of size otherwise */
+ buffer_size = sectors * 2352 / 1024 / 1024 / 25;
+ if (buffer_size > 32)
+ buffer_size = 32;
+ else if (buffer_size < 4)
+ buffer_size = 4;
+
+ g_ptr_array_add (argv, g_strdup_printf ("fs=%im", buffer_size));
+ if (brasero_track_type_get_has_image (type)) {
+ BraseroImageFormat format;
+
+ format = brasero_track_type_get_image_format (type);
+ if (format == BRASERO_IMAGE_FORMAT_BIN) {
+ g_ptr_array_add (argv, g_strdup_printf ("tsize=%Lis", sectors));
+ g_ptr_array_add (argv, g_strdup ("-data"));
+ g_ptr_array_add (argv, g_strdup ("-nopad"));
+ g_ptr_array_add (argv, g_strdup ("-"));
+ }
+ else {
+ brasero_track_type_free (type);
+ BRASERO_JOB_NOT_SUPPORTED (cdrecord);
+ }
+ }
+ else if (brasero_track_type_get_has_stream (type)) {
+ g_ptr_array_add (argv, g_strdup ("-swab"));
+ g_ptr_array_add (argv, g_strdup ("-audio"));
+ g_ptr_array_add (argv, g_strdup ("-useinfo"));
+ g_ptr_array_add (argv, g_strdup ("-text"));
+
+ result = brasero_cdrecord_write_infs (cdrecord,
+ argv,
+ error);
+ if (result != BRASERO_BURN_OK) {
+ brasero_track_type_free (type);
+ return result;
+ }
+ }
+ else {
+ brasero_track_type_free (type);
+ BRASERO_JOB_NOT_SUPPORTED (cdrecord);
+ }
+ }
+ else if (brasero_track_type_get_has_stream (type)) {
+ BraseroBurnResult result;
+ GSList *tracks;
+
+ g_ptr_array_add (argv, g_strdup ("fs=16m"));
+ g_ptr_array_add (argv, g_strdup ("-audio"));
+ g_ptr_array_add (argv, g_strdup ("-swab"));
+ g_ptr_array_add (argv, g_strdup ("-pad"));
+
+ g_ptr_array_add (argv, g_strdup ("-useinfo"));
+ g_ptr_array_add (argv, g_strdup ("-text"));
+
+ result = brasero_cdrecord_write_infs (cdrecord,
+ NULL,
+ error);
+ if (result != BRASERO_BURN_OK) {
+ brasero_track_type_free (type);
+ return result;
+ }
+
+ tracks = NULL;
+ brasero_job_get_tracks (BRASERO_JOB (cdrecord), &tracks);
+ for (; tracks; tracks = tracks->next) {
+ BraseroTrack *track;
+ gchar *path;
+
+ track = tracks->data;
+ path = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (track), FALSE);
+ g_ptr_array_add (argv, path);
+ }
+ }
+ else if (brasero_track_type_get_has_image (type)) {
+ BraseroTrack *track = NULL;
+ BraseroImageFormat format;
+
+ brasero_job_get_current_track (BRASERO_JOB (cdrecord), &track);
+ if (!track) {
+ brasero_track_type_free (type);
+ BRASERO_JOB_NOT_READY (cdrecord);
+ }
+
+ format = brasero_track_type_get_image_format (type);
+ if (format == BRASERO_IMAGE_FORMAT_NONE) {
+ gchar *image_path;
+
+ image_path = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (track), FALSE);
+ if (!image_path) {
+ brasero_track_type_free (type);
+ BRASERO_JOB_NOT_READY (cdrecord);
+ }
+
+ g_ptr_array_add (argv, g_strdup ("fs=16m"));
+ g_ptr_array_add (argv, g_strdup ("-data"));
+ g_ptr_array_add (argv, g_strdup ("-nopad"));
+ g_ptr_array_add (argv, image_path);
+ }
+ else if (format == BRASERO_IMAGE_FORMAT_BIN) {
+ gchar *isopath;
+
+ isopath = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (track), FALSE);
+ if (!isopath) {
+ brasero_track_type_free (type);
+ BRASERO_JOB_NOT_READY (cdrecord);
+ }
+
+ g_ptr_array_add (argv, g_strdup ("fs=16m"));
+ g_ptr_array_add (argv, g_strdup ("-data"));
+ g_ptr_array_add (argv, g_strdup ("-nopad"));
+ g_ptr_array_add (argv, isopath);
+ }
+ else if (format == BRASERO_IMAGE_FORMAT_CLONE) {
+ gchar *rawpath;
+
+ rawpath = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (track), FALSE);
+ if (!rawpath) {
+ brasero_track_type_free (type);
+ BRASERO_JOB_NOT_READY (cdrecord);
+ }
+
+ g_ptr_array_add (argv, g_strdup ("fs=16m"));
+ g_ptr_array_add (argv, g_strdup ("-clone"));
+ g_ptr_array_add (argv, rawpath);
+ }
+ else if (format == BRASERO_IMAGE_FORMAT_CUE) {
+ gchar *cue_str;
+ gchar *cuepath;
+
+ cuepath = brasero_track_image_get_toc_source (BRASERO_TRACK_IMAGE (track), FALSE);
+ if (!cuepath) {
+ brasero_track_type_free (type);
+ BRASERO_JOB_NOT_READY (cdrecord);
+ }
+
+ g_ptr_array_add (argv, g_strdup ("fs=16m"));
+
+ cue_str = g_strdup_printf ("cuefile=%s", cuepath);
+ g_ptr_array_add (argv, cue_str);
+ g_free (cuepath);
+ }
+ else {
+ brasero_track_type_free (type);
+ BRASERO_JOB_NOT_SUPPORTED (cdrecord);
+ }
+ }
+ else {
+ brasero_track_type_free (type);
+ BRASERO_JOB_NOT_SUPPORTED (cdrecord);
+ }
+
+ brasero_track_type_free (type);
+
+ brasero_job_set_current_action (BRASERO_JOB (cdrecord),
+ BRASERO_BURN_ACTION_START_RECORDING,
+ NULL,
+ FALSE);
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_cdrecord_set_argv_blank (BraseroCDRecord *cdrecord, GPtrArray *argv)
+{
+ gchar *blank_str;
+ BraseroBurnFlag flags;
+
+ brasero_job_get_flags (BRASERO_JOB (cdrecord), &flags);
+ blank_str = g_strdup_printf ("blank=%s",
+ (flags & BRASERO_BURN_FLAG_FAST_BLANK) ? "fast" : "all");
+ g_ptr_array_add (argv, blank_str);
+
+ brasero_job_set_current_action (BRASERO_JOB (cdrecord),
+ BRASERO_BURN_ACTION_BLANKING,
+ NULL,
+ FALSE);
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_cdrecord_set_argv (BraseroProcess *process,
+ GPtrArray *argv,
+ GError **error)
+{
+ BraseroCDRecordPrivate *priv;
+ BraseroCDRecord *cdrecord;
+ BraseroBurnResult result;
+ BraseroJobAction action;
+ BraseroBurnFlag flags;
+ gchar *dev_str;
+ gchar *device;
+
+ cdrecord = BRASERO_CD_RECORD (process);
+ priv = BRASERO_CD_RECORD_PRIVATE (cdrecord);
+
+ brasero_job_get_action (BRASERO_JOB (cdrecord), &action);
+ if (action == BRASERO_JOB_ACTION_SIZE)
+ return BRASERO_BURN_NOT_SUPPORTED;
+
+ g_ptr_array_add (argv, g_strdup ("cdrecord"));
+ g_ptr_array_add (argv, g_strdup ("-v"));
+
+#ifdef HAVE_CAM_LIB_H
+ /* FreeBSD like that better */
+ brasero_job_get_bus_target_lun (BRASERO_JOB (cdrecord), &device);
+#else
+ brasero_job_get_device (BRASERO_JOB (cdrecord), &device);
+#endif
+
+ dev_str = g_strdup_printf ("dev=%s", device);
+ g_ptr_array_add (argv, dev_str);
+ g_free (device);
+
+ brasero_job_get_flags (BRASERO_JOB (cdrecord), &flags);
+ if (flags & BRASERO_BURN_FLAG_DUMMY)
+ g_ptr_array_add (argv, g_strdup ("-dummy"));
+
+ if (flags & BRASERO_BURN_FLAG_NOGRACE)
+ g_ptr_array_add (argv, g_strdup ("gracetime=0"));
+
+ if (action == BRASERO_JOB_ACTION_RECORD)
+ result = brasero_cdrecord_set_argv_record (cdrecord, argv, error);
+ else if (action == BRASERO_JOB_ACTION_ERASE)
+ result = brasero_cdrecord_set_argv_blank (cdrecord, argv);
+ else
+ BRASERO_JOB_NOT_SUPPORTED (cdrecord);
+
+ return result;
+}
+
+static BraseroBurnResult
+brasero_cdrecord_post (BraseroJob *job)
+{
+ BraseroCDRecordPrivate *priv;
+ GSList *iter;
+
+ priv = BRASERO_CD_RECORD_PRIVATE (job);
+ for (iter = priv->infs; iter; iter = iter->next) {
+ gchar *path;
+
+ path = iter->data;
+ g_remove (path);
+ g_free (path);
+ }
+
+ g_slist_free (priv->infs);
+ priv->infs = NULL;
+
+ return brasero_job_finished_session (job);
+}
+
+static void
+brasero_cdrecord_class_init (BraseroCDRecordClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ BraseroProcessClass *process_class = BRASERO_PROCESS_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (BraseroCDRecordPrivate));
+
+ parent_class = g_type_class_peek_parent (klass);
+ object_class->finalize = brasero_cdrecord_finalize;
+
+ process_class->stderr_func = brasero_cdrecord_stderr_read;
+ process_class->stdout_func = brasero_cdrecord_stdout_read;
+ process_class->set_argv = brasero_cdrecord_set_argv;
+ process_class->post = brasero_cdrecord_post;
+}
+
+static void
+brasero_cdrecord_init (BraseroCDRecord *obj)
+{
+ GConfClient *client;
+ BraseroCDRecordPrivate *priv;
+
+ /* load our "configuration" */
+ priv = BRASERO_CD_RECORD_PRIVATE (obj);
+
+ client = gconf_client_get_default ();
+ priv->immediate = gconf_client_get_bool (client,
+ GCONF_KEY_IMMEDIATE_FLAG,
+ NULL);
+ priv->minbuf = gconf_client_get_int (client,
+ GCONF_KEY_MINBUF_VALUE,
+ NULL);
+ if (priv->minbuf > 95 || priv->minbuf < 25)
+ priv->minbuf = 30;
+
+ g_object_unref (client);
+}
+
+static void
+brasero_cdrecord_finalize (GObject *object)
+{
+ BraseroCDRecordPrivate *priv;
+ GSList *iter;
+
+ priv = BRASERO_CD_RECORD_PRIVATE (object);
+
+ for (iter = priv->infs; iter; iter = iter->next) {
+ gchar *path;
+
+ path = iter->data;
+ g_remove (path);
+ g_free (path);
+ }
+
+ g_slist_free (priv->infs);
+ priv->infs = NULL;
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static BraseroBurnResult
+brasero_cdrecord_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+ BraseroPluginConfOption *immed, *minbuf;
+ const BraseroMedia media = BRASERO_MEDIUM_CD|
+ BRASERO_MEDIUM_WRITABLE|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_BLANK|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_HAS_AUDIO|
+ BRASERO_MEDIUM_HAS_DATA;
+ const BraseroMedia dvd_media = BRASERO_MEDIUM_DVD|
+ BRASERO_MEDIUM_PLUS|
+ BRASERO_MEDIUM_SEQUENTIAL|
+ BRASERO_MEDIUM_WRITABLE|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_BLANK|
+ BRASERO_MEDIUM_UNFORMATTED|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_HAS_DATA;
+ const BraseroMedia media_rw = BRASERO_MEDIUM_CD|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_CLOSED|
+ BRASERO_MEDIUM_HAS_AUDIO|
+ BRASERO_MEDIUM_HAS_DATA|
+ BRASERO_MEDIUM_BLANK;
+ BraseroBurnResult result;
+ GSList *output;
+ GSList *input;
+
+ /* NOTE: it seems that cdrecord can burn cue files on the fly */
+ brasero_plugin_define (plugin,
+ "cdrecord",
+ _("Use cdrecord to burn CDs and DVDs"),
+ "Philippe Rouquier",
+ 1);
+
+ /* First see if this plugin can be used */
+ result = brasero_process_check_path ("cdrecord", error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+
+ /* for recording */
+ input = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_PIPE|
+ BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_IMAGE_FORMAT_BIN);
+
+ /* cdrecord can burn all DVDs (except restricted) when it's ISOs */
+ output = brasero_caps_disc_new (dvd_media);
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (output);
+
+ /* All CD-R(W) */
+ output = brasero_caps_disc_new (media);
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (input);
+
+ input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_PIPE|
+ BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_AUDIO_FORMAT_RAW|
+ BRASERO_AUDIO_FORMAT_44100|
+ BRASERO_METADATA_INFO);
+
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (input);
+
+ input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_PIPE|
+ BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_AUDIO_FORMAT_RAW|
+ BRASERO_AUDIO_FORMAT_44100);
+
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (output);
+ g_slist_free (input);
+
+ /* for CLONE and CUE type images, we only want blank CD-R(W) */
+ output = brasero_caps_disc_new (BRASERO_MEDIUM_CD|
+ BRASERO_MEDIUM_WRITABLE|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_BLANK);
+
+ input = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_IMAGE_FORMAT_CUE|
+ BRASERO_IMAGE_FORMAT_CLONE);
+
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (output);
+ g_slist_free (input);
+
+ /* Blank CD(R)W : don't use standard flags cdrecord fails consistently
+ * to write a first track of a multisession disc with DAO mode. */
+ brasero_plugin_set_flags (plugin,
+ BRASERO_MEDIUM_CD|
+ BRASERO_MEDIUM_WRITABLE|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_BLANK,
+ BRASERO_BURN_FLAG_DAO|
+ BRASERO_BURN_FLAG_BURNPROOF|
+ BRASERO_BURN_FLAG_OVERBURN|
+ BRASERO_BURN_FLAG_DUMMY|
+ BRASERO_BURN_FLAG_NOGRACE,
+ BRASERO_BURN_FLAG_NONE);
+
+ brasero_plugin_set_flags (plugin,
+ BRASERO_MEDIUM_CD|
+ BRASERO_MEDIUM_WRITABLE|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_BLANK,
+ BRASERO_BURN_FLAG_MULTI|
+ BRASERO_BURN_FLAG_BURNPROOF|
+ BRASERO_BURN_FLAG_OVERBURN|
+ BRASERO_BURN_FLAG_DUMMY|
+ BRASERO_BURN_FLAG_NOGRACE,
+ BRASERO_BURN_FLAG_NONE);
+
+ /* Apart from DAO it also supports RAW mode to burn CLONE images. This
+ * is a special mode for which there isn't any DUMMY burn possible */
+ brasero_plugin_set_flags (plugin,
+ BRASERO_MEDIUM_CD|
+ BRASERO_MEDIUM_WRITABLE|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_BLANK,
+ BRASERO_BURN_FLAG_RAW|
+ BRASERO_BURN_FLAG_BURNPROOF|
+ BRASERO_BURN_FLAG_OVERBURN|
+ BRASERO_BURN_FLAG_NOGRACE,
+ BRASERO_BURN_FLAG_NONE);
+
+ /* This is a CDR with data data can be merged or at least appended */
+ brasero_plugin_set_flags (plugin,
+ BRASERO_MEDIUM_CD|
+ BRASERO_MEDIUM_WRITABLE|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_HAS_AUDIO|
+ BRASERO_MEDIUM_HAS_DATA,
+ BRASERO_BURN_FLAG_APPEND|
+ BRASERO_BURN_FLAG_MERGE|
+ BRASERO_BURN_FLAG_BURNPROOF|
+ BRASERO_BURN_FLAG_OVERBURN|
+ BRASERO_BURN_FLAG_MULTI|
+ BRASERO_BURN_FLAG_DUMMY|
+ BRASERO_BURN_FLAG_NOGRACE,
+ BRASERO_BURN_FLAG_APPEND);
+
+ /* It is a CDRW we want the CD to be either blanked before or appended
+ * that's why we set MERGE as compulsory. That way if the CD is not
+ * MERGED we force the blank before writing to avoid appending sessions
+ * endlessly until there is no free space. */
+ brasero_plugin_set_flags (plugin,
+ BRASERO_MEDIUM_CD|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_HAS_AUDIO|
+ BRASERO_MEDIUM_HAS_DATA,
+ BRASERO_BURN_FLAG_APPEND|
+ BRASERO_BURN_FLAG_MERGE|
+ BRASERO_BURN_FLAG_BURNPROOF|
+ BRASERO_BURN_FLAG_OVERBURN|
+ BRASERO_BURN_FLAG_MULTI|
+ BRASERO_BURN_FLAG_DUMMY|
+ BRASERO_BURN_FLAG_NOGRACE,
+ BRASERO_BURN_FLAG_MERGE);
+
+ /* DVD-RW cdrecord capabilites are limited to blank media.
+ * It should not start a multisession disc. */
+ brasero_plugin_set_flags (plugin,
+ BRASERO_MEDIUM_DVD|
+ BRASERO_MEDIUM_SEQUENTIAL|
+ BRASERO_MEDIUM_WRITABLE|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_BLANK,
+ BRASERO_BURN_FLAG_DAO|
+ BRASERO_BURN_FLAG_BURNPROOF|
+ BRASERO_BURN_FLAG_OVERBURN|
+ BRASERO_BURN_FLAG_DUMMY|
+ BRASERO_BURN_FLAG_NOGRACE,
+ BRASERO_BURN_FLAG_NONE);
+
+ /* DVD+W cdrecord capabilities are limited to blank media */
+ brasero_plugin_set_flags (plugin,
+ BRASERO_MEDIUM_DVDR_PLUS|
+ BRASERO_MEDIUM_BLANK,
+ BRASERO_BURN_FLAG_DAO|
+ BRASERO_BURN_FLAG_BURNPROOF|
+ BRASERO_BURN_FLAG_OVERBURN|
+ BRASERO_BURN_FLAG_NOGRACE,
+ BRASERO_BURN_FLAG_NONE);
+
+ /* for DVD+RW cdrecord capabilities are limited no MERGE */
+ brasero_plugin_set_flags (plugin,
+ BRASERO_MEDIUM_DVDRW_PLUS|
+ BRASERO_MEDIUM_UNFORMATTED|
+ BRASERO_MEDIUM_BLANK,
+ BRASERO_BURN_FLAG_OVERBURN|
+ BRASERO_BURN_FLAG_NOGRACE,
+ BRASERO_BURN_FLAG_NONE);
+
+ brasero_plugin_set_flags (plugin,
+ BRASERO_MEDIUM_DVDRW_PLUS|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_CLOSED|
+ BRASERO_MEDIUM_HAS_DATA,
+ BRASERO_BURN_FLAG_OVERBURN|
+ BRASERO_BURN_FLAG_NOGRACE,
+ BRASERO_BURN_FLAG_NONE);
+
+ /* blanking/formatting caps and flags for +/sequential RW
+ * NOTE: restricted overwrite DVD-RW can't be formatted.
+ * moreover DVD+RW are formatted while DVD-RW sequential are blanked.
+ */
+ output = brasero_caps_disc_new (BRASERO_MEDIUM_DVD|
+ BRASERO_MEDIUM_PLUS|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_SEQUENTIAL|
+ BRASERO_MEDIUM_CLOSED|
+ BRASERO_MEDIUM_HAS_DATA|
+ BRASERO_MEDIUM_UNFORMATTED|
+ BRASERO_MEDIUM_BLANK);
+ brasero_plugin_blank_caps (plugin, output);
+ g_slist_free (output);
+
+ brasero_plugin_set_blank_flags (plugin,
+ BRASERO_MEDIUM_DVDRW |
+ BRASERO_MEDIUM_BLANK|
+ BRASERO_MEDIUM_CLOSED |
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_HAS_DATA|
+ BRASERO_MEDIUM_UNFORMATTED,
+ BRASERO_BURN_FLAG_NOGRACE|
+ BRASERO_BURN_FLAG_FAST_BLANK,
+ BRASERO_BURN_FLAG_NONE);
+ /* again DVD+RW don't support dummy */
+ brasero_plugin_set_blank_flags (plugin,
+ BRASERO_MEDIUM_DVDRW_PLUS|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_HAS_DATA|
+ BRASERO_MEDIUM_UNFORMATTED|
+ BRASERO_MEDIUM_BLANK|
+ BRASERO_MEDIUM_CLOSED,
+ BRASERO_BURN_FLAG_NOGRACE,
+ BRASERO_BURN_FLAG_NONE);
+
+ /* for blanking (CDRWs) */
+ output = brasero_caps_disc_new (media_rw);
+ brasero_plugin_blank_caps (plugin, output);
+ g_slist_free (output);
+
+ brasero_plugin_set_blank_flags (plugin,
+ media_rw,
+ BRASERO_BURN_FLAG_NOGRACE|
+ BRASERO_BURN_FLAG_FAST_BLANK,
+ BRASERO_BURN_FLAG_NONE);
+
+ /* add some configure options */
+ immed = brasero_plugin_conf_option_new (GCONF_KEY_IMMEDIATE_FLAG,
+ _("Enable \"-immed\" flag (see cdrecord manual)"),
+ BRASERO_PLUGIN_OPTION_BOOL);
+ minbuf = brasero_plugin_conf_option_new (GCONF_KEY_MINBUF_VALUE,
+ _("Minimum drive buffer fill ratio (in %%)(see cdrecord manual):"),
+ BRASERO_PLUGIN_OPTION_INT);
+ brasero_plugin_conf_option_int_set_range (minbuf, 25, 95);
+
+ brasero_plugin_conf_option_bool_add_suboption (immed, minbuf);
+ brasero_plugin_add_conf_option (plugin, immed);
+
+ brasero_plugin_register_group (plugin, _(CDRTOOLS_DESCRIPTION));
+
+ return BRASERO_BURN_OK;
+}
diff --git a/plugins/cdrtools/burn-cdrecord.h b/plugins/cdrtools/burn-cdrecord.h
new file mode 100644
index 0000000..3c9719e
--- /dev/null
+++ b/plugins/cdrtools/burn-cdrecord.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ * cdrecord.h
+ *
+ * dim jan 22 15:22:52 2006
+ * Copyright 2006 Rouquier Philippe
+ * brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef CDRECORD_H
+#define CDRECORD_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_CD_RECORD (brasero_cdrecord_get_type ())
+#define BRASERO_CD_RECORD(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_CD_RECORD, BraseroCDRecord))
+#define BRASERO_CD_RECORD_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_CD_RECORD, BraseroCDRecordClass))
+#define BRASERO_IS_CD_RECORD(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_CD_RECORD))
+#define BRASERO_IS_CD_RECORD_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_CD_RECORD))
+#define BRASERO_CD_RECORD_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_CD_RECORD, BraseroCDRecordClass))
+
+G_END_DECLS
+
+#endif /* CDRECORD_H */
diff --git a/plugins/cdrtools/burn-cdrtools.h b/plugins/cdrtools/burn-cdrtools.h
new file mode 100644
index 0000000..a21abb4
--- /dev/null
+++ b/plugins/cdrtools/burn-cdrtools.h
@@ -0,0 +1,39 @@
+/***************************************************************************
+ * burn-cdrtools.h
+ *
+ * Mon Oct 29 12:27:57 2007
+ * Copyright 2007 Philippe Rouquier
+ * <bonfire-app wanadoo fr>
+ ****************************************************************************/
+
+/*
+ * Libbrasero-media is free software; you can redistribute it and/or modify
+fy
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA
+ */
+
+#ifndef _BURN_CDRTOOLS_H
+#define _BURN_CDRTOOLS_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define CDRTOOLS_DESCRIPTION N_("Cdrtools burning suite")
+
+G_END_DECLS
+
+#endif /* _BURN_CDRTOOLS_H */
+
+
diff --git a/plugins/cdrtools/burn-mkisofs.c b/plugins/cdrtools/burn-mkisofs.c
new file mode 100644
index 0000000..2d2b146
--- /dev/null
+++ b/plugins/cdrtools/burn-mkisofs.c
@@ -0,0 +1,586 @@
+/***************************************************************************
+ * mkisofs.c
+ *
+ * dim jan 22 15:20:57 2006
+ * Copyright 2006 Rouquier Philippe
+ * bonfire-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+#include <gmodule.h>
+
+#include "burn-debug.h"
+#include "burn-job.h"
+#include "burn-process.h"
+#include "brasero-plugin-registration.h"
+#include "burn-cdrtools.h"
+#include "burn-mkisofs.h"
+#include "brasero-track-data.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroMkisofs, brasero_mkisofs, BRASERO_TYPE_PROCESS, BraseroProcess);
+
+struct _BraseroMkisofsPrivate {
+ guint use_utf8:1;
+};
+typedef struct _BraseroMkisofsPrivate BraseroMkisofsPrivate;
+
+#define BRASERO_MKISOFS_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_MKISOFS, BraseroMkisofsPrivate))
+static GObjectClass *parent_class = NULL;
+
+static BraseroBurnResult
+brasero_mkisofs_read_isosize (BraseroProcess *process, const gchar *line)
+{
+ gint64 sectors;
+
+ sectors = strtoll (line, NULL, 10);
+ if (!sectors)
+ return BRASERO_BURN_OK;
+
+ /* mkisofs reports blocks of 2048 bytes */
+ brasero_job_set_output_size_for_current_track (BRASERO_JOB (process),
+ sectors,
+ sectors * 2048ULL);
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_mkisofs_read_stdout (BraseroProcess *process, const gchar *line)
+{
+ BraseroJobAction action;
+
+ brasero_job_get_action (BRASERO_JOB (process), &action);
+ if (action == BRASERO_JOB_ACTION_SIZE)
+ return brasero_mkisofs_read_isosize (process, line);
+
+ return TRUE;
+}
+
+static BraseroBurnResult
+brasero_mkisofs_read_stderr (BraseroProcess *process, const gchar *line)
+{
+ gchar fraction_str [7] = { 0, };
+ BraseroMkisofs *mkisofs;
+ BraseroMkisofsPrivate *priv;
+
+ mkisofs = BRASERO_MKISOFS (process);
+ priv = BRASERO_MKISOFS_PRIVATE (process);
+
+ if (strstr (line, "estimate finish")
+ && sscanf (line, "%6c%% done, estimate finish", fraction_str) == 1) {
+ gdouble fraction;
+
+ fraction = g_strtod (fraction_str, NULL) / (gdouble) 100.0;
+ brasero_job_set_progress (BRASERO_JOB (mkisofs), fraction);
+ brasero_job_start_progress (BRASERO_JOB (process), FALSE);
+ }
+ else if (strstr (line, "Input/output error. Read error on old image")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new_literal (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_IMAGE_LAST_SESSION,
+ _("Last session import failed")));
+ }
+ else if (strstr (line, "Unable to sort directory")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new_literal (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_WRITE_IMAGE,
+ _("An image could not be created")));
+ }
+ else if (strstr (line, "have the same joliet name")
+ || strstr (line, "Joliet tree sort failed.")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new_literal (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_IMAGE_JOLIET,
+ _("An image could not be created")));
+ }
+ else if (strstr (line, "Use mkisofs -help")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new_literal (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("This version of mkisofs is not supported")));
+ }
+/* else if ((pos = strstr (line,"mkisofs: Permission denied. "))) {
+ int res = FALSE;
+ gboolean isdir = FALSE;
+ char *path = NULL;
+
+ pos += strlen ("mkisofs: Permission denied. ");
+ if (!strncmp (pos, "Unable to open directory ", 24)) {
+ isdir = TRUE;
+
+ pos += strlen ("Unable to open directory ");
+ path = g_strdup (pos);
+ path[strlen (path) - 1] = 0;
+ }
+ else if (!strncmp (pos, "File ", 5)) {
+ char *end;
+
+ isdir = FALSE;
+ pos += strlen ("File ");
+ end = strstr (pos, " is not readable - ignoring");
+ if (end)
+ path = g_strndup (pos, end - pos);
+ }
+ else
+ return TRUE;
+
+ res = brasero_mkisofs_base_ask_unreadable_file (BRASERO_GENISOIMAGE_BASE (process),
+ path,
+ isdir);
+ if (!res) {
+ g_free (path);
+
+ brasero_job_progress_changed (BRASERO_JOB (process), 1.0, -1);
+ brasero_job_cancel (BRASERO_JOB (process), FALSE);
+ return FALSE;
+ }
+ }*/
+ else if (strstr (line, "Incorrectly encoded string")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new_literal (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_INPUT_INVALID,
+ _("Some files have invalid filenames")));
+ }
+ else if (strstr (line, "Unknown charset")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new_literal (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_INPUT_INVALID,
+ _("Unknown character encoding")));
+ }
+ else if (strstr (line, "No space left on device")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new_literal (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_DISK_SPACE,
+ _("There is no space left on the device")));
+
+ }
+ else if (strstr (line, "Unable to open disc image file")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new_literal (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_PERMISSION,
+ _("You do not have the required permission to write at this location")));
+
+ }
+ else if (strstr (line, "Value too large for defined data type")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new_literal (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_MEDIUM_SPACE,
+ _("Not enough space available on the disc")));
+ }
+
+ /** REMINDER: these should not be necessary
+
+ else if (strstr (line, "Resource temporarily unavailable")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new_literal (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_INPUT,
+ _("Data could not be written")));
+ }
+ else if (strstr (line, "Bad file descriptor.")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new_literal (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_INPUT,
+ _("Internal error: bad file descriptor")));
+ }
+
+ **/
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_mkisofs_set_argv_image (BraseroMkisofs *mkisofs,
+ GPtrArray *argv,
+ GError **error)
+{
+ gchar *label = NULL;
+ BraseroTrack *track;
+ BraseroBurnFlag flags;
+ gchar *videodir = NULL;
+ gchar *emptydir = NULL;
+ BraseroJobAction action;
+ BraseroImageFS image_fs;
+ BraseroBurnResult result;
+ gchar *grafts_path = NULL;
+ gchar *excluded_path = NULL;
+
+ /* set argv */
+ g_ptr_array_add (argv, g_strdup ("-r"));
+
+ result = brasero_job_get_current_track (BRASERO_JOB (mkisofs), &track);
+ if (result != BRASERO_BURN_OK)
+ BRASERO_JOB_NOT_READY (mkisofs);
+
+ image_fs = brasero_track_data_get_fs (BRASERO_TRACK_DATA (track));
+ if (image_fs & BRASERO_IMAGE_FS_JOLIET)
+ g_ptr_array_add (argv, g_strdup ("-J"));
+
+ if ((image_fs & BRASERO_IMAGE_FS_ISO)
+ && (image_fs & BRASERO_IMAGE_ISO_FS_LEVEL_3)) {
+ g_ptr_array_add (argv, g_strdup ("-iso-level"));
+ g_ptr_array_add (argv, g_strdup ("3"));
+ }
+
+ if (image_fs & BRASERO_IMAGE_FS_UDF)
+ g_ptr_array_add (argv, g_strdup ("-udf"));
+
+ if (image_fs & BRASERO_IMAGE_FS_VIDEO) {
+ g_ptr_array_add (argv, g_strdup ("-dvd-video"));
+
+ result = brasero_job_get_tmp_dir (BRASERO_JOB (mkisofs),
+ &videodir,
+ error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+ }
+
+ g_ptr_array_add (argv, g_strdup ("-graft-points"));
+
+ if (image_fs & BRASERO_IMAGE_ISO_FS_DEEP_DIRECTORY)
+ g_ptr_array_add (argv, g_strdup ("-D")); // This is dangerous the manual says but apparently it works well
+
+ result = brasero_job_get_tmp_file (BRASERO_JOB (mkisofs),
+ NULL,
+ &grafts_path,
+ error);
+ if (result != BRASERO_BURN_OK) {
+ g_free (videodir);
+ return result;
+ }
+
+ result = brasero_job_get_tmp_file (BRASERO_JOB (mkisofs),
+ NULL,
+ &excluded_path,
+ error);
+ if (result != BRASERO_BURN_OK) {
+ g_free (grafts_path);
+ g_free (videodir);
+ return result;
+ }
+
+ result = brasero_job_get_tmp_dir (BRASERO_JOB (mkisofs),
+ &emptydir,
+ error);
+ if (result != BRASERO_BURN_OK) {
+ g_free (videodir);
+ g_free (grafts_path);
+ g_free (excluded_path);
+ return result;
+ }
+
+ result = brasero_track_data_get_paths (BRASERO_TRACK_DATA (track),
+ (image_fs & BRASERO_IMAGE_FS_JOLIET) != 0,
+ grafts_path,
+ excluded_path,
+ emptydir,
+ videodir,
+ error);
+ g_free (emptydir);
+
+ if (result != BRASERO_BURN_OK) {
+ g_free (videodir);
+ g_free (grafts_path);
+ g_free (excluded_path);
+ return result;
+ }
+
+ g_ptr_array_add (argv, g_strdup ("-path-list"));
+ g_ptr_array_add (argv, grafts_path);
+
+ g_ptr_array_add (argv, g_strdup ("-exclude-list"));
+ g_ptr_array_add (argv, excluded_path);
+
+ brasero_job_get_data_label (BRASERO_JOB (mkisofs), &label);
+ if (label) {
+ g_ptr_array_add (argv, g_strdup ("-V"));
+ g_ptr_array_add (argv, label);
+ }
+
+ g_ptr_array_add (argv, g_strdup ("-A"));
+ g_ptr_array_add (argv, g_strdup_printf ("Brasero-%i.%i.%i",
+ BRASERO_MAJOR_VERSION,
+ BRASERO_MINOR_VERSION,
+ BRASERO_SUB));
+
+ g_ptr_array_add (argv, g_strdup ("-sysid"));
+#if defined(HAVE_STRUCT_USCSI_CMD)
+ g_ptr_array_add (argv, g_strdup ("SOLARIS"));
+#else
+ g_ptr_array_add (argv, g_strdup ("LINUX"));
+#endif
+
+ /* FIXME! -sort is an interesting option allowing to decide where the
+ * files are written on the disc and therefore to optimize later reading */
+ /* FIXME: -hidden --hidden-list -hide-jolie -hide-joliet-list will allow to hide
+ * some files when we will display the contents of a disc we will want to merge */
+ /* FIXME: support preparer publisher options */
+
+ brasero_job_get_flags (BRASERO_JOB (mkisofs), &flags);
+ if (flags & (BRASERO_BURN_FLAG_APPEND|BRASERO_BURN_FLAG_MERGE)) {
+ guint64 last_session = 0, next_wr_add = 0;
+ gchar *startpoint = NULL;
+
+ brasero_job_get_last_session_address (BRASERO_JOB (mkisofs), &last_session);
+ brasero_job_get_next_writable_address (BRASERO_JOB (mkisofs), &next_wr_add);
+ if (last_session == -1 || next_wr_add == -1) {
+ g_free (videodir);
+ BRASERO_JOB_LOG (mkisofs, "Failed to get the start point of the track. Make sure the media allow to add files (it is not closed)");
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("An internal error occured"));
+ return BRASERO_BURN_ERR;
+ }
+
+ startpoint = g_strdup_printf ("%"G_GINT64_FORMAT",%"G_GINT64_FORMAT,
+ last_session,
+ next_wr_add);
+
+ g_ptr_array_add (argv, g_strdup ("-C"));
+ g_ptr_array_add (argv, startpoint);
+
+ if (flags & BRASERO_BURN_FLAG_MERGE) {
+ gchar *device = NULL;
+
+ g_ptr_array_add (argv, g_strdup ("-M"));
+
+#ifdef HAVE_CAM_LIB_H
+ /* FreeBSD like that better */
+ brasero_job_get_bus_target_lun (BRASERO_JOB (mkisofs), &device);
+#else
+ brasero_job_get_device (BRASERO_JOB (mkisofs), &device);
+#endif
+
+ g_ptr_array_add (argv, device);
+ }
+ }
+
+ brasero_job_get_action (BRASERO_JOB (mkisofs), &action);
+ if (action == BRASERO_JOB_ACTION_SIZE) {
+ g_ptr_array_add (argv, g_strdup ("-quiet"));
+ g_ptr_array_add (argv, g_strdup ("-print-size"));
+
+ brasero_job_set_current_action (BRASERO_JOB (mkisofs),
+ BRASERO_BURN_ACTION_GETTING_SIZE,
+ NULL,
+ FALSE);
+ brasero_job_start_progress (BRASERO_JOB (mkisofs), FALSE);
+
+ if (videodir) {
+ g_ptr_array_add (argv, g_strdup ("-f"));
+ g_ptr_array_add (argv, videodir);
+ }
+
+ return BRASERO_BURN_OK;
+ }
+
+ if (brasero_job_get_fd_out (BRASERO_JOB (mkisofs), NULL) != BRASERO_BURN_OK) {
+ gchar *output = NULL;
+
+ result = brasero_job_get_image_output (BRASERO_JOB (mkisofs),
+ &output,
+ NULL);
+ if (result != BRASERO_BURN_OK) {
+ g_free (videodir);
+ return result;
+ }
+
+ g_ptr_array_add (argv, g_strdup ("-o"));
+ g_ptr_array_add (argv, output);
+ }
+
+ if (videodir) {
+ g_ptr_array_add (argv, g_strdup ("-f"));
+ g_ptr_array_add (argv, videodir);
+ }
+
+ brasero_job_set_current_action (BRASERO_JOB (mkisofs),
+ BRASERO_BURN_ACTION_CREATING_IMAGE,
+ NULL,
+ FALSE);
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_mkisofs_set_argv (BraseroProcess *process,
+ GPtrArray *argv,
+ GError **error)
+{
+ gchar *prog_name;
+ BraseroJobAction action;
+ BraseroMkisofs *mkisofs;
+ BraseroBurnResult result;
+ BraseroMkisofsPrivate *priv;
+
+ mkisofs = BRASERO_MKISOFS (process);
+ priv = BRASERO_MKISOFS_PRIVATE (process);
+
+ prog_name = g_find_program_in_path ("mkisofs");
+ if (prog_name && g_file_test (prog_name, G_FILE_TEST_IS_EXECUTABLE))
+ g_ptr_array_add (argv, prog_name);
+ else
+ g_ptr_array_add (argv, g_strdup ("mkisofs"));
+
+ if (priv->use_utf8) {
+ g_ptr_array_add (argv, g_strdup ("-input-charset"));
+ g_ptr_array_add (argv, g_strdup ("utf8"));
+ }
+
+ brasero_job_get_action (BRASERO_JOB (mkisofs), &action);
+ if (action == BRASERO_JOB_ACTION_SIZE)
+ result = brasero_mkisofs_set_argv_image (mkisofs, argv, error);
+ else if (action == BRASERO_JOB_ACTION_IMAGE)
+ result = brasero_mkisofs_set_argv_image (mkisofs, argv, error);
+ else
+ BRASERO_JOB_NOT_SUPPORTED (mkisofs);
+
+ return result;
+}
+
+static void
+brasero_mkisofs_class_init (BraseroMkisofsClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ BraseroProcessClass *process_class = BRASERO_PROCESS_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (BraseroMkisofsPrivate));
+
+ parent_class = g_type_class_peek_parent(klass);
+ object_class->finalize = brasero_mkisofs_finalize;
+
+ process_class->stdout_func = brasero_mkisofs_read_stdout;
+ process_class->stderr_func = brasero_mkisofs_read_stderr;
+ process_class->set_argv = brasero_mkisofs_set_argv;
+}
+
+static void
+brasero_mkisofs_init (BraseroMkisofs *obj)
+{
+ BraseroMkisofsPrivate *priv;
+ gchar *standard_error;
+ gboolean res;
+
+ priv = BRASERO_MKISOFS_PRIVATE (obj);
+
+ /* this code used to be ncb_mkisofs_supports_utf8 */
+ res = g_spawn_command_line_sync ("mkisofs -input-charset utf8",
+ NULL,
+ &standard_error,
+ NULL,
+ NULL);
+
+ if (res && !g_strrstr (standard_error, "Unknown charset"))
+ priv->use_utf8 = TRUE;
+ else
+ priv->use_utf8 = FALSE;
+
+ g_free (standard_error);
+}
+
+static void
+brasero_mkisofs_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static BraseroBurnResult
+brasero_mkisofs_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+ BraseroBurnResult result;
+ GSList *output;
+ GSList *input;
+
+ brasero_plugin_define (plugin,
+ "mkisofs",
+ _("Use mkisofs to create image from a file selection"),
+ "Philippe Rouquier",
+ 0);
+
+ /* First see if this plugin can be used */
+ result = brasero_process_check_path ("mkisofs", error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+
+ brasero_plugin_set_flags (plugin,
+ BRASERO_MEDIUM_CDR|
+ BRASERO_MEDIUM_CDRW|
+ BRASERO_MEDIUM_DVDR|
+ BRASERO_MEDIUM_DVDRW|
+ BRASERO_MEDIUM_DVDR_PLUS|
+ BRASERO_MEDIUM_DUAL_L|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_HAS_AUDIO|
+ BRASERO_MEDIUM_HAS_DATA,
+ BRASERO_BURN_FLAG_APPEND|
+ BRASERO_BURN_FLAG_MERGE,
+ BRASERO_BURN_FLAG_NONE);
+
+ brasero_plugin_set_flags (plugin,
+ BRASERO_MEDIUM_DUAL_L|
+ BRASERO_MEDIUM_DVDRW_PLUS|
+ BRASERO_MEDIUM_RESTRICTED|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_CLOSED|
+ BRASERO_MEDIUM_HAS_DATA,
+ BRASERO_BURN_FLAG_APPEND|
+ BRASERO_BURN_FLAG_MERGE,
+ BRASERO_BURN_FLAG_NONE);
+
+ /* Caps */
+ output = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE|
+ BRASERO_PLUGIN_IO_ACCEPT_PIPE,
+ BRASERO_IMAGE_FORMAT_BIN);
+
+ input = brasero_caps_data_new (BRASERO_IMAGE_FS_ISO|
+ BRASERO_IMAGE_FS_UDF|
+ BRASERO_IMAGE_ISO_FS_LEVEL_3|
+ BRASERO_IMAGE_ISO_FS_DEEP_DIRECTORY|
+ BRASERO_IMAGE_FS_JOLIET|
+ BRASERO_IMAGE_FS_VIDEO);
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (input);
+
+ input = brasero_caps_data_new (BRASERO_IMAGE_FS_ISO|
+ BRASERO_IMAGE_ISO_FS_LEVEL_3|
+ BRASERO_IMAGE_ISO_FS_DEEP_DIRECTORY|
+ BRASERO_IMAGE_FS_SYMLINK);
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (input);
+
+ g_slist_free (output);
+
+ brasero_plugin_register_group (plugin, _(CDRTOOLS_DESCRIPTION));
+
+ return BRASERO_BURN_OK;
+}
diff --git a/plugins/cdrtools/burn-mkisofs.h b/plugins/cdrtools/burn-mkisofs.h
new file mode 100644
index 0000000..c853f00
--- /dev/null
+++ b/plugins/cdrtools/burn-mkisofs.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+ * mkisofs.h
+ *
+ * dim jan 22 15:20:57 2006
+ * Copyright 2006 Rouquier Philippe
+ * brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef MKISOFS_H
+#define MKISOFS_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "burn-process.h"
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_MKISOFS (brasero_mkisofs_get_type ())
+#define BRASERO_MKISOFS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_MKISOFS, BraseroMkisofs))
+#define BRASERO_MKISOFS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_MKISOFS, BraseroMkisofsClass))
+#define BRASERO_IS_MKISOFS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_MKISOFS))
+#define BRASERO_IS_MKISOFS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_MKISOFS))
+#define BRASERO_MKISOFS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_MKISOFS, BraseroMkisofsClass))
+
+G_END_DECLS
+
+#endif /* MKISOFS_H */
diff --git a/plugins/cdrtools/burn-readcd.c b/plugins/cdrtools/burn-readcd.c
new file mode 100644
index 0000000..072d60c
--- /dev/null
+++ b/plugins/cdrtools/burn-readcd.c
@@ -0,0 +1,496 @@
+/***************************************************************************
+ * readcd.c
+ *
+ * dim jan 22 18:06:10 2006
+ * Copyright 2006 Rouquier Philippe
+ * brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+#include <gmodule.h>
+
+#include "burn-cdrtools.h"
+#include "burn-readcd.h"
+#include "burn-process.h"
+#include "burn-job.h"
+#include "brasero-plugin-registration.h"
+#include "brasero-tags.h"
+#include "brasero-track-disc.h"
+
+#include "burn-volume.h"
+#include "brasero-drive.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroReadcd, brasero_readcd, BRASERO_TYPE_PROCESS, BraseroProcess);
+static GObjectClass *parent_class = NULL;
+
+static BraseroBurnResult
+brasero_readcd_read_stderr (BraseroProcess *process, const gchar *line)
+{
+ BraseroReadcd *readcd;
+ gint dummy1;
+ gint dummy2;
+ gchar *pos;
+
+ readcd = BRASERO_READCD (process);
+
+ if ((pos = strstr (line, "addr:"))) {
+ gint sector;
+ gint64 written;
+ BraseroImageFormat format;
+ BraseroTrackType *output = NULL;
+
+ pos += strlen ("addr:");
+ sector = strtoll (pos, NULL, 10);
+
+ output = brasero_track_type_new ();
+ brasero_job_get_output_type (BRASERO_JOB (readcd), output);
+
+ format = brasero_track_type_get_image_format (output);
+ if (format == BRASERO_IMAGE_FORMAT_BIN)
+ written = (gint64) ((gint64) sector * 2048ULL);
+ else if (format == BRASERO_IMAGE_FORMAT_CLONE)
+ written = (gint64) ((gint64) sector * 2448ULL);
+ else
+ written = (gint64) ((gint64) sector * 2048ULL);
+
+ brasero_track_type_free (output);
+
+ brasero_job_set_written_track (BRASERO_JOB (readcd), written);
+
+ if (sector > 10)
+ brasero_job_start_progress (BRASERO_JOB (readcd), FALSE);
+ }
+ else if ((pos = strstr (line, "Capacity:"))) {
+ brasero_job_set_current_action (BRASERO_JOB (readcd),
+ BRASERO_BURN_ACTION_DRIVE_COPY,
+ NULL,
+ FALSE);
+ }
+ else if (strstr (line, "Device not ready.")) {
+ brasero_job_error (BRASERO_JOB (readcd),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_DRIVE_BUSY,
+ _("The drive is busy")));
+ }
+ else if (strstr (line, "Cannot open SCSI driver.")) {
+ brasero_job_error (BRASERO_JOB (readcd),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_PERMISSION,
+ _("You do not have the required permissions to use this drive")));
+ }
+ else if (strstr (line, "Cannot send SCSI cmd via ioctl")) {
+ brasero_job_error (BRASERO_JOB (readcd),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_PERMISSION,
+ _("You do not have the required permissions to use this drive")));
+ }
+ /* we scan for this error as in this case readcd returns success */
+ else if (sscanf (line, "Input/output error. Error on sector %d not corrected. Total of %d error", &dummy1, &dummy2) == 2) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("An internal error occured")));
+ }
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_readcd_argv_set_iso_boundary (BraseroReadcd *readcd,
+ GPtrArray *argv,
+ GError **error)
+{
+ guint64 nb_blocks;
+ BraseroTrack *track;
+ GValue *value = NULL;
+ BraseroTrackType *output = NULL;
+
+ brasero_job_get_current_track (BRASERO_JOB (readcd), &track);
+
+ output = brasero_track_type_new ();
+ brasero_job_get_output_type (BRASERO_JOB (readcd), output);
+
+ brasero_track_tag_lookup (track,
+ BRASERO_TRACK_MEDIUM_ADDRESS_START_TAG,
+ &value);
+ if (value) {
+ guint64 start, end;
+
+ /* we were given an address to start */
+ start = g_value_get_uint64 (value);
+
+ /* get the length now */
+ value = NULL;
+ brasero_track_tag_lookup (track,
+ BRASERO_TRACK_MEDIUM_ADDRESS_END_TAG,
+ &value);
+
+ end = g_value_get_uint64 (value);
+
+ BRASERO_JOB_LOG (readcd,
+ "reading from sector %lli to %lli",
+ start,
+ end);
+ g_ptr_array_add (argv, g_strdup_printf ("-sectors=%lli-%lli",
+ start,
+ end));
+ }
+ /* 0 means all disc, -1 problem */
+ else if (brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track)) > 0) {
+ guint64 start;
+ BraseroDrive *drive;
+ BraseroMedium *medium;
+
+ drive = brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track));
+ medium = brasero_drive_get_medium (drive);
+ brasero_medium_get_track_space (medium,
+ brasero_track_disc_get_track_num (BRASERO_TRACK_DISC (track)),
+ NULL,
+ &nb_blocks);
+ brasero_medium_get_track_address (medium,
+ brasero_track_disc_get_track_num (BRASERO_TRACK_DISC (track)),
+ NULL,
+ &start);
+
+ BRASERO_JOB_LOG (readcd,
+ "reading %i from sector %lli to %lli",
+ brasero_track_disc_get_track_num (BRASERO_TRACK_DISC (track)),
+ start,
+ start + nb_blocks);
+ g_ptr_array_add (argv, g_strdup_printf ("-sectors=%lli-%lli",
+ start,
+ start + nb_blocks));
+ }
+ /* if it's BIN output just read the last track */
+ else if (brasero_track_type_get_image_format (output) == BRASERO_IMAGE_FORMAT_BIN) {
+ guint64 start;
+ BraseroDrive *drive;
+ BraseroMedium *medium;
+
+ drive = brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track));
+ medium = brasero_drive_get_medium (drive);
+ brasero_medium_get_last_data_track_space (medium,
+ NULL,
+ &nb_blocks);
+ brasero_medium_get_last_data_track_address (medium,
+ NULL,
+ &start);
+ BRASERO_JOB_LOG (readcd,
+ "reading last track from sector %lli to %lli",
+ start,
+ start + nb_blocks);
+ g_ptr_array_add (argv, g_strdup_printf ("-sectors=%lli-%lli",
+ start,
+ start + nb_blocks));
+ }
+ else {
+ brasero_track_get_size (track, &nb_blocks, NULL);
+ g_ptr_array_add (argv, g_strdup_printf ("-sectors=0-%lli", nb_blocks));
+ }
+
+ brasero_track_type_free (output);
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_readcd_get_size (BraseroReadcd *self,
+ GError **error)
+{
+ guint64 blocks;
+ GValue *value = NULL;
+ BraseroImageFormat format;
+ BraseroTrack *track = NULL;
+ BraseroTrackType *output = NULL;
+
+ brasero_job_get_current_track (BRASERO_JOB (self), &track);
+
+ output = brasero_track_type_new ();
+ brasero_job_get_output_type (BRASERO_JOB (self), output);
+
+ if (!brasero_track_type_get_has_image (output)) {
+ brasero_track_type_free (output);
+ return BRASERO_BURN_ERR;
+ }
+
+ brasero_track_type_free (output);
+
+ format = brasero_track_type_get_image_format (output);
+ brasero_track_tag_lookup (track,
+ BRASERO_TRACK_MEDIUM_ADDRESS_START_TAG,
+ &value);
+
+ if (value) {
+ guint64 start, end;
+
+ /* we were given an address to start */
+ start = g_value_get_uint64 (value);
+
+ /* get the length now */
+ value = NULL;
+ brasero_track_tag_lookup (track,
+ BRASERO_TRACK_MEDIUM_ADDRESS_END_TAG,
+ &value);
+
+ end = g_value_get_uint64 (value);
+ blocks = end - start;
+ }
+ else if (brasero_track_disc_get_track_num (BRASERO_TRACK_DISC (track)) > 0) {
+ BraseroDrive *drive;
+ BraseroMedium *medium;
+
+ drive = brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track));
+ medium = brasero_drive_get_medium (drive);
+ brasero_medium_get_track_space (medium,
+ brasero_track_disc_get_track_num (BRASERO_TRACK_DISC (track)),
+ NULL,
+ &blocks);
+ }
+ else if (format == BRASERO_IMAGE_FORMAT_BIN) {
+ BraseroDrive *drive;
+ BraseroMedium *medium;
+
+ drive = brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track));
+ medium = brasero_drive_get_medium (drive);
+ brasero_medium_get_last_data_track_space (medium,
+ NULL,
+ &blocks);
+ }
+ else
+ brasero_track_get_size (track, &blocks, NULL);
+
+ if (format == BRASERO_IMAGE_FORMAT_BIN) {
+ brasero_job_set_output_size_for_current_track (BRASERO_JOB (self),
+ blocks,
+ blocks * 2048ULL);
+ }
+ else if (format == BRASERO_IMAGE_FORMAT_CLONE) {
+ brasero_job_set_output_size_for_current_track (BRASERO_JOB (self),
+ blocks,
+ blocks * 2448ULL);
+ }
+ else
+ return BRASERO_BURN_NOT_SUPPORTED;
+
+ /* no need to go any further */
+ return BRASERO_BURN_NOT_RUNNING;
+}
+
+static BraseroBurnResult
+brasero_readcd_set_argv (BraseroProcess *process,
+ GPtrArray *argv,
+ GError **error)
+{
+ BraseroBurnResult result = FALSE;
+ BraseroTrackType *output = NULL;
+ BraseroImageFormat format;
+ BraseroJobAction action;
+ BraseroReadcd *readcd;
+ BraseroMedium *medium;
+ BraseroTrack *track;
+ BraseroDrive *drive;
+ BraseroMedia media;
+ gchar *outfile_arg;
+ gchar *dev_str;
+ gchar *device;
+
+ readcd = BRASERO_READCD (process);
+
+ /* This is a kind of shortcut */
+ brasero_job_get_action (BRASERO_JOB (process), &action);
+ if (action == BRASERO_JOB_ACTION_SIZE)
+ return brasero_readcd_get_size (readcd, error);
+
+ g_ptr_array_add (argv, g_strdup ("readcd"));
+
+ brasero_job_get_current_track (BRASERO_JOB (readcd), &track);
+ drive = brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track));
+
+#ifdef HAVE_CAM_LIB_H
+ /* FreeBSD like that better */
+ device = brasero_drive_get_bus_target_lun_string (drive);
+#else
+ device = g_strdup (brasero_drive_get_device (drive));
+#endif
+
+ if (!device)
+ return BRASERO_BURN_ERR;
+
+ dev_str = g_strdup_printf ("dev=%s", device);
+ g_ptr_array_add (argv, dev_str);
+ g_free (device);
+
+ g_ptr_array_add (argv, g_strdup ("-nocorr"));
+
+ medium = brasero_drive_get_medium (drive);
+ media = brasero_medium_get_status (medium);
+
+ output = brasero_track_type_new ();
+ brasero_job_get_output_type (BRASERO_JOB (readcd), output);
+ format = brasero_track_type_get_image_format (output);
+ brasero_track_type_free (output);
+
+ if ((media & BRASERO_MEDIUM_DVD) && format != BRASERO_IMAGE_FORMAT_BIN) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("An internal error occured"));
+ return BRASERO_BURN_ERR;
+ }
+
+ if (format == BRASERO_IMAGE_FORMAT_CLONE) {
+ /* NOTE: with this option the sector size is 2448
+ * because it is raw96 (2352+96) otherwise it is 2048 */
+ g_ptr_array_add (argv, g_strdup ("-clone"));
+ }
+ else if (format == BRASERO_IMAGE_FORMAT_BIN) {
+ g_ptr_array_add (argv, g_strdup ("-noerror"));
+
+ /* don't do it for clone since we need the entire disc */
+ result = brasero_readcd_argv_set_iso_boundary (readcd, argv, error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+ }
+ else
+ BRASERO_JOB_NOT_SUPPORTED (readcd);
+
+ if (brasero_job_get_fd_out (BRASERO_JOB (readcd), NULL) != BRASERO_BURN_OK) {
+ gchar *image;
+
+ if (format != BRASERO_IMAGE_FORMAT_CLONE
+ && format != BRASERO_IMAGE_FORMAT_BIN)
+ BRASERO_JOB_NOT_SUPPORTED (readcd);
+
+ result = brasero_job_get_image_output (BRASERO_JOB (readcd),
+ &image,
+ NULL);
+ if (result != BRASERO_BURN_OK)
+ return result;
+
+ outfile_arg = g_strdup_printf ("-f=%s", image);
+ g_ptr_array_add (argv, outfile_arg);
+ g_free (image);
+ }
+ else if (format == BRASERO_IMAGE_FORMAT_BIN) {
+ outfile_arg = g_strdup ("-f=-");
+ g_ptr_array_add (argv, outfile_arg);
+ }
+ else /* unfortunately raw images can't be piped out */
+ BRASERO_JOB_NOT_SUPPORTED (readcd);
+
+ brasero_job_set_use_average_rate (BRASERO_JOB (process), TRUE);
+ return BRASERO_BURN_OK;
+}
+
+static void
+brasero_readcd_class_init (BraseroReadcdClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ BraseroProcessClass *process_class = BRASERO_PROCESS_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+ object_class->finalize = brasero_readcd_finalize;
+
+ process_class->stderr_func = brasero_readcd_read_stderr;
+ process_class->set_argv = brasero_readcd_set_argv;
+}
+
+static void
+brasero_readcd_init (BraseroReadcd *obj)
+{ }
+
+static void
+brasero_readcd_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static BraseroBurnResult
+brasero_readcd_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+ BraseroBurnResult result;
+ GSList *output;
+ GSList *input;
+
+ brasero_plugin_define (plugin,
+ "readcd",
+ _("Use readcd to create disc images"),
+ "Philippe Rouquier",
+ 0);
+
+ /* First see if this plugin can be used */
+ result = brasero_process_check_path ("readcd", error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+
+ /* that's for clone mode only The only one to copy audio */
+ output = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_IMAGE_FORMAT_CLONE);
+
+ input = brasero_caps_disc_new (BRASERO_MEDIUM_CD|
+ BRASERO_MEDIUM_ROM|
+ BRASERO_MEDIUM_WRITABLE|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_CLOSED|
+ BRASERO_MEDIUM_HAS_AUDIO|
+ BRASERO_MEDIUM_HAS_DATA);
+
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (output);
+ g_slist_free (input);
+
+ /* that's for regular mode: it accepts the previous type of discs
+ * plus the DVDs types as well */
+ output = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE|
+ BRASERO_PLUGIN_IO_ACCEPT_PIPE,
+ BRASERO_IMAGE_FORMAT_BIN);
+
+ input = brasero_caps_disc_new (BRASERO_MEDIUM_CD|
+ BRASERO_MEDIUM_DVD|
+ BRASERO_MEDIUM_DUAL_L|
+ BRASERO_MEDIUM_PLUS|
+ BRASERO_MEDIUM_SEQUENTIAL|
+ BRASERO_MEDIUM_RESTRICTED|
+ BRASERO_MEDIUM_ROM|
+ BRASERO_MEDIUM_WRITABLE|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_CLOSED|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_HAS_DATA);
+
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (output);
+ g_slist_free (input);
+
+ brasero_plugin_register_group (plugin, _(CDRTOOLS_DESCRIPTION));
+
+ return BRASERO_BURN_OK;
+}
diff --git a/plugins/cdrtools/burn-readcd.h b/plugins/cdrtools/burn-readcd.h
new file mode 100644
index 0000000..730d3ae
--- /dev/null
+++ b/plugins/cdrtools/burn-readcd.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+ * readcd.h
+ *
+ * dim jan 22 18:06:10 2006
+ * Copyright 2006 Rouquier Philippe
+ * brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef READCD_H
+#define READCD_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "burn-process.h"
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_READCD (brasero_readcd_get_type ())
+#define BRASERO_READCD(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_READCD, BraseroReadcd))
+#define BRASERO_READCD_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_READCD, BraseroReadcdClass))
+#define BRASERO_IS_READCD(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_READCD))
+#define BRASERO_IS_READCD_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_READCD))
+#define BRASERO_READCD_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_READCD, BraseroReadcdClass))
+
+G_END_DECLS
+
+#endif /* READCD_H */
diff --git a/plugins/checksum/Makefile.am b/plugins/checksum/Makefile.am
new file mode 100644
index 0000000..b3269a3
--- /dev/null
+++ b/plugins/checksum/Makefile.am
@@ -0,0 +1,34 @@
+
+INCLUDES = \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/libbrasero-media/ \
+ -I$(top_builddir)/libbrasero-media/ \
+ -I$(top_srcdir)/libbrasero-burn \
+ -I$(top_builddir)/libbrasero-burn/ \
+ -DBRASERO_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
+ -DBRASERO_PREFIX=\"$(prefix)\" \
+ -DBRASERO_SYSCONFDIR=\"$(sysconfdir)\" \
+ -DBRASERO_DATADIR=\"$(datadir)/brasero\" \
+ -DBRASERO_LIBDIR=\"$(libdir)\" \
+ $(DISABLE_DEPRECATED) \
+ $(BRASERO_GLIB_CFLAGS) \
+ $(BRASERO_GTK_CFLAGS) \
+ $(BRASERO_GCONF_CFLAGS)
+
+checksumdir = $(libdir)/brasero/plugins
+checksum_LTLIBRARIES = libbrasero-checksum.la
+libbrasero_checksum_la_SOURCES = burn-checksum-image.c \
+ burn-checksum-image.h
+
+libbrasero_checksum_la_LDFLAGS = -module -avoid-version
+libbrasero_checksum_la_LIBADD = $(BRASERO_GLIB_LIBS) $(BRASERO_GCONF_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+
+checksumfiledir = $(libdir)/brasero/plugins
+checksumfile_LTLIBRARIES = libbrasero-checksum-file.la
+libbrasero_checksum_file_la_SOURCES = burn-checksum-files.c \
+ burn-checksum-files.h\
+ burn-volume-read.c \
+ burn-volume-read.h
+
+libbrasero_checksum_file_la_LDFLAGS = -module -avoid-version
+libbrasero_checksum_file_la_LIBADD = $(BRASERO_GLIB_LIBS) $(BRASERO_GCONF_LIBS) $(BRASERO_GTK_LIBS) ../../libbrasero-burn/libbrasero-burn.la
diff --git a/plugins/checksum/burn-checksum-files.c b/plugins/checksum/burn-checksum-files.c
new file mode 100644
index 0000000..02a8cd9
--- /dev/null
+++ b/plugins/checksum/burn-checksum-files.c
@@ -0,0 +1,1506 @@
+/***************************************************************************
+ * burn-sum.c
+ *
+ * ven aoû 4 19:46:34 2006
+ * Copyright 2006 Rouquier Philippe
+ * brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/param.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+
+#include <gmodule.h>
+
+#include <gconf/gconf-client.h>
+
+#include "scsi-device.h"
+#include "brasero-plugin-registration.h"
+#include "burn-job.h"
+#include "burn-checksum-files.h"
+
+#include "brasero-tags.h"
+#include "brasero-track-data.h"
+#include "brasero-track-disc.h"
+
+#include "burn-volume.h"
+#include "brasero-drive.h"
+#include "brasero-volume.h"
+
+#include "burn-volume-read.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroChecksumFiles, brasero_checksum_files, BRASERO_TYPE_JOB, BraseroJob);
+
+struct _BraseroChecksumFilesPrivate {
+ /* the path to read from when we check */
+ gchar *sums_path;
+ BraseroChecksumType checksum_type;
+
+ gint64 file_num;
+
+ /* the FILE to write to when we generate */
+ FILE *file;
+
+ /* this is for the thread and the end of it */
+ GThread *thread;
+ GMutex *mutex;
+ GCond *cond;
+ gint end_id;
+
+ guint cancel;
+};
+typedef struct _BraseroChecksumFilesPrivate BraseroChecksumFilesPrivate;
+
+#define BRASERO_CHECKSUM_FILES_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_CHECKSUM_FILES, BraseroChecksumFilesPrivate))
+
+#define BLOCK_SIZE 64
+#define GCONF_KEY_CHECKSUM_TYPE "/apps/brasero/config/checksum_files"
+
+static BraseroJobClass *parent_class = NULL;
+
+static BraseroBurnResult
+brasero_checksum_files_get_file_checksum (BraseroChecksumFiles *self,
+ GChecksumType type,
+ const gchar *path,
+ gchar **checksum_string,
+ GError **error)
+{
+ BraseroChecksumFilesPrivate *priv;
+ guchar buffer [BLOCK_SIZE];
+ GChecksum *checksum;
+ gint read_bytes;
+ FILE *file;
+
+ priv = BRASERO_CHECKSUM_FILES_PRIVATE (self);
+
+ file = fopen (path, "r");
+ if (!file) {
+ int errsv;
+ gchar *name = NULL;
+
+ /* If the file doesn't exist carry on with next */
+ if (errno == ENOENT)
+ return BRASERO_BURN_RETRY;
+
+ name = g_path_get_basename (path);
+
+ errsv = errno;
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("File \"%s\" could not be opened (%s)"),
+ name,
+ g_strerror (errsv));
+ g_free (name);
+
+ return BRASERO_BURN_ERR;
+ }
+
+ checksum = g_checksum_new (type);
+
+ read_bytes = fread (buffer, 1, BLOCK_SIZE, file);
+ g_checksum_update (checksum, buffer, read_bytes);
+
+ while (read_bytes == BLOCK_SIZE) {
+ if (priv->cancel) {
+ fclose (file);
+ g_checksum_free (checksum);
+ return BRASERO_BURN_CANCEL;
+ }
+
+ read_bytes = fread (buffer, 1, BLOCK_SIZE, file);
+ g_checksum_update (checksum, buffer, read_bytes);
+ }
+
+ *checksum_string = g_strdup (g_checksum_get_string (checksum));
+ g_checksum_free (checksum);
+ fclose (file);
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_checksum_files_add_file_checksum (BraseroChecksumFiles *self,
+ const gchar *path,
+ GChecksumType checksum_type,
+ const gchar *graft_path,
+ GError **error)
+{
+ BraseroBurnResult result = BRASERO_BURN_OK;
+ BraseroChecksumFilesPrivate *priv;
+ gchar *checksum_string = NULL;
+ gint written;
+
+ priv = BRASERO_CHECKSUM_FILES_PRIVATE (self);
+
+ /* write to the file */
+ result = brasero_checksum_files_get_file_checksum (self,
+ checksum_type,
+ path,
+ &checksum_string,
+ error);
+ if (result != BRASERO_BURN_OK)
+ return BRASERO_BURN_ERR;
+
+ written = fwrite (checksum_string,
+ strlen (checksum_string),
+ 1,
+ priv->file);
+ g_free (checksum_string);
+
+ if (written != 1) {
+ int errsv = errno;
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("Data could not be written (%s)"),
+ g_strerror (errsv));
+
+ return BRASERO_BURN_ERR;
+ }
+
+ written = fwrite (" ",
+ 2,
+ 1,
+ priv->file);
+
+ /* NOTE: we remove the first "/" from path so the file can be
+ * used with md5sum at the root of the disc once mounted */
+ written = fwrite (graft_path + 1,
+ strlen (graft_path + 1),
+ 1,
+ priv->file);
+
+ if (written != 1) {
+ int errsv = errno;
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("Data could not be written (%s)"),
+ g_strerror (errsv));
+
+ return BRASERO_BURN_ERR;
+ }
+
+ written = fwrite ("\n",
+ 1,
+ 1,
+ priv->file);
+
+ return result;
+}
+
+static BraseroBurnResult
+brasero_checksum_files_explore_directory (BraseroChecksumFiles *self,
+ GChecksumType checksum_type,
+ gint64 file_nb,
+ const gchar *directory,
+ const gchar *disc_path,
+ GHashTable *excludedH,
+ GError **error)
+{
+ BraseroBurnResult result = BRASERO_BURN_OK;
+ BraseroChecksumFilesPrivate *priv;
+ const gchar *name;
+ GDir *dir;
+
+ priv = BRASERO_CHECKSUM_FILES_PRIVATE (self);
+
+ dir = g_dir_open (directory, 0, error);
+ if (!dir || *error)
+ return BRASERO_BURN_ERR;
+
+ while ((name = g_dir_read_name (dir))) {
+ gchar *path;
+ gchar *graft_path;
+
+ if (priv->cancel) {
+ result = BRASERO_BURN_CANCEL;
+ break;
+ }
+
+ path = g_build_path (G_DIR_SEPARATOR_S, directory, name, NULL);
+ if (g_hash_table_lookup (excludedH, path)) {
+ g_free (path);
+ continue;
+ }
+
+ graft_path = g_build_path (G_DIR_SEPARATOR_S, disc_path, name, NULL);
+ if (g_file_test (path, G_FILE_TEST_IS_DIR)) {
+ result = brasero_checksum_files_explore_directory (self,
+ checksum_type,
+ file_nb,
+ path,
+ graft_path,
+ excludedH,
+ error);
+ g_free (path);
+ g_free (graft_path);
+
+ if (result != BRASERO_BURN_OK)
+ break;
+
+ continue;
+ }
+
+ /* Only checksum regular files and avoid fifos, ... */
+ if (!g_file_test (path, G_FILE_TEST_IS_REGULAR)) {
+ g_free (path);
+ g_free (graft_path);
+ continue;
+ }
+
+ result = brasero_checksum_files_add_file_checksum (self,
+ path,
+ checksum_type,
+ graft_path,
+ error);
+ g_free (graft_path);
+ g_free (path);
+
+ if (result != BRASERO_BURN_OK)
+ break;
+
+ priv->file_num ++;
+ brasero_job_set_progress (BRASERO_JOB (self),
+ (gdouble) priv->file_num /
+ (gdouble) file_nb);
+ }
+ g_dir_close (dir);
+
+ /* NOTE: we don't care if the file is twice or more on the disc,
+ * that would be too much overhead/memory consumption for something
+ * that scarcely happens and that way each file can be checked later*/
+
+ return result;
+}
+
+static BraseroBurnResult
+brasero_checksum_file_process_former_line (BraseroChecksumFiles *self,
+ BraseroTrack *track,
+ const gchar *line,
+ GError **error)
+{
+ guint i;
+ gchar *path;
+ GSList *grafts;
+ guint written_bytes;
+ BraseroChecksumFilesPrivate *priv;
+
+ priv = BRASERO_CHECKSUM_FILES_PRIVATE (self);
+
+ /* first skip the checksum string */
+ i = 0;
+ while (!isspace (line [i])) i ++;
+
+ /* skip white spaces */
+ while (isspace (line [i])) i ++;
+
+ /* get the path string */
+ path = g_strdup (line + i);
+
+ for (grafts = brasero_track_data_get_grafts (BRASERO_TRACK_DATA (track)); grafts; grafts = grafts->next) {
+ BraseroGraftPt *graft;
+ guint len;
+
+ /* NOTE: graft->path + 1 is because in the checksum files on the
+ * disc there is not first "/" so if we want to compare ... */
+ graft = grafts->data;
+ if (!strcmp (graft->path + 1, path)) {
+ g_free (path);
+ return BRASERO_BURN_OK;
+ }
+
+ len = strlen (graft->path + 1);
+ if (!strncmp (graft->path + 1, path, len)
+ && path [len] == G_DIR_SEPARATOR) {
+ g_free (path);
+ return BRASERO_BURN_OK;
+ }
+ }
+
+ g_free (path);
+
+ /* write the whole line in the new file */
+ written_bytes = fwrite (line, 1, strlen (line), priv->file);
+ if (written_bytes != strlen (line)) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ "%s",
+ g_strerror (errno));
+ return BRASERO_BURN_ERR;
+ }
+
+ if (!fwrite ("\n", 1, 1, priv->file)) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ "%s",
+ g_strerror (errno));
+ return BRASERO_BURN_ERR;
+ }
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_checksum_files_merge_with_former_session (BraseroChecksumFiles *self,
+ GError **error)
+{
+ BraseroBurnFlag flags = BRASERO_BURN_FLAG_NONE;
+ BraseroChecksumFilesPrivate *priv;
+ BraseroDeviceHandle *dev_handle;
+ BraseroVolFileHandle *handle;
+ BraseroBurnResult result;
+ BraseroVolFile *file;
+ BraseroTrack *track;
+ gchar buffer [2048];
+ BraseroVolSrc *vol;
+ guint64 start_block;
+ gchar *device;
+
+ priv = BRASERO_CHECKSUM_FILES_PRIVATE (self);
+
+ /* Now we need to know if we're merging. If so, we need to merge the
+ * former checksum file with the new ones. */
+ brasero_job_get_flags (BRASERO_JOB (self), &flags);
+ if (!(flags & BRASERO_BURN_FLAG_MERGE))
+ return BRASERO_BURN_OK;
+
+ /* get the former file */
+ result = brasero_job_get_last_session_address (BRASERO_JOB (self), &start_block);
+ if (result != BRASERO_BURN_OK)
+ return result;
+
+ /* try every file and make sure they are of the same type */
+ brasero_job_get_device (BRASERO_JOB (self), &device);
+ dev_handle = brasero_device_handle_open (device, FALSE, NULL);
+ g_free (device);
+
+ vol = brasero_volume_source_open_device_handle (dev_handle, error);
+ file = brasero_volume_get_file (vol,
+ "/"BRASERO_MD5_FILE,
+ start_block,
+ NULL);
+
+ if (!file) {
+ file = brasero_volume_get_file (vol,
+ "/"BRASERO_SHA1_FILE,
+ start_block,
+ NULL);
+ if (!file) {
+ file = brasero_volume_get_file (vol,
+ "/"BRASERO_SHA256_FILE,
+ start_block,
+ NULL);
+ if (!file) {
+ brasero_volume_source_close (vol);
+ BRASERO_JOB_LOG (self, "no checksum file found");
+ return BRASERO_BURN_OK;
+ }
+ else if (priv->checksum_type != BRASERO_CHECKSUM_SHA256_FILE) {
+ brasero_volume_source_close (vol);
+ BRASERO_JOB_LOG (self, "checksum type mismatch (%i against %i)",
+ priv->checksum_type,
+ BRASERO_CHECKSUM_SHA256_FILE);
+ return BRASERO_BURN_OK;
+ }
+ }
+ else if (priv->checksum_type != BRASERO_CHECKSUM_SHA1_FILE) {
+ BRASERO_JOB_LOG (self, "checksum type mismatch (%i against %i)",
+ priv->checksum_type,
+ BRASERO_CHECKSUM_SHA1_FILE);
+ brasero_volume_source_close (vol);
+ return BRASERO_BURN_OK;
+ }
+ }
+ else if (priv->checksum_type != BRASERO_CHECKSUM_MD5_FILE) {
+ brasero_volume_source_close (vol);
+ BRASERO_JOB_LOG (self, "checksum type mismatch (%i against %i)",
+ priv->checksum_type,
+ BRASERO_CHECKSUM_MD5_FILE);
+ return BRASERO_BURN_OK;
+ }
+
+ BRASERO_JOB_LOG (self, "Found file %p", file);
+ handle = brasero_volume_file_open (vol, file);
+ brasero_volume_source_close (vol);
+
+ if (!handle) {
+ BRASERO_JOB_LOG (self, "Failed to open file");
+ brasero_device_handle_close (dev_handle);
+ brasero_volume_file_free (file);
+ return BRASERO_BURN_ERR;
+ }
+
+ brasero_job_get_current_track (BRASERO_JOB (self), &track);
+
+ /* Now check the files that have been replaced; to do that check the
+ * paths of the new image whenever a read path from former file is a
+ * child of one of the new paths, then it must not be included. */
+ result = brasero_volume_file_read_line (handle, buffer, sizeof (buffer));
+ while (result == BRASERO_BURN_RETRY) {
+ if (priv->cancel) {
+ brasero_volume_file_close (handle);
+ brasero_volume_file_free (file);
+ brasero_device_handle_close (dev_handle);
+ return BRASERO_BURN_CANCEL;
+ }
+
+ result = brasero_checksum_file_process_former_line (self,
+ track,
+ buffer,
+ error);
+ if (result != BRASERO_BURN_OK) {
+ brasero_volume_file_close (handle);
+ brasero_volume_file_free (file);
+ brasero_device_handle_close (dev_handle);
+ return result;
+ }
+
+ result = brasero_volume_file_read_line (handle, buffer, sizeof (buffer));
+ }
+
+ result = brasero_checksum_file_process_former_line (self, track, buffer, error);
+ brasero_volume_file_close (handle);
+ brasero_volume_file_free (file);
+ brasero_device_handle_close (dev_handle);
+
+ return result;
+}
+
+static BraseroBurnResult
+brasero_checksum_files_create_checksum (BraseroChecksumFiles *self,
+ GError **error)
+{
+ GSList *iter;
+ guint64 file_nb;
+ BraseroTrack *track;
+ GConfClient *client;
+ GHashTable *excludedH;
+ GChecksumType gchecksum_type;
+ BraseroChecksumFilesPrivate *priv;
+ BraseroChecksumType checksum_type;
+ BraseroBurnResult result = BRASERO_BURN_OK;
+
+ priv = BRASERO_CHECKSUM_FILES_PRIVATE (self);
+
+ /* get the checksum type */
+ client = gconf_client_get_default ();
+ checksum_type = gconf_client_get_int (client, GCONF_KEY_CHECKSUM_TYPE, NULL);
+ g_object_unref (client);
+
+ if (checksum_type == BRASERO_CHECKSUM_NONE)
+ gchecksum_type = G_CHECKSUM_MD5;
+ else if (checksum_type & BRASERO_CHECKSUM_MD5_FILE)
+ gchecksum_type = G_CHECKSUM_MD5;
+ else if (checksum_type & BRASERO_CHECKSUM_SHA1_FILE)
+ gchecksum_type = G_CHECKSUM_SHA1;
+ else if (checksum_type & BRASERO_CHECKSUM_SHA256_FILE)
+ gchecksum_type = G_CHECKSUM_SHA256;
+ else
+ gchecksum_type = G_CHECKSUM_MD5;
+
+ /* opens a file for the sums */
+ switch (gchecksum_type) {
+ case G_CHECKSUM_MD5:
+ priv->checksum_type = BRASERO_CHECKSUM_MD5_FILE;
+ result = brasero_job_get_tmp_file (BRASERO_JOB (self),
+ ".md5",
+ &priv->sums_path,
+ error);
+ break;
+ case G_CHECKSUM_SHA1:
+ priv->checksum_type = BRASERO_CHECKSUM_SHA1_FILE;
+ result = brasero_job_get_tmp_file (BRASERO_JOB (self),
+ ".sha1",
+ &priv->sums_path,
+ error);
+ break;
+ case G_CHECKSUM_SHA256:
+ priv->checksum_type = BRASERO_CHECKSUM_SHA256_FILE;
+ result = brasero_job_get_tmp_file (BRASERO_JOB (self),
+ ".sha256",
+ &priv->sums_path,
+ error);
+ break;
+ default:
+ result = BRASERO_BURN_CANCEL;
+ break;
+ }
+
+ if (result != BRASERO_BURN_OK || !priv->sums_path)
+ return result;
+
+ priv->file = fopen (priv->sums_path, "w");
+ if (!priv->file) {
+ int errsv = errno;
+
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("File \"%s\" could not be opened (%s)"),
+ priv->sums_path,
+ g_strerror (errsv));
+
+ return BRASERO_BURN_ERR;
+ }
+
+ if (brasero_job_get_current_track (BRASERO_JOB (self), &track) != BRASERO_BURN_OK)
+ BRASERO_JOB_NOT_SUPPORTED (self);
+
+ /* we fill a hash table with all the files that are excluded globally */
+ excludedH = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+ iter = brasero_track_data_get_excluded (BRASERO_TRACK_DATA (track), FALSE);
+ for (; iter; iter = iter->next) {
+ gchar *uri;
+ gchar *path;
+
+ /* get the path */
+ uri = iter->data;
+ path = g_filename_from_uri (uri, NULL, NULL);
+
+ if (path)
+ g_hash_table_insert (excludedH, path, path);
+ }
+
+ /* it's now time to start reporting our progress */
+ brasero_job_set_current_action (BRASERO_JOB (self),
+ BRASERO_BURN_ACTION_CHECKSUM,
+ _("Creating checksum for image files"),
+ TRUE);
+
+ file_nb = -1;
+ priv->file_num = 0;
+ brasero_track_data_get_file_num (BRASERO_TRACK_DATA (track), &file_nb);
+ if (file_nb > 0)
+ brasero_job_start_progress (BRASERO_JOB (self), TRUE);
+ else
+ file_nb = -1;
+
+ iter = brasero_track_data_get_grafts (BRASERO_TRACK_DATA (track));
+ for (; iter; iter = iter->next) {
+ BraseroGraftPt *graft;
+ gchar *graft_path;
+ gchar *path;
+
+ if (priv->cancel) {
+ result = BRASERO_BURN_CANCEL;
+ break;
+ }
+
+ graft = iter->data;
+ if (!graft->uri)
+ continue;
+
+ /* get the current and future paths */
+ /* FIXME: graft->uri can be path or URIs ... This should be
+ * fixed for graft points. */
+ if (!graft->uri)
+ path = NULL;
+ else if (graft->uri [0] == '/')
+ path = g_strdup (graft->uri);
+ else if (g_str_has_prefix (graft->uri, "file://"))
+ path = g_filename_from_uri (graft->uri, NULL, NULL);
+ else
+ path = NULL;
+
+ graft_path = graft->path;
+
+ if (g_file_test (path, G_FILE_TEST_IS_DIR))
+ result = brasero_checksum_files_explore_directory (self,
+ gchecksum_type,
+ file_nb,
+ path,
+ graft_path,
+ excludedH,
+ error);
+ else {
+ result = brasero_checksum_files_add_file_checksum (self,
+ path,
+ gchecksum_type,
+ graft_path,
+ error);
+ priv->file_num ++;
+ brasero_job_set_progress (BRASERO_JOB (self),
+ (gdouble) priv->file_num /
+ (gdouble) file_nb);
+ }
+
+ g_free (path);
+ if (result != BRASERO_BURN_OK)
+ break;
+ }
+
+ g_hash_table_destroy (excludedH);
+
+ if (result == BRASERO_BURN_OK)
+ result = brasero_checksum_files_merge_with_former_session (self, error);
+
+ /* that's finished we close the file */
+ fclose (priv->file);
+ priv->file = NULL;
+
+ return result;
+}
+
+static BraseroBurnResult
+brasero_checksum_files_sum_on_disc_file (BraseroChecksumFiles *self,
+ GChecksumType type,
+ BraseroVolSrc *src,
+ BraseroVolFile *file,
+ gchar **checksum_string,
+ GError **error)
+{
+ guchar buffer [64 * 2048];
+ BraseroChecksumFilesPrivate *priv;
+ BraseroVolFileHandle *handle;
+ GChecksum *checksum;
+ gint read_bytes;
+
+ priv = BRASERO_CHECKSUM_FILES_PRIVATE (self);
+
+ handle = brasero_volume_file_open_direct (src, file);
+ if (!handle)
+ return BRASERO_BURN_ERR;
+
+ checksum = g_checksum_new (type);
+
+ read_bytes = brasero_volume_file_read_direct (handle,
+ buffer,
+ 64);
+ g_checksum_update (checksum, buffer, read_bytes);
+
+ while (read_bytes == sizeof (buffer)) {
+ if (priv->cancel) {
+ brasero_volume_file_close (handle);
+ return BRASERO_BURN_CANCEL;
+ }
+
+ read_bytes = brasero_volume_file_read_direct (handle,
+ buffer,
+ 64);
+ g_checksum_update (checksum, buffer, read_bytes);
+ }
+
+ *checksum_string = g_strdup (g_checksum_get_string (checksum));
+ g_checksum_free (checksum);
+
+ brasero_volume_file_close (handle);
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroVolFile *
+brasero_checksum_files_get_on_disc_checksum_type (BraseroChecksumFiles *self,
+ BraseroVolSrc *vol,
+ guint start_block)
+{
+ BraseroVolFile *file;
+ BraseroChecksumFilesPrivate *priv;
+
+ priv = BRASERO_CHECKSUM_FILES_PRIVATE (self);
+
+
+ file = brasero_volume_get_file (vol,
+ "/"BRASERO_MD5_FILE,
+ start_block,
+ NULL);
+
+ if (!file) {
+ file = brasero_volume_get_file (vol,
+ "/"BRASERO_SHA1_FILE,
+ start_block,
+ NULL);
+ if (!file) {
+ file = brasero_volume_get_file (vol,
+ "/"BRASERO_SHA256_FILE,
+ start_block,
+ NULL);
+ if (!file || !(priv->checksum_type & (BRASERO_CHECKSUM_SHA256_FILE|BRASERO_CHECKSUM_DETECT))) {
+ BRASERO_JOB_LOG (self, "no checksum file found");
+ if (file)
+ brasero_volume_file_free (file);
+
+ return NULL;
+ }
+ priv->checksum_type = BRASERO_CHECKSUM_SHA256_FILE;
+ }
+ else if (priv->checksum_type & (BRASERO_CHECKSUM_SHA1_FILE|BRASERO_CHECKSUM_DETECT))
+ priv->checksum_type = BRASERO_CHECKSUM_SHA1_FILE;
+ else {
+ brasero_volume_file_free (file);
+ file = NULL;
+ }
+ }
+ else if (priv->checksum_type & (BRASERO_CHECKSUM_MD5_FILE|BRASERO_CHECKSUM_DETECT))
+ priv->checksum_type = BRASERO_CHECKSUM_MD5_FILE;
+ else {
+ brasero_volume_file_free (file);
+ file = NULL;
+ }
+
+ BRASERO_JOB_LOG (self, "Found file %p", file);
+ return file;
+}
+
+static gint
+brasero_checksum_files_get_line_num (BraseroChecksumFiles *self,
+ BraseroVolFileHandle *handle)
+{
+ BraseroBurnResult result;
+ int num = 0;
+
+ while ((result = brasero_volume_file_read_line (handle, NULL, 0)) == BRASERO_BURN_RETRY)
+ num ++;
+
+ if (result == BRASERO_BURN_ERR)
+ return -1;
+
+ brasero_volume_file_rewind (handle);
+ return num;
+}
+
+static BraseroBurnResult
+brasero_checksum_files_check_files (BraseroChecksumFiles *self,
+ GError **error)
+{
+ GValue *value;
+ guint file_nb;
+ guint file_num;
+ gint checksum_len;
+ BraseroVolSrc *vol;
+ guint64 start_block;
+ BraseroTrack *track;
+ const gchar *device;
+ BraseroVolFile *file;
+ BraseroDrive *drive;
+ BraseroMedium *medium;
+ BraseroVolFileHandle *handle;
+ GChecksumType gchecksum_type;
+ GArray *wrong_checksums = NULL;
+ BraseroDeviceHandle *dev_handle;
+ BraseroChecksumFilesPrivate *priv;
+ BraseroBurnResult result = BRASERO_BURN_OK;
+
+ priv = BRASERO_CHECKSUM_FILES_PRIVATE (self);
+
+ /* get medium */
+ brasero_job_get_current_track (BRASERO_JOB (self), &track);
+ drive = brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track));
+ medium = brasero_drive_get_medium (drive);
+
+ /* open volume */
+ if (!brasero_medium_get_last_data_track_address (medium, NULL, &start_block))
+ return BRASERO_BURN_ERR;
+
+ device = brasero_drive_get_device (brasero_medium_get_drive (medium));
+ dev_handle = brasero_device_handle_open (device, FALSE, NULL);
+ vol = brasero_volume_source_open_device_handle (dev_handle, error);
+
+ /* open checksum file */
+ file = brasero_checksum_files_get_on_disc_checksum_type (self,
+ vol,
+ start_block);
+ if (!file) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("No checksum file could be found on the disc"));
+
+ BRASERO_JOB_LOG (self, "No checksum file");
+ result = BRASERO_BURN_ERR;
+ goto end;
+ }
+
+ handle = brasero_volume_file_open (vol, file);
+ if (!handle) {
+ BRASERO_JOB_LOG (self, "Cannot open checksum file");
+ /* FIXME: error here ? */
+ result = BRASERO_BURN_ERR;
+ goto end;
+ }
+
+ /* get the number of files at this time and rewind */
+ file_nb = brasero_checksum_files_get_line_num (self, handle);
+ if (file_nb == 0) {
+ BRASERO_JOB_LOG (self, "Empty checksum file");
+ result = BRASERO_BURN_OK;
+ goto end;
+ }
+
+ if (file_nb < 0) {
+ /* An error here */
+ BRASERO_JOB_LOG (self, "Failed to retrieve the number of lines");
+ result = BRASERO_BURN_ERR;
+ goto end;
+ }
+
+ /* signal we're ready to start */
+ file_num = 0;
+ brasero_job_set_current_action (BRASERO_JOB (self),
+ BRASERO_BURN_ACTION_CHECKSUM,
+ _("Checking file integrity"),
+ TRUE);
+ brasero_job_start_progress (BRASERO_JOB (self), FALSE);
+
+ /* Get the checksum type */
+ switch (priv->checksum_type) {
+ case BRASERO_CHECKSUM_MD5_FILE:
+ gchecksum_type = G_CHECKSUM_MD5;
+ break;
+ case BRASERO_CHECKSUM_SHA1_FILE:
+ gchecksum_type = G_CHECKSUM_SHA1;
+ break;
+ case BRASERO_CHECKSUM_SHA256_FILE:
+ gchecksum_type = G_CHECKSUM_SHA256;
+ break;
+ default:
+ gchecksum_type = G_CHECKSUM_MD5;
+ break;
+ }
+
+ checksum_len = g_checksum_type_get_length (gchecksum_type) * 2;
+ while (1) {
+ gchar file_path [MAXPATHLEN + 1];
+ gchar checksum_file [512 + 1];
+ BraseroVolFile *disc_file;
+ gchar *checksum_real;
+ gint read_bytes;
+
+ if (priv->cancel)
+ break;
+
+ /* first read the checksum */
+ read_bytes = brasero_volume_file_read (handle,
+ checksum_file,
+ checksum_len);
+ if (read_bytes == 0)
+ break;
+
+ if (read_bytes != checksum_len) {
+ /* FIXME: an error here */
+ BRASERO_JOB_LOG (self, "Impossible to read the checksum from file");
+ result = BRASERO_BURN_ERR;
+ break;
+ }
+ checksum_file [checksum_len] = '\0';
+
+ if (priv->cancel)
+ break;
+
+ /* skip spaces in between */
+ while (1) {
+ gchar c [2];
+
+ read_bytes = brasero_volume_file_read (handle, c, 1);
+ if (read_bytes == 0) {
+ result = BRASERO_BURN_OK;
+ goto end;
+ }
+
+ if (read_bytes < 0) {
+ /* FIXME: an error here */
+ BRASERO_JOB_LOG (self, "Impossible to read checksum file");
+ result = BRASERO_BURN_ERR;
+ goto end;
+ }
+
+ if (!isspace (c [0])) {
+ file_path [0] = '/';
+ file_path [1] = c [0];
+ break;
+ }
+ }
+
+ /* get the filename */
+ result = brasero_volume_file_read_line (handle, file_path + 2, sizeof (file_path) - 2);
+
+ /* FIXME: an error here */
+ if (result == BRASERO_BURN_ERR) {
+ BRASERO_JOB_LOG (self, "Impossible to read checksum file");
+ break;
+ }
+
+ checksum_real = NULL;
+
+ /* get the file handle itself */
+ BRASERO_JOB_LOG (self, "Getting file %s", file_path);
+ disc_file = brasero_volume_get_file (vol,
+ file_path,
+ start_block,
+ NULL);
+ if (!disc_file) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("File \"%s\" could not be opened"),
+ file_path);
+ result = BRASERO_BURN_ERR;
+ break;
+ }
+
+ /* we certainly don't want to checksum anything but regular file
+ * if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
+ * brasero_volume_file_free (disc_file);
+ * continue;
+ * }
+ */
+
+ /* checksum the file */
+ result = brasero_checksum_files_sum_on_disc_file (self,
+ gchecksum_type,
+ vol,
+ disc_file,
+ &checksum_real,
+ error);
+ brasero_volume_file_free (disc_file);
+ if (result == BRASERO_BURN_ERR) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("File \"%s\" could not be opened"),
+ file_path);
+ break;
+ }
+
+ if (result != BRASERO_BURN_OK)
+ break;
+
+ file_num++;
+ brasero_job_set_progress (BRASERO_JOB (self),
+ (gdouble) file_num /
+ (gdouble) file_nb);
+ BRASERO_JOB_LOG (self,
+ "comparing checksums for file %s : %s (from md5 file) / %s (current)",
+ file_path, checksum_file, checksum_real);
+
+ if (strcmp (checksum_file, checksum_real)) {
+ gchar *string;
+
+ BRASERO_JOB_LOG (self, "Wrong checksum");
+ if (!wrong_checksums)
+ wrong_checksums = g_array_new (TRUE,
+ TRUE,
+ sizeof (gchar *));
+
+ string = g_strdup (file_path);
+ wrong_checksums = g_array_append_val (wrong_checksums, string);
+ }
+
+ g_free (checksum_real);
+ if (priv->cancel)
+ break;
+ }
+
+end:
+
+ if (handle)
+ brasero_volume_file_close (handle);
+
+ if (file)
+ brasero_volume_file_free (file);
+
+ if (vol)
+ brasero_volume_source_close (vol);
+
+ if (dev_handle)
+ brasero_device_handle_close (dev_handle);
+
+ if (result != BRASERO_BURN_OK) {
+ BRASERO_JOB_LOG (self, "Ended with an error");
+ if (wrong_checksums) {
+ g_strfreev ((gchar **) wrong_checksums->data);
+ g_array_free (wrong_checksums, FALSE);
+ }
+ return result;
+ }
+
+ if (!wrong_checksums)
+ return BRASERO_BURN_OK;
+
+ /* add the tag */
+ value = g_new0 (GValue, 1);
+ g_value_init (value, G_TYPE_STRV);
+ g_value_take_boxed (value, wrong_checksums->data);
+ g_array_free (wrong_checksums, FALSE);
+
+ brasero_track_tag_add (track,
+ BRASERO_TRACK_MEDIUM_WRONG_CHECKSUM_TAG,
+ value);
+
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_BAD_CHECKSUM,
+ _("Some files may be corrupted on the disc"));
+
+ return BRASERO_BURN_ERR;
+}
+
+struct _BraseroChecksumFilesThreadCtx {
+ BraseroChecksumFiles *sum;
+ BraseroBurnResult result;
+ GError *error;
+};
+typedef struct _BraseroChecksumFilesThreadCtx BraseroChecksumFilesThreadCtx;
+
+static gboolean
+brasero_checksum_files_end (gpointer data)
+{
+ BraseroJobAction action;
+ BraseroChecksumFiles *self;
+ BraseroTrack *current = NULL;
+ BraseroChecksumFilesPrivate *priv;
+ BraseroChecksumFilesThreadCtx *ctx;
+
+ ctx = data;
+ self = ctx->sum;
+ priv = BRASERO_CHECKSUM_FILES_PRIVATE (self);
+
+ /* NOTE ctx/data is destroyed in its own callback */
+ priv->end_id = 0;
+
+ if (ctx->result != BRASERO_BURN_OK) {
+ GError *error;
+
+ error = ctx->error;
+ ctx->error = NULL;
+
+ brasero_job_error (BRASERO_JOB (self), error);
+ return FALSE;
+ }
+
+ brasero_job_get_action (BRASERO_JOB (self), &action);
+ if (action == BRASERO_JOB_ACTION_CHECKSUM) {
+ /* everything was done in thread */
+ brasero_job_finished_track (BRASERO_JOB (self));
+ return FALSE;
+ }
+
+ /* we were asked to create a checksum. Its type depends on the input */
+ brasero_job_get_current_track (BRASERO_JOB (self), ¤t);
+
+ /* let's create a new DATA track with the md5 file created */
+ if (BRASERO_IS_TRACK_DATA (current)) {
+ GSList *grafts;
+ GSList *excluded;
+ BraseroGraftPt *graft;
+ GSList *new_grafts = NULL;
+ BraseroTrackData *track = NULL;
+
+ /* for DATA track we add the file to the track */
+ grafts = brasero_track_data_get_grafts (BRASERO_TRACK_DATA (current));
+ for (; grafts; grafts = grafts->next) {
+ graft = grafts->data;
+ graft = brasero_graft_point_copy (graft);
+ new_grafts = g_slist_prepend (new_grafts, graft);
+ }
+
+ graft = g_new0 (BraseroGraftPt, 1);
+ graft->uri = g_strconcat ("file://", priv->sums_path, NULL);
+ switch (priv->checksum_type) {
+ case BRASERO_CHECKSUM_SHA1_FILE:
+ graft->path = g_strdup ("/"BRASERO_SHA1_FILE);
+ break;
+ case BRASERO_CHECKSUM_SHA256_FILE:
+ graft->path = g_strdup ("/"BRASERO_SHA256_FILE);
+ break;
+ case BRASERO_CHECKSUM_MD5_FILE:
+ default:
+ graft->path = g_strdup ("/"BRASERO_MD5_FILE);
+ break;
+ }
+
+ BRASERO_JOB_LOG (self,
+ "Adding graft for checksum file %s %s",
+ graft->path,
+ graft->uri);
+
+ new_grafts = g_slist_prepend (new_grafts, graft);
+ excluded = brasero_track_data_get_excluded (BRASERO_TRACK_DATA (current), TRUE);
+
+ track = brasero_track_data_new ();
+ brasero_track_data_add_fs (track, brasero_track_data_get_fs (BRASERO_TRACK_DATA (current)));
+ brasero_track_data_set_source (track, new_grafts, excluded);
+ brasero_track_set_checksum (BRASERO_TRACK (track),
+ priv->checksum_type,
+ graft->uri);
+
+ brasero_job_add_track (BRASERO_JOB (self), BRASERO_TRACK (track));
+
+ /* It's good practice to unref the track afterwards as we don't
+ * need it anymore. BraseroTaskCtx refs it. */
+ g_object_unref (track);
+
+ brasero_job_finished_track (BRASERO_JOB (self));
+ return FALSE;
+ }
+ else
+ goto error;
+
+ return FALSE;
+
+error:
+{
+ GError *error = NULL;
+
+ error = g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_BAD_CHECKSUM,
+ _("Some files may be corrupted on the disc"));
+ brasero_job_error (BRASERO_JOB (self), error);
+ return FALSE;
+}
+}
+
+static void
+brasero_checksum_files_destroy (gpointer data)
+{
+ BraseroChecksumFilesThreadCtx *ctx;
+
+ ctx = data;
+ if (ctx->error) {
+ g_error_free (ctx->error);
+ ctx->error = NULL;
+ }
+
+ g_free (ctx);
+}
+
+static gpointer
+brasero_checksum_files_thread (gpointer data)
+{
+ GError *error = NULL;
+ BraseroJobAction action;
+ BraseroChecksumFiles *self;
+ BraseroTrack *current = NULL;
+ BraseroChecksumFilesPrivate *priv;
+ BraseroChecksumFilesThreadCtx *ctx;
+ BraseroBurnResult result = BRASERO_BURN_NOT_SUPPORTED;
+
+ self = BRASERO_CHECKSUM_FILES (data);
+ priv = BRASERO_CHECKSUM_FILES_PRIVATE (self);
+
+ /* check DISC types and add checksums for DATA and IMAGE-bin types */
+ brasero_job_get_action (BRASERO_JOB (self), &action);
+ brasero_job_get_current_track (BRASERO_JOB (self), ¤t);
+ if (action == BRASERO_JOB_ACTION_CHECKSUM) {
+ priv->checksum_type = brasero_track_get_checksum_type (current);
+ if (priv->checksum_type & (BRASERO_CHECKSUM_MD5_FILE|BRASERO_CHECKSUM_SHA1_FILE|BRASERO_CHECKSUM_SHA256_FILE|BRASERO_CHECKSUM_DETECT))
+ result = brasero_checksum_files_check_files (self, &error);
+ else
+ result = BRASERO_BURN_ERR;
+ }
+ else if (action == BRASERO_JOB_ACTION_IMAGE) {
+ if (BRASERO_IS_TRACK_DATA (current))
+ result = brasero_checksum_files_create_checksum (self, &error);
+ else
+ result = BRASERO_BURN_ERR;
+ }
+
+ if (result != BRASERO_BURN_CANCEL) {
+ ctx = g_new0 (BraseroChecksumFilesThreadCtx, 1);
+ ctx->sum = self;
+ ctx->error = error;
+ ctx->result = result;
+ priv->end_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE,
+ brasero_checksum_files_end,
+ ctx,
+ brasero_checksum_files_destroy);
+ }
+
+ /* End thread */
+ g_mutex_lock (priv->mutex);
+ priv->thread = NULL;
+ g_cond_signal (priv->cond);
+ g_mutex_unlock (priv->mutex);
+
+ g_thread_exit (NULL);
+ return NULL;
+}
+
+static BraseroBurnResult
+brasero_checksum_files_start (BraseroJob *job,
+ GError **error)
+{
+ BraseroChecksumFilesPrivate *priv;
+ GError *thread_error = NULL;
+ BraseroJobAction action;
+
+ brasero_job_get_action (job, &action);
+ if (action == BRASERO_JOB_ACTION_SIZE) {
+ /* say we won't write to disc */
+ brasero_job_set_output_size_for_current_track (job, 0, 0);
+ return BRASERO_BURN_NOT_RUNNING;
+ }
+
+ /* we start a thread for the exploration of the graft points */
+ priv = BRASERO_CHECKSUM_FILES_PRIVATE (job);
+ g_mutex_lock (priv->mutex);
+ priv->thread = g_thread_create (brasero_checksum_files_thread,
+ BRASERO_CHECKSUM_FILES (job),
+ TRUE,
+ &thread_error);
+ g_mutex_unlock (priv->mutex);
+
+ /* Reminder: this is not necessarily an error as the thread may have finished */
+ //if (!priv->thread)
+ // return BRASERO_BURN_ERR;
+ if (thread_error) {
+ g_propagate_error (error, thread_error);
+ return BRASERO_BURN_ERR;
+ }
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_checksum_files_activate (BraseroJob *job,
+ GError **error)
+{
+ GSList *grafts;
+ BraseroTrack *track = NULL;
+ BraseroTrackType *output = NULL;
+
+ output = brasero_track_type_new ();
+ brasero_job_get_output_type (job, output);
+
+ if (!brasero_track_type_get_has_data (output)) {
+ brasero_track_type_free (output);
+ return BRASERO_BURN_OK;
+ }
+
+ brasero_track_type_free (output);
+
+ /* see that a file with graft "/BRASERO_CHECKSUM_FILE" doesn't already
+ * exists (possible when doing several copies) or when a simulation
+ * already took place before. */
+ brasero_job_get_current_track (job, &track);
+ grafts = brasero_track_data_get_grafts (BRASERO_TRACK_DATA (track));
+ for (; grafts; grafts = grafts->next) {
+ BraseroGraftPt *graft;
+
+ graft = grafts->data;
+ if (graft->path) {
+ if (!strcmp (graft->path, "/"BRASERO_MD5_FILE))
+ return BRASERO_BURN_NOT_RUNNING;
+ if (!strcmp (graft->path, "/"BRASERO_SHA1_FILE))
+ return BRASERO_BURN_NOT_RUNNING;
+ if (!strcmp (graft->path, "/"BRASERO_SHA256_FILE))
+ return BRASERO_BURN_NOT_RUNNING;
+ }
+ }
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_checksum_files_clock_tick (BraseroJob *job)
+{
+ BraseroChecksumFilesPrivate *priv;
+
+ priv = BRASERO_CHECKSUM_FILES_PRIVATE (job);
+
+ /* we'll need that function later. For the moment, when generating a
+ * file we can't know how many files there are. Just when checking it */
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_checksum_files_stop (BraseroJob *job,
+ GError **error)
+{
+ BraseroChecksumFilesPrivate *priv;
+
+ priv = BRASERO_CHECKSUM_FILES_PRIVATE (job);
+
+ g_mutex_lock (priv->mutex);
+ if (priv->thread) {
+ priv->cancel = 1;
+ g_cond_wait (priv->cond, priv->mutex);
+ priv->cancel = 0;
+ priv->thread = NULL;
+ }
+ g_mutex_unlock (priv->mutex);
+
+ if (priv->end_id) {
+ g_source_remove (priv->end_id);
+ priv->end_id = 0;
+ }
+
+ if (priv->file) {
+ fclose (priv->file);
+ priv->file = NULL;
+ }
+
+ if (priv->sums_path) {
+ g_free (priv->sums_path);
+ priv->sums_path = NULL;
+ }
+
+ return BRASERO_BURN_OK;
+}
+
+static void
+brasero_checksum_files_init (BraseroChecksumFiles *obj)
+{
+ BraseroChecksumFilesPrivate *priv;
+
+ priv = BRASERO_CHECKSUM_FILES_PRIVATE (obj);
+
+ priv->mutex = g_mutex_new ();
+ priv->cond = g_cond_new ();
+}
+
+static void
+brasero_checksum_files_finalize (GObject *object)
+{
+ BraseroChecksumFilesPrivate *priv;
+
+ priv = BRASERO_CHECKSUM_FILES_PRIVATE (object);
+
+ g_mutex_lock (priv->mutex);
+ if (priv->thread) {
+ priv->cancel = 1;
+ g_cond_wait (priv->cond, priv->mutex);
+ priv->cancel = 0;
+ priv->thread = NULL;
+ }
+ g_mutex_unlock (priv->mutex);
+
+ if (priv->end_id) {
+ g_source_remove (priv->end_id);
+ priv->end_id = 0;
+ }
+
+ if (priv->file) {
+ fclose (priv->file);
+ priv->file = NULL;
+ }
+
+ if (priv->mutex) {
+ g_mutex_free (priv->mutex);
+ priv->mutex = NULL;
+ }
+
+ if (priv->cond) {
+ g_cond_free (priv->cond);
+ priv->cond = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+brasero_checksum_files_class_init (BraseroChecksumFilesClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ BraseroJobClass *job_class = BRASERO_JOB_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (BraseroChecksumFilesPrivate));
+
+ parent_class = g_type_class_peek_parent (klass);
+ object_class->finalize = brasero_checksum_files_finalize;
+
+ job_class->activate = brasero_checksum_files_activate;
+ job_class->start = brasero_checksum_files_start;
+ job_class->stop = brasero_checksum_files_stop;
+ job_class->clock_tick = brasero_checksum_files_clock_tick;
+}
+
+static BraseroBurnResult
+brasero_checksum_files_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+ GSList *input;
+ BraseroPluginConfOption *checksum_type;
+
+ brasero_plugin_define (plugin,
+ /* Translators: this is the name of the plugin
+ * which will be translated only when it needs
+ * displaying. */
+ N_("File Checksum"),
+ _("Allows to check file integrities on a disc"),
+ "Philippe Rouquier",
+ 0);
+
+ /* we can only generate a file for DATA input */
+ input = brasero_caps_data_new (BRASERO_IMAGE_FS_ANY);
+ brasero_plugin_process_caps (plugin, input);
+ g_slist_free (input);
+
+ /* we can run on initial track or later for whatever a DATA track */
+ brasero_plugin_set_process_flags (plugin,
+ BRASERO_PLUGIN_RUN_PREPROCESSING|
+ BRASERO_PLUGIN_RUN_BEFORE_TARGET);
+
+ /* For discs, we can only check each files on a disc against an md5sum
+ * file (provided we managed to mount the disc).
+ * NOTE: we can't generate md5 from discs anymore. There are too many
+ * problems reading straight from the disc dev. So we use readcd or
+ * equivalent instead */
+ input = brasero_caps_disc_new (BRASERO_MEDIUM_CD|
+ BRASERO_MEDIUM_DVD|
+ BRASERO_MEDIUM_DUAL_L|
+ BRASERO_MEDIUM_PLUS|
+ BRASERO_MEDIUM_RESTRICTED|
+ BRASERO_MEDIUM_SEQUENTIAL|
+ BRASERO_MEDIUM_WRITABLE|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_CLOSED|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_HAS_DATA);
+ brasero_plugin_check_caps (plugin,
+ BRASERO_CHECKSUM_DETECT|
+ BRASERO_CHECKSUM_MD5_FILE|
+ BRASERO_CHECKSUM_SHA1_FILE|
+ BRASERO_CHECKSUM_SHA256_FILE,
+ input);
+ g_slist_free (input);
+
+ /* add some configure options */
+ checksum_type = brasero_plugin_conf_option_new (GCONF_KEY_CHECKSUM_TYPE,
+ _("Hashing algorithm to be used:"),
+ BRASERO_PLUGIN_OPTION_CHOICE);
+ brasero_plugin_conf_option_choice_add (checksum_type,
+ _("MD5"), BRASERO_CHECKSUM_MD5_FILE);
+ brasero_plugin_conf_option_choice_add (checksum_type,
+ _("SHA1"), BRASERO_CHECKSUM_SHA1_FILE);
+ brasero_plugin_conf_option_choice_add (checksum_type,
+ _("SHA256"), BRASERO_CHECKSUM_SHA256_FILE);
+
+ brasero_plugin_add_conf_option (plugin, checksum_type);
+
+ brasero_plugin_set_compulsory (plugin, FALSE);
+
+ return BRASERO_BURN_OK;
+}
diff --git a/plugins/checksum/burn-checksum-files.h b/plugins/checksum/burn-checksum-files.h
new file mode 100644
index 0000000..191f346
--- /dev/null
+++ b/plugins/checksum/burn-checksum-files.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ * burn-sum.h
+ *
+ * ven aoû 4 19:46:34 2006
+ * Copyright 2006 Rouquier Philippe
+ * brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef BURN_SUM_FILE_H
+#define BURN_SUM_FILE_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_CHECKSUM_FILES (brasero_checksum_files_get_type ())
+#define BRASERO_CHECKSUM_FILES(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_CHECKSUM_FILES, BraseroChecksumFiles))
+#define BRASERO_CHECKSUM_FILES_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_CHECKSUM_FILES, BraseroChecksumFilesClass))
+#define BRASERO_IS_CHECKSUM_FILES(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_CHECKSUM_FILES))
+#define BRASERO_IS_CHECKSUM_FILES_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_CHECKSUM_FILES))
+#define BRASERO_CHECKSUM_FILES_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_CHECKSUM_FILES, BraseroChecksumFilesClass))
+
+G_END_DECLS
+
+#endif /* BURN_SUM_FILE_H */
diff --git a/plugins/checksum/burn-checksum-image.c b/plugins/checksum/burn-checksum-image.c
new file mode 100644
index 0000000..e71072f
--- /dev/null
+++ b/plugins/checksum/burn-checksum-image.c
@@ -0,0 +1,824 @@
+/***************************************************************************
+ * burn-sum.c
+ *
+ * ven aoû 4 19:46:34 2006
+ * Copyright 2006 Rouquier Philippe
+ * brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/param.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+
+#include <gmodule.h>
+
+#include <gconf/gconf-client.h>
+
+#include "brasero-plugin-registration.h"
+#include "burn-job.h"
+#include "burn-checksum-image.h"
+#include "burn-volume.h"
+#include "brasero-drive.h"
+#include "brasero-track-disc.h"
+#include "brasero-track-image.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroChecksumImage, brasero_checksum_image, BRASERO_TYPE_JOB, BraseroJob);
+
+struct _BraseroChecksumImagePrivate {
+ GChecksum *checksum;
+ BraseroChecksumType checksum_type;
+
+ /* That's for progress reporting */
+ guint64 total;
+ guint64 bytes;
+
+ /* this is for the thread and the end of it */
+ GThread *thread;
+ GMutex *mutex;
+ GCond *cond;
+ gint end_id;
+
+ guint cancel;
+};
+typedef struct _BraseroChecksumImagePrivate BraseroChecksumImagePrivate;
+
+#define BRASERO_CHECKSUM_IMAGE_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_CHECKSUM_IMAGE, BraseroChecksumImagePrivate))
+
+#define GCONF_KEY_CHECKSUM_TYPE "/apps/brasero/config/checksum_image"
+
+static BraseroJobClass *parent_class = NULL;
+
+static gint
+brasero_checksum_image_read (BraseroChecksumImage *self,
+ int fd,
+ guchar *buffer,
+ gint bytes,
+ GError **error)
+{
+ gint total = 0;
+ gint read_bytes;
+ BraseroChecksumImagePrivate *priv;
+
+ priv = BRASERO_CHECKSUM_IMAGE_PRIVATE (self);
+
+ while (1) {
+ read_bytes = read (fd, buffer + total, (bytes - total));
+
+ /* maybe that's the end of the stream ... */
+ if (!read_bytes)
+ return total;
+
+ if (priv->cancel)
+ return -2;
+
+ /* ... or an error =( */
+ if (read_bytes == -1) {
+ if (errno != EAGAIN && errno != EINTR) {
+ int errsv = errno;
+
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("Data could not be read (%s)"),
+ g_strerror (errsv));
+ return -1;
+ }
+ }
+ else {
+ total += read_bytes;
+
+ if (total == bytes)
+ return total;
+ }
+
+ g_usleep (500);
+ }
+
+ return total;
+}
+
+static BraseroBurnResult
+brasero_checksum_image_write (BraseroChecksumImage *self,
+ int fd,
+ guchar *buffer,
+ gint bytes,
+ GError **error)
+{
+ gint bytes_remaining;
+ gint bytes_written = 0;
+ BraseroChecksumImagePrivate *priv;
+
+ priv = BRASERO_CHECKSUM_IMAGE_PRIVATE (self);
+
+ bytes_remaining = bytes;
+ while (bytes_remaining) {
+ gint written;
+
+ written = write (fd,
+ buffer + bytes_written,
+ bytes_remaining);
+
+ if (priv->cancel)
+ return BRASERO_BURN_CANCEL;
+
+ if (written != bytes_remaining) {
+ if (errno != EINTR && errno != EAGAIN) {
+ int errsv = errno;
+
+ /* unrecoverable error */
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("Data could not be written (%s)"),
+ g_strerror (errsv));
+ return BRASERO_BURN_ERR;
+ }
+ }
+
+ g_usleep (500);
+
+ if (written > 0) {
+ bytes_remaining -= written;
+ bytes_written += written;
+ }
+ }
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_checksum_image_checksum (BraseroChecksumImage *self,
+ GChecksumType checksum_type,
+ int fd_in,
+ int fd_out,
+ GError **error)
+{
+ gint read_bytes;
+ guchar buffer [2048];
+ BraseroBurnResult result;
+ BraseroChecksumImagePrivate *priv;
+
+ priv = BRASERO_CHECKSUM_IMAGE_PRIVATE (self);
+
+ priv->checksum = g_checksum_new (checksum_type);
+ result = BRASERO_BURN_OK;
+ while (1) {
+ read_bytes = brasero_checksum_image_read (self,
+ fd_in,
+ buffer,
+ sizeof (buffer),
+ error);
+ if (read_bytes == -2)
+ return BRASERO_BURN_CANCEL;
+
+ if (read_bytes == -1)
+ return BRASERO_BURN_ERR;
+
+ if (!read_bytes)
+ break;
+
+ /* it can happen when we're just asked to generate a checksum
+ * that we don't need to output the received data */
+ if (fd_out > 0) {
+ result = brasero_checksum_image_write (self,
+ fd_out,
+ buffer,
+ read_bytes, error);
+ if (result != BRASERO_BURN_OK)
+ break;
+ }
+
+ g_checksum_update (priv->checksum,
+ buffer,
+ read_bytes);
+
+ priv->bytes += read_bytes;
+ }
+
+ return result;
+}
+
+static BraseroBurnResult
+brasero_checksum_image_checksum_fd_input (BraseroChecksumImage *self,
+ GChecksumType checksum_type,
+ GError **error)
+{
+ int fd_in = -1;
+ int fd_out = -1;
+ BraseroBurnResult result;
+ BraseroChecksumImagePrivate *priv;
+
+ priv = BRASERO_CHECKSUM_IMAGE_PRIVATE (self);
+
+ BRASERO_JOB_LOG (self, "Starting checksum generation live (size = %lli)", priv->total);
+ result = brasero_job_set_nonblocking (BRASERO_JOB (self), error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+
+ brasero_job_get_fd_in (BRASERO_JOB (self), &fd_in);
+ brasero_job_get_fd_out (BRASERO_JOB (self), &fd_out);
+
+ return brasero_checksum_image_checksum (self, checksum_type, fd_in, fd_out, error);
+}
+
+static BraseroBurnResult
+brasero_checksum_image_checksum_file_input (BraseroChecksumImage *self,
+ GChecksumType checksum_type,
+ GError **error)
+{
+ BraseroChecksumImagePrivate *priv;
+ BraseroBurnResult result;
+ BraseroTrack *track;
+ int fd_out = -1;
+ int fd_in = -1;
+ gchar *path;
+
+ priv = BRASERO_CHECKSUM_IMAGE_PRIVATE (self);
+
+ /* get all information */
+ brasero_job_get_current_track (BRASERO_JOB (self), &track);
+ path = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (track), FALSE);
+ if (!path) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_FILE_NOT_LOCAL,
+ _("The file is not stored locally"));
+ return BRASERO_BURN_ERR;
+ }
+
+ BRASERO_JOB_LOG (self,
+ "Starting checksuming file %s (size = %i)",
+ path,
+ priv->total);
+
+ fd_in = open (path, O_RDONLY);
+ if (!fd_in) {
+ int errsv;
+ gchar *name = NULL;
+
+ if (errno == ENOENT)
+ return BRASERO_BURN_RETRY;
+
+ name = g_path_get_basename (path);
+
+ errsv = errno;
+
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ /* Translators: first %s is the filename, second %s
+ * is the error generated from errno */
+ _("\"%s\" could not be opened (%s)"),
+ name,
+ g_strerror (errsv));
+ g_free (name);
+ g_free (path);
+
+ return BRASERO_BURN_ERR;
+ }
+
+ /* and here we go */
+ brasero_job_get_fd_out (BRASERO_JOB (self), &fd_out);
+ result = brasero_checksum_image_checksum (self, checksum_type, fd_in, fd_out, error);
+ g_free (path);
+ close (fd_in);
+
+ return result;
+}
+
+static BraseroBurnResult
+brasero_checksum_image_create_checksum (BraseroChecksumImage *self,
+ GError **error)
+{
+ BraseroBurnResult result;
+ BraseroTrack *track = NULL;
+ GChecksumType checksum_type;
+ BraseroChecksumImagePrivate *priv;
+
+ priv = BRASERO_CHECKSUM_IMAGE_PRIVATE (self);
+
+ /* get the checksum type */
+ switch (priv->checksum_type) {
+ case BRASERO_CHECKSUM_MD5:
+ checksum_type = G_CHECKSUM_MD5;
+ break;
+ case BRASERO_CHECKSUM_SHA1:
+ checksum_type = G_CHECKSUM_SHA1;
+ break;
+ case BRASERO_CHECKSUM_SHA256:
+ checksum_type = G_CHECKSUM_SHA256;
+ break;
+ default:
+ return BRASERO_BURN_ERR;
+ }
+
+ brasero_job_set_current_action (BRASERO_JOB (self),
+ BRASERO_BURN_ACTION_CHECKSUM,
+ _("Creating image checksum"),
+ FALSE);
+ brasero_job_start_progress (BRASERO_JOB (self), FALSE);
+ brasero_job_get_current_track (BRASERO_JOB (self), &track);
+
+ /* see if another plugin is sending us data to checksum */
+ if (brasero_job_get_fd_in (BRASERO_JOB (self), NULL) == BRASERO_BURN_OK) {
+ BraseroMedium *medium;
+ BraseroDrive *drive;
+
+ /* we're only able to checksum ISO format at the moment so that
+ * means we can only handle last session */
+ drive = brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track));
+ medium = brasero_drive_get_medium (drive);
+ brasero_medium_get_last_data_track_space (medium,
+ &priv->total,
+ NULL);
+
+ return brasero_checksum_image_checksum_fd_input (self, checksum_type, error);
+ }
+ else {
+ result = brasero_track_get_size (track,
+ NULL,
+ &priv->total);
+ if (result != BRASERO_BURN_OK)
+ return result;
+
+ return brasero_checksum_image_checksum_file_input (self, checksum_type, error);
+ }
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroChecksumType
+brasero_checksum_get_checksum_type (void)
+{
+ GConfClient *client;
+ GChecksumType checksum_type;
+
+ client = gconf_client_get_default ();
+ checksum_type = gconf_client_get_int (client, GCONF_KEY_CHECKSUM_TYPE, NULL);
+ g_object_unref (client);
+
+ if (!checksum_type)
+ checksum_type = BRASERO_CHECKSUM_MD5;
+
+ return checksum_type;
+}
+
+static BraseroBurnResult
+brasero_checksum_image_image_and_checksum (BraseroChecksumImage *self,
+ GError **error)
+{
+ BraseroBurnResult result;
+ GChecksumType checksum_type;
+ BraseroChecksumImagePrivate *priv;
+
+ priv = BRASERO_CHECKSUM_IMAGE_PRIVATE (self);
+
+ priv->checksum_type = brasero_checksum_get_checksum_type ();
+ if (priv->checksum_type == BRASERO_CHECKSUM_NONE)
+ checksum_type = G_CHECKSUM_MD5;
+ else if (priv->checksum_type & BRASERO_CHECKSUM_MD5)
+ checksum_type = G_CHECKSUM_MD5;
+ else if (priv->checksum_type & BRASERO_CHECKSUM_SHA1)
+ checksum_type = G_CHECKSUM_SHA1;
+ else if (priv->checksum_type & BRASERO_CHECKSUM_SHA256)
+ checksum_type = G_CHECKSUM_SHA256;
+ else
+ checksum_type = G_CHECKSUM_MD5;
+
+ brasero_job_set_current_action (BRASERO_JOB (self),
+ BRASERO_BURN_ACTION_CHECKSUM,
+ _("Creating image checksum"),
+ FALSE);
+ brasero_job_start_progress (BRASERO_JOB (self), FALSE);
+
+ if (brasero_job_get_fd_in (BRASERO_JOB (self), NULL) != BRASERO_BURN_OK) {
+ BraseroTrack *track;
+
+ brasero_job_get_current_track (BRASERO_JOB (self), &track);
+ result = brasero_track_get_size (track,
+ NULL,
+ &priv->total);
+ if (result != BRASERO_BURN_OK)
+ return result;
+
+ result = brasero_checksum_image_checksum_file_input (self,
+ checksum_type,
+ error);
+ }
+ else
+ result = brasero_checksum_image_checksum_fd_input (self,
+ checksum_type,
+ error);
+
+ return result;
+}
+
+struct _BraseroChecksumImageThreadCtx {
+ BraseroChecksumImage *sum;
+ BraseroBurnResult result;
+ GError *error;
+};
+typedef struct _BraseroChecksumImageThreadCtx BraseroChecksumImageThreadCtx;
+
+static gboolean
+brasero_checksum_image_end (gpointer data)
+{
+ BraseroChecksumImage *self;
+ BraseroTrack *track;
+ const gchar *checksum;
+ BraseroBurnResult result;
+ BraseroChecksumImagePrivate *priv;
+ BraseroChecksumImageThreadCtx *ctx;
+
+ ctx = data;
+ self = ctx->sum;
+ priv = BRASERO_CHECKSUM_IMAGE_PRIVATE (self);
+
+ /* NOTE ctx/data is destroyed in its own callback */
+ priv->end_id = 0;
+
+ if (ctx->result != BRASERO_BURN_OK) {
+ GError *error;
+
+ error = ctx->error;
+ ctx->error = NULL;
+
+ g_checksum_free (priv->checksum);
+ priv->checksum = NULL;
+
+ brasero_job_error (BRASERO_JOB (self), error);
+ return FALSE;
+ }
+
+ /* we were asked to check the sum of the track so get the type
+ * of the checksum first to see what to do */
+ track = NULL;
+ brasero_job_get_current_track (BRASERO_JOB (self), &track);
+
+ /* Set the checksum for the track and at the same time compare it to a
+ * potential previous one. */
+ checksum = g_checksum_get_string (priv->checksum);
+ BRASERO_JOB_LOG (self,
+ "Setting new checksum (type = %i) %s (%s before)",
+ priv->checksum_type,
+ checksum,
+ brasero_track_get_checksum (track));
+ result = brasero_track_set_checksum (track,
+ priv->checksum_type,
+ checksum);
+ g_checksum_free (priv->checksum);
+ priv->checksum = NULL;
+
+ if (result != BRASERO_BURN_OK)
+ goto error;
+
+ brasero_job_finished_track (BRASERO_JOB (self));
+ return FALSE;
+
+error:
+{
+ GError *error = NULL;
+
+ error = g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_BAD_CHECKSUM,
+ _("Some files may be corrupted on the disc"));
+ brasero_job_error (BRASERO_JOB (self), error);
+ return FALSE;
+}
+}
+
+static void
+brasero_checksum_image_destroy (gpointer data)
+{
+ BraseroChecksumImageThreadCtx *ctx;
+
+ ctx = data;
+ if (ctx->error) {
+ g_error_free (ctx->error);
+ ctx->error = NULL;
+ }
+
+ g_free (ctx);
+}
+
+static gpointer
+brasero_checksum_image_thread (gpointer data)
+{
+ GError *error = NULL;
+ BraseroJobAction action;
+ BraseroTrack *track = NULL;
+ BraseroChecksumImage *self;
+ BraseroChecksumImagePrivate *priv;
+ BraseroChecksumImageThreadCtx *ctx;
+ BraseroBurnResult result = BRASERO_BURN_NOT_SUPPORTED;
+
+ self = BRASERO_CHECKSUM_IMAGE (data);
+ priv = BRASERO_CHECKSUM_IMAGE_PRIVATE (self);
+
+ /* check DISC types and add checksums for DATA and IMAGE-bin types */
+ brasero_job_get_action (BRASERO_JOB (self), &action);
+ brasero_job_get_current_track (BRASERO_JOB (self), &track);
+
+ if (action == BRASERO_JOB_ACTION_CHECKSUM) {
+ priv->checksum_type = brasero_track_get_checksum_type (track);
+ if (priv->checksum_type & (BRASERO_CHECKSUM_MD5|BRASERO_CHECKSUM_SHA1|BRASERO_CHECKSUM_SHA256))
+ result = brasero_checksum_image_create_checksum (self, &error);
+ else
+ result = BRASERO_BURN_ERR;
+ }
+ else if (action == BRASERO_JOB_ACTION_IMAGE) {
+ if (BRASERO_IS_TRACK_IMAGE (track))
+ result = brasero_checksum_image_image_and_checksum (self, &error);
+ else
+ result = BRASERO_BURN_ERR;
+ }
+
+ if (result != BRASERO_BURN_CANCEL) {
+ ctx = g_new0 (BraseroChecksumImageThreadCtx, 1);
+ ctx->sum = self;
+ ctx->error = error;
+ ctx->result = result;
+ priv->end_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE,
+ brasero_checksum_image_end,
+ ctx,
+ brasero_checksum_image_destroy);
+ }
+
+ /* End thread */
+ g_mutex_lock (priv->mutex);
+ priv->thread = NULL;
+ g_cond_signal (priv->cond);
+ g_mutex_unlock (priv->mutex);
+
+ g_thread_exit (NULL);
+ return NULL;
+}
+
+static BraseroBurnResult
+brasero_checksum_image_start (BraseroJob *job,
+ GError **error)
+{
+ BraseroChecksumImagePrivate *priv;
+ GError *thread_error = NULL;
+ BraseroJobAction action;
+
+ brasero_job_get_action (job, &action);
+ if (action == BRASERO_JOB_ACTION_SIZE) {
+ /* say we won't write to disc if we're just checksuming "live" */
+ if (brasero_job_get_fd_in (job, NULL) == BRASERO_BURN_OK)
+ return BRASERO_BURN_NOT_SUPPORTED;
+
+ /* otherwise return an output of 0 since we're not actually
+ * writing anything to the disc. That will prevent a disc space
+ * failure. */
+ brasero_job_set_output_size_for_current_track (job, 0, 0);
+ return BRASERO_BURN_NOT_RUNNING;
+ }
+
+ /* we start a thread for the exploration of the graft points */
+ priv = BRASERO_CHECKSUM_IMAGE_PRIVATE (job);
+ g_mutex_lock (priv->mutex);
+ priv->thread = g_thread_create (brasero_checksum_image_thread,
+ BRASERO_CHECKSUM_IMAGE (job),
+ TRUE,
+ &thread_error);
+ g_mutex_unlock (priv->mutex);
+
+ /* Reminder: this is not necessarily an error as the thread may have finished */
+ //if (!priv->thread)
+ // return BRASERO_BURN_ERR;
+ if (thread_error) {
+ g_propagate_error (error, thread_error);
+ return BRASERO_BURN_ERR;
+ }
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_checksum_image_activate (BraseroJob *job,
+ GError **error)
+{
+ BraseroBurnFlag flags = BRASERO_BURN_FLAG_NONE;
+ BraseroTrack *track = NULL;
+ BraseroJobAction action;
+
+ brasero_job_get_current_track (job, &track);
+ brasero_job_get_action (job, &action);
+
+ if (action == BRASERO_JOB_ACTION_IMAGE
+ && brasero_track_get_checksum_type (track) == brasero_checksum_get_checksum_type ()) {
+ BRASERO_JOB_LOG (job,
+ "There is a checksum already %d",
+ brasero_track_get_checksum_type (track));
+ /* if there is a checksum already, if so no need to redo one */
+ return BRASERO_BURN_NOT_RUNNING;
+ }
+
+ flags = BRASERO_BURN_FLAG_NONE;
+ brasero_job_get_flags (job, &flags);
+ if (flags & BRASERO_BURN_FLAG_DUMMY) {
+ BRASERO_JOB_LOG (job, "Dummy operation, skipping");
+ return BRASERO_BURN_NOT_RUNNING;
+ }
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_checksum_image_clock_tick (BraseroJob *job)
+{
+ BraseroChecksumImagePrivate *priv;
+
+ priv = BRASERO_CHECKSUM_IMAGE_PRIVATE (job);
+ if (!priv->checksum)
+ return BRASERO_BURN_OK;
+
+ if (!priv->total)
+ return BRASERO_BURN_OK;
+
+ brasero_job_set_progress (job,
+ (gdouble) priv->bytes /
+ (gdouble) priv->total);
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_checksum_image_stop (BraseroJob *job,
+ GError **error)
+{
+ BraseroChecksumImagePrivate *priv;
+
+ priv = BRASERO_CHECKSUM_IMAGE_PRIVATE (job);
+
+ g_mutex_lock (priv->mutex);
+ if (priv->thread) {
+ priv->cancel = 1;
+ g_cond_wait (priv->cond, priv->mutex);
+ priv->cancel = 0;
+ priv->thread = NULL;
+ }
+ g_mutex_unlock (priv->mutex);
+
+ if (priv->end_id) {
+ g_source_remove (priv->end_id);
+ priv->end_id = 0;
+ }
+
+ if (priv->checksum) {
+ g_checksum_free (priv->checksum);
+ priv->checksum = NULL;
+ }
+
+ return BRASERO_BURN_OK;
+}
+
+static void
+brasero_checksum_image_init (BraseroChecksumImage *obj)
+{
+ BraseroChecksumImagePrivate *priv;
+
+ priv = BRASERO_CHECKSUM_IMAGE_PRIVATE (obj);
+
+ priv->mutex = g_mutex_new ();
+ priv->cond = g_cond_new ();
+}
+
+static void
+brasero_checksum_image_finalize (GObject *object)
+{
+ BraseroChecksumImagePrivate *priv;
+
+ priv = BRASERO_CHECKSUM_IMAGE_PRIVATE (object);
+
+ g_mutex_lock (priv->mutex);
+ if (priv->thread) {
+ priv->cancel = 1;
+ g_cond_wait (priv->cond, priv->mutex);
+ priv->cancel = 0;
+ priv->thread = NULL;
+ }
+ g_mutex_unlock (priv->mutex);
+
+ if (priv->end_id) {
+ g_source_remove (priv->end_id);
+ priv->end_id = 0;
+ }
+
+ if (priv->checksum) {
+ g_checksum_free (priv->checksum);
+ priv->checksum = NULL;
+ }
+
+ if (priv->mutex) {
+ g_mutex_free (priv->mutex);
+ priv->mutex = NULL;
+ }
+
+ if (priv->cond) {
+ g_cond_free (priv->cond);
+ priv->cond = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+brasero_checksum_image_class_init (BraseroChecksumImageClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ BraseroJobClass *job_class = BRASERO_JOB_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (BraseroChecksumImagePrivate));
+
+ parent_class = g_type_class_peek_parent (klass);
+ object_class->finalize = brasero_checksum_image_finalize;
+
+ job_class->activate = brasero_checksum_image_activate;
+ job_class->start = brasero_checksum_image_start;
+ job_class->stop = brasero_checksum_image_stop;
+ job_class->clock_tick = brasero_checksum_image_clock_tick;
+}
+
+static BraseroBurnResult
+brasero_checksum_image_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+ GSList *input;
+ BraseroPluginConfOption *checksum_type;
+
+ brasero_plugin_define (plugin,
+ /* Translators: this is the name of the plugin
+ * which will be translated only when it needs
+ * displaying. */
+ N_("Image Checksum"),
+ _("Allows to check data integrity on disc after it is burnt"),
+ "Philippe Rouquier",
+ 0);
+
+ /* For images we can process (thus generating a sum on the fly or simply
+ * test images). */
+ input = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE|
+ BRASERO_PLUGIN_IO_ACCEPT_PIPE,
+ BRASERO_IMAGE_FORMAT_BIN);
+ brasero_plugin_process_caps (plugin, input);
+
+ brasero_plugin_set_process_flags (plugin,
+ BRASERO_PLUGIN_RUN_PREPROCESSING|
+ BRASERO_PLUGIN_RUN_BEFORE_TARGET);
+
+ brasero_plugin_check_caps (plugin,
+ BRASERO_CHECKSUM_MD5|
+ BRASERO_CHECKSUM_SHA1|
+ BRASERO_CHECKSUM_SHA256,
+ input);
+ g_slist_free (input);
+
+ /* add some configure options */
+ checksum_type = brasero_plugin_conf_option_new (GCONF_KEY_CHECKSUM_TYPE,
+ _("Hashing algorithm to be used:"),
+ BRASERO_PLUGIN_OPTION_CHOICE);
+ brasero_plugin_conf_option_choice_add (checksum_type,
+ _("MD5"), BRASERO_CHECKSUM_MD5);
+ brasero_plugin_conf_option_choice_add (checksum_type,
+ _("SHA1"), BRASERO_CHECKSUM_SHA1);
+ brasero_plugin_conf_option_choice_add (checksum_type,
+ _("SHA256"), BRASERO_CHECKSUM_SHA256);
+
+ brasero_plugin_add_conf_option (plugin, checksum_type);
+
+ brasero_plugin_set_compulsory (plugin, FALSE);
+
+ return BRASERO_BURN_OK;
+}
diff --git a/plugins/checksum/burn-checksum-image.h b/plugins/checksum/burn-checksum-image.h
new file mode 100644
index 0000000..aada24a
--- /dev/null
+++ b/plugins/checksum/burn-checksum-image.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ * burn-sum.h
+ *
+ * ven aoû 4 19:46:34 2006
+ * Copyright 2006 Rouquier Philippe
+ * brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef BURN_SUM_H
+#define BURN_SUM_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_CHECKSUM_IMAGE (brasero_checksum_image_get_type ())
+#define BRASERO_CHECKSUM_IMAGE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_CHECKSUM_IMAGE, BraseroChecksumImage))
+#define BRASERO_CHECKSUM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_CHECKSUM_IMAGE, BraseroChecksumImageClass))
+#define BRASERO_IS_CHECKSUM_IMAGE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_CHECKSUM_IMAGE))
+#define BRASERO_IS_CHECKSUM_IMAGE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_CHECKSUM_IMAGE))
+#define BRASERO_CHECKSUM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_CHECKSUM_IMAGE, BraseroChecksumImageClass))
+
+G_END_DECLS
+
+#endif /* BURN_SUM_H */
diff --git a/plugins/checksum/burn-volume-read.c b/plugins/checksum/burn-volume-read.c
new file mode 100644
index 0000000..29c9772
--- /dev/null
+++ b/plugins/checksum/burn-volume-read.c
@@ -0,0 +1,397 @@
+/***************************************************************************
+ * brasero-medium-handle.c
+ *
+ * Sat Mar 15 17:27:29 2008
+ * Copyright 2008 Philippe Rouquier
+ * <bonfire-app wanadoo fr>
+ ****************************************************************************/
+
+/*
+ * Libbrasero-media is free software; you can redistribute it and/or modify
+fy
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA
+ */
+
+#include "scsi-device.h"
+#include "scsi-mmc1.h"
+#include "burn-volume.h"
+#include "burn-iso9660.h"
+#include "burn-volume-read.h"
+
+struct _BraseroVolFileHandle {
+ /* 64 is an empirical value based on one of my drives. */
+ guchar buffer [2048 * 64];
+ guint buffer_max;
+
+ /* position in buffer */
+ guint offset;
+
+ /* address (in blocks) for current extent */
+ guint extent_last;
+
+ /* size in bytes for the current extent */
+ guint extent_size;
+
+ BraseroVolSrc *src;
+ GSList *extents_backward;
+ GSList *extents_forward;
+ guint position;
+};
+
+void
+brasero_volume_file_close (BraseroVolFileHandle *handle)
+{
+ g_slist_free (handle->extents_forward);
+ g_slist_free (handle->extents_backward);
+ brasero_volume_source_close (handle->src);
+ g_free (handle);
+}
+
+static gboolean
+brasero_volume_file_fill_buffer (BraseroVolFileHandle *handle)
+{
+ guint blocks;
+ gboolean result;
+
+ blocks = MIN (sizeof (handle->buffer) / 2048,
+ handle->extent_last - handle->position);
+
+ result = BRASERO_VOL_SRC_READ (handle->src,
+ (char *) handle->buffer,
+ blocks,
+ NULL);
+ if (!result)
+ return FALSE;
+
+ handle->offset = 0;
+ handle->position += blocks;
+
+ if (handle->position == handle->extent_last)
+ handle->buffer_max = (blocks - 1) * 2048 +
+ ((handle->extent_size % 2048) ?
+ (handle->extent_size % 2048) :
+ 2048);
+ else
+ handle->buffer_max = sizeof (handle->buffer);
+
+ return TRUE;
+}
+
+static gboolean
+brasero_volume_file_next_extent (BraseroVolFileHandle *handle)
+{
+ BraseroVolFileExtent *extent;
+ gint res_seek;
+ GSList *node;
+
+ node = handle->extents_forward;
+ extent = node->data;
+
+ handle->extents_forward = g_slist_remove_link (handle->extents_forward, node);
+ node->next = handle->extents_backward;
+ handle->extents_backward = node;
+
+ handle->position = extent->block;
+ handle->extent_size = extent->size;
+ handle->extent_last = BRASERO_BYTES_TO_SECTORS (extent->size, 2048) + extent->block;
+
+ res_seek = BRASERO_VOL_SRC_SEEK (handle->src, handle->position, SEEK_SET, NULL);
+ if (res_seek == -1)
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+brasero_volume_file_rewind_real (BraseroVolFileHandle *handle)
+{
+ if (!brasero_volume_file_next_extent (handle))
+ return FALSE;
+
+ return brasero_volume_file_fill_buffer (handle);
+}
+
+BraseroVolFileHandle *
+brasero_volume_file_open (BraseroVolSrc *src,
+ BraseroVolFile *file)
+{
+ BraseroVolFileHandle *handle;
+
+ if (file->isdir)
+ return NULL;
+
+ handle = g_new0 (BraseroVolFileHandle, 1);
+ handle->src = src;
+ brasero_volume_source_ref (src);
+
+ handle->extents_forward = g_slist_copy (file->specific.file.extents);
+ if (!brasero_volume_file_rewind_real (handle)) {
+ brasero_volume_file_close (handle);
+ return NULL;
+ }
+
+ return handle;
+}
+
+gboolean
+brasero_volume_file_rewind (BraseroVolFileHandle *handle)
+{
+ GSList *node, *next;
+
+ /* Put back all extents in the unread list */
+ for (node = handle->extents_backward; node; node = next) {
+ next = node->next;
+ handle->extents_backward = g_slist_remove_link (handle->extents_backward, node);
+
+ node->next = handle->extents_forward;
+ handle->extents_forward = node;
+ }
+ return brasero_volume_file_rewind_real (handle);
+}
+
+BraseroBurnResult
+brasero_volume_file_check_state (BraseroVolFileHandle *handle)
+{
+ /* check if we need to load a new block */
+ if (handle->offset < handle->buffer_max)
+ return BRASERO_BURN_RETRY;
+
+ /* check if we need to change our extent */
+ if (handle->position >= handle->extent_last) {
+ /* we are at the end of current extent try to find another */
+ if (!handle->extents_forward) {
+ /* we reached the end of our file */
+ return BRASERO_BURN_OK;
+ }
+
+ if (!brasero_volume_file_next_extent (handle))
+ return BRASERO_BURN_ERR;
+ }
+
+ /* Refill buffer */
+ if (!brasero_volume_file_fill_buffer (handle))
+ return BRASERO_BURN_ERR;
+
+ return BRASERO_BURN_RETRY;
+}
+
+gint
+brasero_volume_file_read (BraseroVolFileHandle *handle,
+ gchar *buffer,
+ guint len)
+{
+ guint buffer_offset = 0;
+ BraseroBurnResult result;
+
+ while ((len - buffer_offset) > (handle->buffer_max - handle->offset)) {
+ /* copy what is already in the buffer and refill the latter */
+ memcpy (buffer + buffer_offset,
+ handle->buffer + handle->offset,
+ handle->buffer_max - handle->offset);
+
+ buffer_offset += handle->buffer_max - handle->offset;
+ handle->offset = handle->buffer_max;
+
+ result = brasero_volume_file_check_state (handle);
+ if (result == BRASERO_BURN_OK)
+ return buffer_offset;
+
+ if (result == BRASERO_BURN_ERR)
+ return -1;
+ }
+
+ /* we filled the buffer and put len bytes in it */
+ memcpy (buffer + buffer_offset,
+ handle->buffer + handle->offset,
+ len - buffer_offset);
+
+ handle->offset += len - buffer_offset;
+
+ result = brasero_volume_file_check_state (handle);
+ if (result == BRASERO_BURN_ERR)
+ return -1;
+
+ return len;
+}
+
+static gint
+brasero_volume_file_find_line_break (BraseroVolFileHandle *handle,
+ guint buffer_offset,
+ gchar *buffer,
+ guint len)
+{
+ guchar *break_line;
+ guint line_len;
+
+ /* search the next end of line characher in the buffer */
+ break_line = memchr (handle->buffer + handle->offset,
+ '\n',
+ handle->buffer_max - handle->offset);
+
+ if (!break_line)
+ return FALSE;
+
+ line_len = break_line - (handle->buffer + handle->offset);
+ if (len && line_len >= len) {
+ /* - 1 is to be able to set last character to '\0' */
+ if (buffer) {
+ memcpy (buffer + buffer_offset,
+ handle->buffer + handle->offset,
+ len - buffer_offset - 1);
+
+ buffer [len - 1] = '\0';
+ }
+
+ handle->offset += len - buffer_offset - 1;
+ return TRUE;
+ }
+
+ if (buffer) {
+ memcpy (buffer, handle->buffer + handle->offset, line_len);
+ buffer [line_len] = '\0';
+ }
+
+ /* add 1 to skip the line break */
+ handle->offset += line_len + 1;
+ return TRUE;
+}
+
+BraseroBurnResult
+brasero_volume_file_read_line (BraseroVolFileHandle *handle,
+ gchar *buffer,
+ guint len)
+{
+ guint buffer_offset = 0;
+ gboolean found;
+
+ found = brasero_volume_file_find_line_break (handle,
+ buffer_offset,
+ buffer,
+ len);
+ if (found)
+ return brasero_volume_file_check_state (handle);
+
+ /* continue while remaining data is too small to fit buffer */
+ while (!len || (len - buffer_offset) > (handle->buffer_max - handle->offset)) {
+ BraseroScsiResult result;
+
+ /* copy what we already have in the buffer. */
+ if (buffer)
+ memcpy (buffer + buffer_offset,
+ handle->offset + handle->buffer,
+ handle->buffer_max - handle->offset);
+
+ buffer_offset += handle->buffer_max - handle->offset;
+ handle->offset = handle->buffer_max;
+
+ /* refill buffer */
+ result = brasero_volume_file_check_state (handle);
+ if (result == BRASERO_BURN_OK) {
+ if (buffer)
+ buffer [len - 1] = '\0';
+
+ return result;
+ }
+
+ found = brasero_volume_file_find_line_break (handle,
+ buffer_offset,
+ buffer,
+ len);
+ if (found)
+ return brasero_volume_file_check_state (handle);
+ }
+
+ /* we filled the buffer */
+ if (buffer) {
+ memcpy (buffer + buffer_offset,
+ handle->buffer + handle->offset,
+ len - buffer_offset - 1);
+ buffer [len - 1] = '\0';
+ }
+
+ /* NOTE: when len == 0 we never reach this part */
+ handle->offset += len - buffer_offset - 1;
+
+ return brasero_volume_file_check_state (handle);
+}
+
+BraseroVolFileHandle *
+brasero_volume_file_open_direct (BraseroVolSrc *src,
+ BraseroVolFile *file)
+{
+ BraseroVolFileHandle *handle;
+
+ if (file->isdir)
+ return NULL;
+
+ handle = g_new0 (BraseroVolFileHandle, 1);
+ handle->src = src;
+ brasero_volume_source_ref (src);
+
+ handle->extents_forward = g_slist_copy (file->specific.file.extents);
+
+ /* Here the buffer stays unused, we copy straight to the buffer passed
+ * in the read direct function. */
+ if (!brasero_volume_file_next_extent (handle)) {
+ brasero_volume_file_close (handle);
+ return NULL;
+ }
+
+ return handle;
+}
+
+gint64
+brasero_volume_file_read_direct (BraseroVolFileHandle *handle,
+ guchar *buffer,
+ guint blocks)
+{
+ gboolean result;
+ guint block2read;
+ guint readblocks = 0;
+
+start:
+
+ block2read = MIN (blocks - readblocks, handle->extent_last - handle->position);
+ if (!block2read)
+ return readblocks * 2048;
+
+ result = BRASERO_VOL_SRC_READ (handle->src,
+ (char *) buffer + readblocks * 2048,
+ block2read,
+ NULL);
+ if (!result)
+ return -1;
+
+ handle->position += block2read;
+ readblocks += block2read;
+
+ if (handle->position == handle->extent_last) {
+ /* we are at the end of current extent try to find another */
+ if (!handle->extents_forward) {
+ /* we reached the end of our file */
+ return (readblocks - 1) * 2048 +
+ ((handle->extent_size % 2048) != 0?
+ (handle->extent_size % 2048) :
+ 2048);
+ }
+
+ if (!brasero_volume_file_next_extent (handle))
+ return -1;
+
+ goto start;
+ }
+
+ return readblocks * 2048;
+}
+
diff --git a/plugins/checksum/burn-volume-read.h b/plugins/checksum/burn-volume-read.h
new file mode 100644
index 0000000..973a40d
--- /dev/null
+++ b/plugins/checksum/burn-volume-read.h
@@ -0,0 +1,72 @@
+/***************************************************************************
+ * brasero-medium-handle.h
+ *
+ * Sat Mar 15 17:28:02 2008
+ * Copyright 2008 Philippe Rouquier
+ * <bonfire-app wanadoo fr>
+ ****************************************************************************/
+
+/*
+ * Libbrasero-media is free software; you can redistribute it and/or modify
+fy
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA
+ */
+
+#ifndef _BRASERO_MEDIUM_HANDLE_H
+#define BRASERO_MEDIUM_HANDLE_H
+
+#include <glib.h>
+
+#include "burn-basics.h"
+#include "burn-volume-source.h"
+
+G_BEGIN_DECLS
+
+typedef struct _BraseroVolFileHandle BraseroVolFileHandle;
+
+
+BraseroVolFileHandle *
+brasero_volume_file_open (BraseroVolSrc *src,
+ BraseroVolFile *file);
+
+void
+brasero_volume_file_close (BraseroVolFileHandle *handle);
+
+gboolean
+brasero_volume_file_rewind (BraseroVolFileHandle *handle);
+
+gint
+brasero_volume_file_read (BraseroVolFileHandle *handle,
+ gchar *buffer,
+ guint len);
+
+BraseroBurnResult
+brasero_volume_file_read_line (BraseroVolFileHandle *handle,
+ gchar *buffer,
+ guint len);
+
+BraseroVolFileHandle *
+brasero_volume_file_open_direct (BraseroVolSrc *src,
+ BraseroVolFile *file);
+
+gint64
+brasero_volume_file_read_direct (BraseroVolFileHandle *handle,
+ guchar *buffer,
+ guint blocks);
+
+G_END_DECLS
+
+#endif /* BRASERO_MEDIUM_HANDLE_H */
+
+
diff --git a/plugins/dvdauthor/Makefile.am b/plugins/dvdauthor/Makefile.am
new file mode 100644
index 0000000..deefcf5
--- /dev/null
+++ b/plugins/dvdauthor/Makefile.am
@@ -0,0 +1,23 @@
+
+INCLUDES = \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/libbrasero-media/ \
+ -I$(top_builddir)/libbrasero-media/ \
+ -I$(top_srcdir)/libbrasero-burn \
+ -I$(top_builddir)/libbrasero-burn/ \
+ -DBRASERO_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
+ -DBRASERO_PREFIX=\"$(prefix)\" \
+ -DBRASERO_SYSCONFDIR=\"$(sysconfdir)\" \
+ -DBRASERO_DATADIR=\"$(datadir)/brasero\" \
+ -DBRASERO_LIBDIR=\"$(libdir)\" \
+ $(DISABLE_DEPRECATED) \
+ $(BRASERO_GLIB_CFLAGS) \
+ $(BRASERO_LIBXML_CFLAGS)
+
+dvdauthordir = $(libdir)/brasero/plugins
+dvdauthor_LTLIBRARIES = libbrasero-dvdauthor.la
+
+libbrasero_dvdauthor_la_SOURCES = burn-dvdauthor.c burn-dvdauthor.h
+libbrasero_dvdauthor_la_LIBADD = $(BRASERO_GLIB_LIBS) $(BRASERO_LIBXML_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_dvdauthor_la_LDFLAGS = -module -avoid-version
+
diff --git a/plugins/dvdauthor/burn-dvdauthor.c b/plugins/dvdauthor/burn-dvdauthor.c
new file mode 100644
index 0000000..436610b
--- /dev/null
+++ b/plugins/dvdauthor/burn-dvdauthor.c
@@ -0,0 +1,423 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * burn-dvdauthor.c
+ * Copyright (C) Philippe Rouquier 2005-2008 <bonfire-app wanadoo fr>
+ *
+ * burn-dvdauthor.c is free software.
+ *
+ * You may redistribute it and/or modify it under the terms of the
+ * GNU General Public License, as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * burn-dvdauthor.c is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with burn-dvdauthor.c. If not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+#include <gmodule.h>
+
+#include <libxml/xmlerror.h>
+#include <libxml/xmlwriter.h>
+#include <libxml/parser.h>
+#include <libxml/xmlstring.h>
+#include <libxml/uri.h>
+
+#include "brasero-plugin-registration.h"
+#include "burn-job.h"
+#include "burn-process.h"
+#include "burn-dvdauthor.h"
+#include "brasero-track-data.h"
+#include "brasero-track-stream.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroDvdAuthor, brasero_dvd_author, BRASERO_TYPE_PROCESS, BraseroProcess);
+
+typedef struct _BraseroDvdAuthorPrivate BraseroDvdAuthorPrivate;
+struct _BraseroDvdAuthorPrivate
+{
+ gchar *output;
+};
+
+#define BRASERO_DVD_AUTHOR_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_DVD_AUTHOR, BraseroDvdAuthorPrivate))
+
+static BraseroProcessClass *parent_class = NULL;
+
+static BraseroBurnResult
+brasero_dvd_author_add_track (BraseroJob *job)
+{
+ gchar *path;
+ GSList *grafts = NULL;
+ BraseroGraftPt *graft;
+ BraseroTrackData *track;
+ BraseroDvdAuthorPrivate *priv;
+
+ priv = BRASERO_DVD_AUTHOR_PRIVATE (job);
+
+ /* create the track */
+ track = brasero_track_data_new ();
+
+ /* audio */
+ graft = g_new (BraseroGraftPt, 1);
+ path = g_build_path (G_DIR_SEPARATOR_S,
+ priv->output,
+ "AUDIO_TS",
+ NULL);
+ graft->uri = g_filename_to_uri (path, NULL, NULL);
+ g_free (path);
+
+ graft->path = g_strdup ("/AUDIO_TS");
+ grafts = g_slist_prepend (grafts, graft);
+
+ BRASERO_JOB_LOG (job, "Adding graft point for %s", graft->uri);
+
+ /* video */
+ graft = g_new (BraseroGraftPt, 1);
+ path = g_build_path (G_DIR_SEPARATOR_S,
+ priv->output,
+ "VIDEO_TS",
+ NULL);
+ graft->uri = g_filename_to_uri (path, NULL, NULL);
+ g_free (path);
+
+ graft->path = g_strdup ("/VIDEO_TS");
+ grafts = g_slist_prepend (grafts, graft);
+
+ BRASERO_JOB_LOG (job, "Adding graft point for %s", graft->uri);
+
+ brasero_track_data_add_fs (track,
+ BRASERO_IMAGE_FS_ISO|
+ BRASERO_IMAGE_FS_UDF|
+ BRASERO_IMAGE_FS_VIDEO);
+ brasero_track_data_set_source (track,
+ grafts,
+ NULL);
+ brasero_job_add_track (job, BRASERO_TRACK (track));
+ g_object_unref (track);
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_dvd_author_read_stdout (BraseroProcess *process,
+ const gchar *line)
+{
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_dvd_author_read_stderr (BraseroProcess *process,
+ const gchar *line)
+{
+ gint percent = 0;
+
+ if (sscanf (line, "STAT: fixing VOBU at %*s (%*d/%*d, %d%%)", &percent) == 1) {
+ brasero_job_start_progress (BRASERO_JOB (process), FALSE);
+ brasero_job_set_progress (BRASERO_JOB (process),
+ (gdouble) ((gdouble) percent) / 100.0);
+ }
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_dvd_author_generate_xml_file (BraseroProcess *process,
+ const gchar *path,
+ GError **error)
+{
+ BraseroDvdAuthorPrivate *priv;
+ BraseroBurnResult result;
+ GSList *tracks = NULL;
+ xmlTextWriter *xml;
+ gint success;
+ GSList *iter;
+
+ BRASERO_JOB_LOG (process, "Creating DVD layout xml file(%s)", path);
+
+ xml = xmlNewTextWriterFilename (path, 0);
+ if (!xml)
+ return BRASERO_BURN_ERR;
+
+ priv = BRASERO_DVD_AUTHOR_PRIVATE (process);
+
+ xmlTextWriterSetIndent (xml, 1);
+ xmlTextWriterSetIndentString (xml, (xmlChar *) "\t");
+
+ success = xmlTextWriterStartDocument (xml,
+ NULL,
+ "UTF8",
+ NULL);
+ if (success < 0)
+ goto error;
+
+ result = brasero_job_get_tmp_dir (BRASERO_JOB (process),
+ &priv->output,
+ error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+
+ /* let's start */
+ success = xmlTextWriterStartElement (xml, (xmlChar *) "dvdauthor");
+ if (success < 0)
+ goto error;
+
+ success = xmlTextWriterWriteAttribute (xml,
+ (xmlChar *) "dest",
+ (xmlChar *) priv->output);
+ if (success < 0)
+ goto error;
+
+ /* This is needed to finalize */
+ success = xmlTextWriterWriteElement (xml, (xmlChar *) "vmgm", (xmlChar *) "");
+ if (success < 0)
+ goto error;
+
+ /* the tracks */
+ success = xmlTextWriterStartElement (xml, (xmlChar *) "titleset");
+ if (success < 0)
+ goto error;
+
+ success = xmlTextWriterStartElement (xml, (xmlChar *) "titles");
+ if (success < 0)
+ goto error;
+
+ /* get all tracks */
+ brasero_job_get_tracks (BRASERO_JOB (process), &tracks);
+ for (iter = tracks; iter; iter = iter->next) {
+ BraseroTrack *track;
+ gchar *video;
+
+ track = iter->data;
+ success = xmlTextWriterStartElement (xml, (xmlChar *) "pgc");
+ if (success < 0)
+ goto error;
+
+ success = xmlTextWriterStartElement (xml, (xmlChar *) "vob");
+ if (success < 0)
+ goto error;
+
+ video = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (track), FALSE);
+ success = xmlTextWriterWriteAttribute (xml,
+ (xmlChar *) "file",
+ (xmlChar *) video);
+ g_free (video);
+
+ if (success < 0)
+ goto error;
+
+ /* vob */
+ success = xmlTextWriterEndElement (xml);
+ if (success < 0)
+ goto error;
+
+ /* pgc */
+ success = xmlTextWriterEndElement (xml);
+ if (success < 0)
+ goto error;
+ }
+
+ /* titles */
+ success = xmlTextWriterEndElement (xml);
+ if (success < 0)
+ goto error;
+
+ /* titleset */
+ success = xmlTextWriterEndElement (xml);
+ if (success < 0)
+ goto error;
+
+ /* close dvdauthor */
+ success = xmlTextWriterEndElement (xml);
+ if (success < 0)
+ goto error;
+
+ xmlTextWriterEndDocument (xml);
+ xmlFreeTextWriter (xml);
+
+ return BRASERO_BURN_OK;
+
+error:
+
+ BRASERO_JOB_LOG (process, "Error");
+
+ /* close everything */
+ xmlTextWriterEndDocument (xml);
+ xmlFreeTextWriter (xml);
+
+ /* FIXME: get the error */
+
+ return BRASERO_BURN_ERR;
+}
+
+static BraseroBurnResult
+brasero_dvd_author_set_argv (BraseroProcess *process,
+ GPtrArray *argv,
+ GError **error)
+{
+ BraseroDvdAuthorPrivate *priv;
+ BraseroBurnResult result;
+ BraseroJobAction action;
+ gchar *output;
+
+ priv = BRASERO_DVD_AUTHOR_PRIVATE (process);
+
+ brasero_job_get_action (BRASERO_JOB (process), &action);
+ if (action != BRASERO_JOB_ACTION_IMAGE)
+ BRASERO_JOB_NOT_SUPPORTED (process);
+
+ g_ptr_array_add (argv, g_strdup ("dvdauthor"));
+
+ /* get all arguments to write XML file */
+ result = brasero_job_get_tmp_file (BRASERO_JOB (process),
+ NULL,
+ &output,
+ error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+
+ g_ptr_array_add (argv, g_strdup ("-x"));
+ g_ptr_array_add (argv, output);
+
+ result = brasero_dvd_author_generate_xml_file (process, output, error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+
+ brasero_job_set_current_action (BRASERO_JOB (process),
+ BRASERO_BURN_ACTION_CREATING_IMAGE,
+ _("Creating file layout"),
+ FALSE);
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_dvd_author_post (BraseroJob *job)
+{
+ BraseroDvdAuthorPrivate *priv;
+
+ priv = BRASERO_DVD_AUTHOR_PRIVATE (job);
+
+ brasero_dvd_author_add_track (job);
+
+ if (priv->output) {
+ g_free (priv->output);
+ priv->output = NULL;
+ }
+
+ return brasero_job_finished_session (job);
+}
+
+static void
+brasero_dvd_author_init (BraseroDvdAuthor *object)
+{}
+
+static void
+brasero_dvd_author_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+brasero_dvd_author_class_init (BraseroDvdAuthorClass *klass)
+{
+ GObjectClass* object_class = G_OBJECT_CLASS (klass);
+ BraseroProcessClass* process_class = BRASERO_PROCESS_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (BraseroDvdAuthorPrivate));
+
+ object_class->finalize = brasero_dvd_author_finalize;
+
+ process_class->stdout_func = brasero_dvd_author_read_stdout;
+ process_class->stderr_func = brasero_dvd_author_read_stderr;
+ process_class->set_argv = brasero_dvd_author_set_argv;
+ process_class->post = brasero_dvd_author_post;
+}
+
+static BraseroBurnResult
+brasero_dvd_author_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+ BraseroBurnResult result;
+ GSList *output;
+ GSList *input;
+
+ /* NOTE: it seems that cdrecord can burn cue files on the fly */
+ brasero_plugin_define (plugin,
+ "dvdauthor",
+ _("Use dvdauthor to create Video DVDs"),
+ "Philippe Rouquier",
+ 1);
+
+ /* First see if this plugin can be used */
+ result = brasero_process_check_path ("dvdauthor", error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+
+ input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_AUDIO_FORMAT_AC3|
+ BRASERO_AUDIO_FORMAT_MP2|
+ BRASERO_AUDIO_FORMAT_RAW|
+ BRASERO_AUDIO_FORMAT_44100|
+ BRASERO_AUDIO_FORMAT_48000|
+ BRASERO_METADATA_INFO|
+ BRASERO_VIDEO_FORMAT_VIDEO_DVD);
+
+ output = brasero_caps_data_new (BRASERO_IMAGE_FS_ISO|
+ BRASERO_IMAGE_FS_UDF|
+ BRASERO_IMAGE_FS_VIDEO);
+
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (input);
+
+ input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_AUDIO_FORMAT_AC3|
+ BRASERO_AUDIO_FORMAT_MP2|
+ BRASERO_AUDIO_FORMAT_RAW|
+ BRASERO_AUDIO_FORMAT_44100|
+ BRASERO_AUDIO_FORMAT_48000|
+ BRASERO_VIDEO_FORMAT_VIDEO_DVD);
+
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (output);
+ g_slist_free (input);
+
+ /* we only support DVDs */
+ brasero_plugin_set_flags (plugin,
+ BRASERO_MEDIUM_FILE|
+ BRASERO_MEDIUM_DVDR|
+ BRASERO_MEDIUM_DVDR_PLUS|
+ BRASERO_MEDIUM_DUAL_L|
+ BRASERO_MEDIUM_BLANK|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_HAS_DATA,
+ BRASERO_BURN_FLAG_NONE,
+ BRASERO_BURN_FLAG_NONE);
+
+ brasero_plugin_set_flags (plugin,
+ BRASERO_MEDIUM_DVDRW|
+ BRASERO_MEDIUM_DVDRW_PLUS|
+ BRASERO_MEDIUM_DVDRW_RESTRICTED|
+ BRASERO_MEDIUM_DUAL_L|
+ BRASERO_MEDIUM_BLANK|
+ BRASERO_MEDIUM_CLOSED|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_HAS_DATA,
+ BRASERO_BURN_FLAG_NONE,
+ BRASERO_BURN_FLAG_NONE);
+
+ return BRASERO_BURN_OK;
+}
diff --git a/plugins/dvdauthor/burn-dvdauthor.h b/plugins/dvdauthor/burn-dvdauthor.h
new file mode 100644
index 0000000..4c39910
--- /dev/null
+++ b/plugins/dvdauthor/burn-dvdauthor.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * burn-dvdauthor.c
+ * Copyright (C) Philippe Rouquier 2005-2008 <bonfire-app wanadoo fr>
+ *
+ * burn-dvdauthor.c is free software.
+ *
+ * You may redistribute it and/or modify it under the terms of the
+ * GNU General Public License, as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * burn-dvdauthor.c is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with burn-dvdauthor.c. If not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _BRASERO_DVD_AUTHOR_H_
+#define _BRASERO_DVD_AUTHOR_H_
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_DVD_AUTHOR (brasero_dvd_author_get_type ())
+#define BRASERO_DVD_AUTHOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BRASERO_TYPE_DVD_AUTHOR, BraseroDvdAuthor))
+#define BRASERO_DVD_AUTHOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), BRASERO_TYPE_DVD_AUTHOR, BraseroDvdAuthorClass))
+#define BRASERO_IS_DVD_AUTHOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BRASERO_TYPE_DVD_AUTHOR))
+#define BRASERO_IS_DVD_AUTHOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), BRASERO_TYPE_DVD_AUTHOR))
+#define BRASERO_DVD_AUTHOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), BRASERO_TYPE_DVD_AUTHOR, BraseroDvdAuthorClass))
+
+G_END_DECLS
+
+#endif /* _BRASERO_DVD_AUTHOR_H_ */
diff --git a/plugins/dvdcss/Makefile.am b/plugins/dvdcss/Makefile.am
new file mode 100644
index 0000000..626105a
--- /dev/null
+++ b/plugins/dvdcss/Makefile.am
@@ -0,0 +1,22 @@
+plugindir = $(libdir)/brasero/plugins
+
+INCLUDES = \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/libbrasero-media/ \
+ -I$(top_builddir)/libbrasero-media/ \
+ -I$(top_srcdir)/libbrasero-burn \
+ -I$(top_builddir)/libbrasero-burn/ \
+ -DBRASERO_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
+ -DBRASERO_PREFIX=\"$(prefix)\" \
+ -DBRASERO_SYSCONFDIR=\"$(sysconfdir)\" \
+ -DBRASERO_DATADIR=\"$(datadir)/brasero\" \
+ -DBRASERO_LIBDIR=\"$(libdir)\" \
+ $(DISABLE_DEPRECATED) \
+ $(BRASERO_GLIB_CFLAGS)
+
+plugin_LTLIBRARIES = libbrasero-dvdcss.la
+
+libbrasero_dvdcss_la_SOURCES = burn-dvdcss.c burn-dvdcss.h \
+ burn-dvdcss-private.h
+libbrasero_dvdcss_la_LIBADD = $(BRASERO_GLIB_LIBS) $(BRASERO_GMODULE_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_dvdcss_la_LDFLAGS = -module -avoid-version
diff --git a/plugins/dvdcss/burn-dvdcss-private.h b/plugins/dvdcss/burn-dvdcss-private.h
new file mode 100644
index 0000000..8dd37d8
--- /dev/null
+++ b/plugins/dvdcss/burn-dvdcss-private.h
@@ -0,0 +1,66 @@
+/***************************************************************************
+ * burn-dvdcss-private.h
+ *
+ * Thu Nov 16 16:20:39 2006
+ * Copyright 2006 Rouquier Philippe
+ * <bonfire-app wanadoo fr>
+ ****************************************************************************/
+
+/*
+ * Libbrasero-media is free software; you can redistribute it and/or modify
+fy
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA
+ */
+
+
+#include <gmodule.h>
+
+#ifndef _BURN_DVDCSS_PRIVATE_H
+#define _BURN_DVDCSS_PRIVATE_H
+
+G_BEGIN_DECLS
+
+static gboolean css_ready = FALSE;
+
+typedef gpointer dvdcss_handle;
+
+#define DVDCSS_NOFLAGS 0x00
+
+#define DVDCSS_READ_DECRYPT (1 << 0)
+
+#define DVDCSS_SEEK_MPEG (1 << 0)
+#define DVDCSS_SEEK_KEY (1 << 1)
+
+#define DVDCSS_BLOCK_SIZE 2048ULL
+
+static dvdcss_handle *
+(*dvdcss_open) (const gchar *device) = NULL;
+
+static gint
+(*dvdcss_close) (dvdcss_handle *handle) = NULL;
+
+static gint
+(*dvdcss_read) (dvdcss_handle *handle, gpointer p_buffer, gint i_blocks, gint i_flags) = NULL;
+
+static gint
+(*dvdcss_seek) (dvdcss_handle *handle, gint i_blocks, gint i_flags) = NULL;
+
+static gchar *
+(*dvdcss_error) (dvdcss_handle *handle) = NULL;
+
+G_END_DECLS
+
+#endif /* _BURN_DVDCSS_PRIVATE_H */
+
+
diff --git a/plugins/dvdcss/burn-dvdcss.c b/plugins/dvdcss/burn-dvdcss.c
new file mode 100644
index 0000000..3c4a4d5
--- /dev/null
+++ b/plugins/dvdcss/burn-dvdcss.c
@@ -0,0 +1,698 @@
+/***************************************************************************
+ * burn-dvdcss.c
+ *
+ * lun aoû 21 14:34:32 2006
+ * Copyright 2006 Rouquier Philippe
+ * bonfire-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * TBrasero is free software; you can redistribute itand/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * TBrasero is distributed in the hope that it will be useful
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to t:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.30, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gstdio.h>
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+
+#include "brasero-units.h"
+
+#include "burn-debug.h"
+#include "burn-job.h"
+#include "brasero-plugin-registration.h"
+#include "burn-dvdcss.h"
+#include "burn-dvdcss-private.h"
+#include "burn-volume.h"
+#include "brasero-medium.h"
+#include "brasero-track-image.h"
+#include "brasero-track-disc.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroDvdcss, brasero_dvdcss, BRASERO_TYPE_JOB, BraseroJob);
+
+struct _BraseroDvdcssPrivate {
+ GError *error;
+ GThread *thread;
+ GMutex *mutex;
+ GCond *cond;
+ guint thread_id;
+
+ guint cancel:1;
+};
+typedef struct _BraseroDvdcssPrivate BraseroDvdcssPrivate;
+
+#define BRASERO_DVDCSS_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_DVDCSS, BraseroDvdcssPrivate))
+
+#define BRASERO_DVDCSS_I_BLOCKS 16ULL
+
+static GObjectClass *parent_class = NULL;
+
+static gboolean
+brasero_dvdcss_library_init (GError **error)
+{
+ GModule *module;
+ gpointer address;
+ gchar *dvdcss_interface_2 = NULL;
+
+ if (css_ready)
+ return TRUE;
+
+ /* load libdvdcss library and see the version (mine is 1.2.0) */
+ module = g_module_open ("libdvdcss.so.2", G_MODULE_BIND_LOCAL);
+ if (!module)
+ goto error_doesnt_exist;
+
+ if (!g_module_symbol (module, "dvdcss_interface_2", &address))
+ goto error_version;
+
+ dvdcss_interface_2 = address;
+ BRASERO_BURN_LOG ("libdvdcss version %d.%d.%d\n",
+ (guchar) dvdcss_interface_2 [0],
+ (guchar) dvdcss_interface_2 [1],
+ (guchar) dvdcss_interface_2 [2]);
+
+ if (!g_module_symbol (module, "dvdcss_open", &address))
+ goto error_loading;
+ dvdcss_open = address;
+
+ if (!g_module_symbol (module, "dvdcss_close", &address))
+ goto error_loading;
+ dvdcss_close = address;
+
+ if (!g_module_symbol (module, "dvdcss_read", &address))
+ goto error_loading;
+ dvdcss_read = address;
+
+ if (!g_module_symbol (module, "dvdcss_seek", &address))
+ goto error_loading;
+ dvdcss_seek = address;
+
+ if (!g_module_symbol (module, "dvdcss_error", &address))
+ goto error_loading;
+ dvdcss_error = address;
+
+ css_ready = TRUE;
+ return TRUE;
+
+error_doesnt_exist:
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("Encrypted DVD: please install libdvdcss version 1.2.x"));
+ return FALSE;
+
+error_version:
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("Libdvdcss version %s is not supported.\nPlease install libdvdcss version 1.2.x"),
+ dvdcss_interface_2);
+ g_module_close (module);
+ return FALSE;
+
+
+error_loading:
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("Libdvdcss could not be loaded properly"));
+ g_module_close (module);
+ return FALSE;
+}
+
+static gboolean
+brasero_dvdcss_thread_finished (gpointer data)
+{
+ gchar *image = NULL;
+ BraseroDvdcss *self = data;
+ BraseroDvdcssPrivate *priv;
+ BraseroTrackImage *track = NULL;
+
+ priv = BRASERO_DVDCSS_PRIVATE (self);
+ priv->thread_id = 0;
+
+ if (priv->error) {
+ GError *error;
+
+ error = priv->error;
+ priv->error = NULL;
+ brasero_job_error (BRASERO_JOB (self), error);
+ return FALSE;
+ }
+
+ track = brasero_track_image_new ();
+ brasero_job_get_image_output (BRASERO_JOB (self),
+ &image,
+ NULL);
+ brasero_track_image_set_source (track,
+ image,
+ NULL,
+ BRASERO_IMAGE_FORMAT_BIN);
+
+ brasero_job_add_track (BRASERO_JOB (self), BRASERO_TRACK (track));
+
+ /* It's good practice to unref the track afterwards as we don't need it
+ * anymore. BraseroTaskCtx refs it. */
+ g_object_unref (track);
+
+ brasero_job_finished_track (BRASERO_JOB (self));
+
+ return FALSE;
+}
+
+static BraseroBurnResult
+brasero_dvdcss_write_sector_to_fd (BraseroDvdcss *self,
+ gpointer buffer,
+ gint bytes_remaining)
+{
+ int fd;
+ gint bytes_written = 0;
+ BraseroDvdcssPrivate *priv;
+
+ priv = BRASERO_DVDCSS_PRIVATE (self);
+
+ brasero_job_get_fd_out (BRASERO_JOB (self), &fd);
+ while (bytes_remaining) {
+ gint written;
+
+ written = write (fd,
+ buffer + bytes_written,
+ bytes_remaining);
+
+ if (priv->cancel)
+ break;
+
+ if (written != bytes_remaining) {
+ if (errno != EINTR && errno != EAGAIN) {
+ int errsv = errno;
+
+ /* unrecoverable error */
+ priv->error = g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("Data could not be written (%s)"),
+ g_strerror (errsv));
+ return BRASERO_BURN_ERR;
+ }
+
+ g_thread_yield ();
+ }
+
+ if (written > 0) {
+ bytes_remaining -= written;
+ bytes_written += written;
+ }
+ }
+
+ return BRASERO_BURN_OK;
+}
+
+struct _BraseroScrambledSectorRange {
+ gint start;
+ gint end;
+};
+typedef struct _BraseroScrambledSectorRange BraseroScrambledSectorRange;
+
+static gboolean
+brasero_dvdcss_create_scrambled_sectors_map (GQueue *map,
+ dvdcss_handle *handle,
+ BraseroVolFile *parent,
+ GError **error)
+{
+ GList *iter;
+
+ /* this allows to cache keys for encrypted files */
+ for (iter = parent->specific.dir.children; iter; iter = iter->next) {
+ BraseroVolFile *file;
+
+ file = iter->data;
+ if (!file->isdir) {
+ if (!strncmp (file->name + strlen (file->name) - 6, ".VOB", 4)) {
+ BraseroScrambledSectorRange *range;
+ GSList *extents;
+
+ range = g_new0 (BraseroScrambledSectorRange, 1);
+
+ /* take the first address for each extent of the file */
+ if (!file->specific.file.extents)
+ return FALSE;
+
+ for (extents = file->specific.file.extents; extents; extents = extents->next) {
+ BraseroVolFileExtent *extent;
+
+ extent = extents->data;
+ range->start = extent->block;
+ range->end = extent->block + BRASERO_BYTES_TO_SECTORS (extent->size, DVDCSS_BLOCK_SIZE);
+
+ g_queue_push_head (map, range);
+
+ if (dvdcss_seek (handle, range->start, DVDCSS_SEEK_KEY) != range->start) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("Error reading video DVD (%s)"),
+ dvdcss_error (handle));
+ return FALSE;
+ }
+ }
+ }
+ }
+ else if (!brasero_dvdcss_create_scrambled_sectors_map (map, handle, file, error))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gint
+brasero_dvdcss_sort_ranges (gconstpointer a, gconstpointer b, gpointer user_data)
+{
+ const BraseroScrambledSectorRange *range_a = a;
+ const BraseroScrambledSectorRange *range_b = b;
+
+ return range_a->start - range_b->start;
+}
+
+static gpointer
+brasero_dvdcss_write_image_thread (gpointer data)
+{
+ guchar buf [DVDCSS_BLOCK_SIZE * BRASERO_DVDCSS_I_BLOCKS];
+ BraseroScrambledSectorRange *range = NULL;
+ BraseroMedium *medium = NULL;
+ BraseroVolFile *files = NULL;
+ dvdcss_handle *handle = NULL;
+ BraseroDrive *drive = NULL;
+ BraseroDvdcssPrivate *priv;
+ gint64 written_sectors = 0;
+ BraseroDvdcss *self = data;
+ BraseroTrack *track = NULL;
+ guint64 remaining_sectors;
+ FILE *output_fd = NULL;
+ BraseroVolSrc *vol;
+ gint64 volume_size;
+ GQueue *map = NULL;
+
+ brasero_job_set_use_average_rate (BRASERO_JOB (self), TRUE);
+ brasero_job_set_current_action (BRASERO_JOB (self),
+ BRASERO_BURN_ACTION_ANALYSING,
+ _("Retrieving DVD keys"),
+ FALSE);
+ brasero_job_start_progress (BRASERO_JOB (self), FALSE);
+
+ priv = BRASERO_DVDCSS_PRIVATE (self);
+
+ /* get the contents of the DVD */
+ brasero_job_get_current_track (BRASERO_JOB (self), &track);
+ drive = brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track));
+
+ vol = brasero_volume_source_open_file (brasero_drive_get_device (drive), &priv->error);
+ files = brasero_volume_get_files (vol,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ &priv->error);
+ brasero_volume_source_close (vol);
+ if (!files)
+ goto end;
+
+ medium = brasero_drive_get_medium (drive);
+ brasero_medium_get_data_size (medium, NULL, &volume_size);
+ if (volume_size == -1) {
+ priv->error = g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("The size of the volume could not be retrieved"));
+ goto end;
+ }
+
+ /* create a handle/open DVD */
+ handle = dvdcss_open (brasero_drive_get_device (drive));
+ if (!handle) {
+ priv->error = g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("Video DVD could not be opened"));
+ goto end;
+ }
+
+ /* look through the files to get the ranges of encrypted sectors
+ * and cache the CSS keys while at it. */
+ map = g_queue_new ();
+ if (!brasero_dvdcss_create_scrambled_sectors_map (map, handle, files, &priv->error))
+ goto end;
+
+ g_queue_sort (map, brasero_dvdcss_sort_ranges, NULL);
+
+ brasero_volume_file_free (files);
+ files = NULL;
+
+ if (dvdcss_seek (handle, 0, DVDCSS_NOFLAGS) != 0) {
+ priv->error = g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("Error while reading video DVD (%s)"),
+ dvdcss_error (handle));
+ goto end;
+ }
+
+ brasero_job_set_current_action (BRASERO_JOB (self),
+ BRASERO_BURN_ACTION_DRIVE_COPY,
+ _("Copying Video DVD"),
+ FALSE);
+
+ brasero_job_start_progress (BRASERO_JOB (self), TRUE);
+
+ remaining_sectors = volume_size;
+ range = g_queue_pop_head (map);
+
+ if (brasero_job_get_fd_out (BRASERO_JOB (self), NULL) != BRASERO_BURN_OK) {
+ gchar *output = NULL;
+
+ brasero_job_get_image_output (BRASERO_JOB (self), &output, NULL);
+ output_fd = fopen (output, "w");
+ g_free (output);
+
+ if (!output_fd) {
+ priv->error = g_error_new_literal (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ g_strerror (errno));
+ goto end;
+ }
+ }
+
+ while (remaining_sectors) {
+ gint flag;
+ guint64 num_blocks, data_size;
+
+ if (priv->cancel)
+ break;
+
+ num_blocks = BRASERO_DVDCSS_I_BLOCKS;
+
+ /* see if we are approaching the end of the dvd */
+ if (num_blocks > remaining_sectors)
+ num_blocks = remaining_sectors;
+
+ /* see if we need to update the key */
+ if (!range || written_sectors < range->start) {
+ /* this is in a non scrambled sectors range */
+ flag = DVDCSS_NOFLAGS;
+
+ /* we don't want to mix scrambled and non scrambled sectors */
+ if (range && written_sectors + num_blocks > range->start)
+ num_blocks = range->start - written_sectors;
+ }
+ else {
+ /* this is in a scrambled sectors range */
+ flag = DVDCSS_READ_DECRYPT;
+
+ /* see if we need to update the key */
+ if (written_sectors == range->start
+ && dvdcss_seek (handle, written_sectors, DVDCSS_SEEK_KEY) != written_sectors) {
+ priv->error = g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("Error while reading video DVD (%s)"),
+ dvdcss_error (handle));
+ break;
+ }
+
+ /* we don't want to mix scrambled and non scrambled sectors
+ * NOTE: range->end address is the next non scrambled sector */
+ if (written_sectors + num_blocks > range->end)
+ num_blocks = range->end - written_sectors;
+
+ if (written_sectors + num_blocks == range->end) {
+ /* update to get the next range of scrambled sectors */
+ g_free (range);
+ range = g_queue_pop_head (map);
+ }
+ }
+
+ if (dvdcss_read (handle, buf, num_blocks, flag) != num_blocks) {
+ priv->error = g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("Error while reading video DVD (%s)"),
+ dvdcss_error (handle));
+ break;
+ }
+
+ data_size = num_blocks * DVDCSS_BLOCK_SIZE;
+ if (output_fd) {
+ if (fwrite (buf, 1, data_size, output_fd) != data_size) {
+ int errsv = errno;
+
+ priv->error = g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("Data could not be written (%s)"),
+ g_strerror (errsv));
+ break;
+ }
+ }
+ else {
+ BraseroBurnResult result;
+
+ result = brasero_dvdcss_write_sector_to_fd (self,
+ buf,
+ data_size);
+ if (result != BRASERO_BURN_OK)
+ break;
+ }
+
+ written_sectors += num_blocks;
+ remaining_sectors -= num_blocks;
+ brasero_job_set_written_track (BRASERO_JOB (self), written_sectors * DVDCSS_BLOCK_SIZE);
+ }
+
+end:
+
+ if (range)
+ g_free (range);
+
+ if (handle)
+ dvdcss_close (handle);
+
+ if (files)
+ brasero_volume_file_free (files);
+
+ if (output_fd)
+ fclose (output_fd);
+
+ if (map) {
+ g_queue_foreach (map, (GFunc) g_free, NULL);
+ g_queue_free (map);
+ }
+
+ if (!priv->cancel)
+ priv->thread_id = g_idle_add (brasero_dvdcss_thread_finished, self);
+
+ /* End thread */
+ g_mutex_lock (priv->mutex);
+ priv->thread = NULL;
+ g_cond_signal (priv->cond);
+ g_mutex_unlock (priv->mutex);
+
+ g_thread_exit (NULL);
+
+ return NULL;
+}
+
+static BraseroBurnResult
+brasero_dvdcss_start (BraseroJob *job,
+ GError **error)
+{
+ BraseroDvdcss *self;
+ BraseroJobAction action;
+ BraseroDvdcssPrivate *priv;
+ GError *thread_error = NULL;
+
+ self = BRASERO_DVDCSS (job);
+ priv = BRASERO_DVDCSS_PRIVATE (self);
+
+ brasero_job_get_action (job, &action);
+ if (action == BRASERO_JOB_ACTION_SIZE) {
+ guint64 blocks = 0;
+ BraseroTrack *track;
+
+ brasero_job_get_current_track (job, &track);
+ brasero_track_get_size (track, &blocks, NULL);
+ brasero_job_set_output_size_for_current_track (job,
+ blocks,
+ blocks * DVDCSS_BLOCK_SIZE);
+ return BRASERO_BURN_NOT_RUNNING;
+ }
+
+ if (action != BRASERO_JOB_ACTION_IMAGE)
+ return BRASERO_BURN_NOT_SUPPORTED;
+
+ if (priv->thread)
+ return BRASERO_BURN_RUNNING;
+
+ if (!brasero_dvdcss_library_init (error))
+ return BRASERO_BURN_ERR;
+
+ g_mutex_lock (priv->mutex);
+ priv->thread = g_thread_create (brasero_dvdcss_write_image_thread,
+ self,
+ TRUE,
+ &thread_error);
+ g_mutex_unlock (priv->mutex);
+
+ /* Reminder: this is not necessarily an error as the thread may have finished */
+ //if (!priv->thread)
+ // return BRASERO_BURN_ERR;
+ if (thread_error) {
+ g_propagate_error (error, thread_error);
+ return BRASERO_BURN_ERR;
+ }
+
+ return BRASERO_BURN_OK;
+}
+
+static void
+brasero_dvdcss_stop_real (BraseroDvdcss *self)
+{
+ BraseroDvdcssPrivate *priv;
+
+ priv = BRASERO_DVDCSS_PRIVATE (self);
+
+ g_mutex_lock (priv->mutex);
+ if (priv->thread) {
+ priv->cancel = 1;
+ g_cond_wait (priv->cond, priv->mutex);
+ priv->cancel = 0;
+ }
+ g_mutex_unlock (priv->mutex);
+
+ if (priv->thread_id) {
+ g_source_remove (priv->thread_id);
+ priv->thread_id = 0;
+ }
+
+ if (priv->error) {
+ g_error_free (priv->error);
+ priv->error = NULL;
+ }
+}
+
+static BraseroBurnResult
+brasero_dvdcss_stop (BraseroJob *job,
+ GError **error)
+{
+ BraseroDvdcss *self;
+
+ self = BRASERO_DVDCSS (job);
+
+ brasero_dvdcss_stop_real (self);
+ return BRASERO_BURN_OK;
+}
+
+static void
+brasero_dvdcss_class_init (BraseroDvdcssClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ BraseroJobClass *job_class = BRASERO_JOB_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (BraseroDvdcssPrivate));
+
+ parent_class = g_type_class_peek_parent (klass);
+ object_class->finalize = brasero_dvdcss_finalize;
+
+ job_class->start = brasero_dvdcss_start;
+ job_class->stop = brasero_dvdcss_stop;
+}
+
+static void
+brasero_dvdcss_init (BraseroDvdcss *obj)
+{
+ BraseroDvdcssPrivate *priv;
+
+ priv = BRASERO_DVDCSS_PRIVATE (obj);
+
+ priv->mutex = g_mutex_new ();
+ priv->cond = g_cond_new ();
+}
+
+static void
+brasero_dvdcss_finalize (GObject *object)
+{
+ BraseroDvdcssPrivate *priv;
+
+ priv = BRASERO_DVDCSS_PRIVATE (object);
+
+ brasero_dvdcss_stop_real (BRASERO_DVDCSS (object));
+
+ if (priv->mutex) {
+ g_mutex_free (priv->mutex);
+ priv->mutex = NULL;
+ }
+
+ if (priv->cond) {
+ g_cond_free (priv->cond);
+ priv->cond = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static BraseroBurnResult
+brasero_dvdcss_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+ GError *gerror = NULL;
+ GSList *output;
+ GSList *input;
+
+ brasero_plugin_define (plugin,
+ "dvdcss",
+ _("Dvdcss allows to read css encrypted video DVDs"),
+ "Philippe Rouquier",
+ 0);
+
+ /* see if libdvdcss can be initted */
+ if (!brasero_dvdcss_library_init (&gerror)) {
+ if (gerror) {
+ *error = g_strdup (gerror->message);
+ g_error_free (gerror);
+ }
+ return BRASERO_BURN_ERR;
+ }
+
+ /* to my knowledge, css can only be applied to pressed discs so no need
+ * to specify anything else but ROM */
+ output = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE|
+ BRASERO_PLUGIN_IO_ACCEPT_PIPE,
+ BRASERO_IMAGE_FORMAT_BIN);
+ input = brasero_caps_disc_new (BRASERO_MEDIUM_DVD|
+ BRASERO_MEDIUM_DUAL_L|
+ BRASERO_MEDIUM_ROM|
+ BRASERO_MEDIUM_CLOSED|
+ BRASERO_MEDIUM_HAS_DATA|
+ BRASERO_MEDIUM_PROTECTED);
+
+ brasero_plugin_link_caps (plugin, output, input);
+
+ g_slist_free (input);
+ g_slist_free (output);
+
+ return BRASERO_BURN_OK;
+}
diff --git a/plugins/dvdcss/burn-dvdcss.h b/plugins/dvdcss/burn-dvdcss.h
new file mode 100644
index 0000000..0ccae4c
--- /dev/null
+++ b/plugins/dvdcss/burn-dvdcss.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+ * burn-dvdcss.h
+ *
+ * lun aoû 21 14:34:32 2006
+ * Copyright 2006 Rouquier Philippe
+ * bonfire-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib-object.h>
+
+#ifndef BURN_DVDCSS_H
+#define BURN_DVDCSS_H
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_DVDCSS (brasero_dvdcss_get_type ())
+#define BRASERO_DVDCSS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_DVDCSS, BraseroDvdcss))
+#define BRASERO_DVDCSS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_DVDCSS, BraseroDvdcssClass))
+#define BRASERO_IS_DVDCSS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_DVDCSS))
+#define BRASERO_IS_DVDCSS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_DVDCSS))
+#define BRASERO_DVDCSS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_DVDCSS, BraseroDvdcssClass))
+
+G_END_DECLS
+
+#endif /* BURN_DVDCSS_H */
diff --git a/plugins/growisofs/Makefile.am b/plugins/growisofs/Makefile.am
new file mode 100644
index 0000000..eb128f0
--- /dev/null
+++ b/plugins/growisofs/Makefile.am
@@ -0,0 +1,30 @@
+
+INCLUDES = \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/libbrasero-media/ \
+ -I$(top_builddir)/libbrasero-media/ \
+ -I$(top_srcdir)/libbrasero-burn \
+ -I$(top_builddir)/libbrasero-burn/ \
+ -DBRASERO_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
+ -DBRASERO_PREFIX=\"$(prefix)\" \
+ -DBRASERO_SYSCONFDIR=\"$(sysconfdir)\" \
+ -DBRASERO_DATADIR=\"$(datadir)/brasero\" \
+ -DBRASERO_LIBDIR=\"$(libdir)\" \
+ $(DISABLE_DEPRECATED) \
+ $(BRASERO_GLIB_CFLAGS) \
+ $(BRASERO_GCONF_CFLAGS)
+
+#growisofs
+growisofsdir = $(libdir)/brasero/plugins
+growisofs_LTLIBRARIES = libbrasero-growisofs.la
+libbrasero_growisofs_la_SOURCES = burn-growisofs.c burn-growisofs.h \
+ burn-growisofs-common.h
+libbrasero_growisofs_la_LIBADD = $(BRASERO_GLIB_LIBS) $(BRASERO_GCONF_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_growisofs_la_LDFLAGS = -module -avoid-version
+
+#dvdrwformat
+dvdrwformatdir = $(libdir)/brasero/plugins
+dvdrwformat_LTLIBRARIES = libbrasero-dvdrwformat.la
+libbrasero_dvdrwformat_la_SOURCES = burn-dvd-rw-format.c burn-dvd-rw-format.h
+libbrasero_dvdrwformat_la_LIBADD = $(BRASERO_GLIB_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_dvdrwformat_la_LDFLAGS = -module -avoid-version
diff --git a/plugins/growisofs/burn-dvd-rw-format.c b/plugins/growisofs/burn-dvd-rw-format.c
new file mode 100644
index 0000000..e0be9c5
--- /dev/null
+++ b/plugins/growisofs/burn-dvd-rw-format.c
@@ -0,0 +1,212 @@
+/***************************************************************************
+ * dvd-rw-format.c
+ *
+ * sam fév 4 13:50:07 2006
+ * Copyright 2006 Rouquier Philippe
+ * brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+
+#include <gmodule.h>
+
+#include "burn-basics.h"
+#include "brasero-plugin.h"
+#include "brasero-plugin-registration.h"
+#include "burn-job.h"
+#include "burn-process.h"
+#include "brasero-medium.h"
+#include "burn-dvd-rw-format.h"
+#include "burn-growisofs-common.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroDvdRwFormat, brasero_dvd_rw_format, BRASERO_TYPE_PROCESS, BraseroProcess);
+
+static GObjectClass *parent_class = NULL;
+
+static BraseroBurnResult
+brasero_dvd_rw_format_read_stderr (BraseroProcess *process, const gchar *line)
+{
+ int perc_1 = 0, perc_2 = 0;
+ float percent;
+
+ if (strstr (line, "unable to proceed with format")
+ || strstr (line, "media is not blank")
+ || strstr (line, "media is already formatted")
+ || strstr (line, "you have the option to re-run")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_MEDIUM_INVALID,
+ _("The disc is not supported")));
+ return BRASERO_BURN_OK;
+ }
+ else if (strstr (line, "unable to umount")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_DRIVE_BUSY,
+ _("The drive is busy")));
+ return BRASERO_BURN_OK;
+ }
+
+ if ((sscanf (line, "* blanking %d.%1d%%,", &perc_1, &perc_2) == 2)
+ || (sscanf (line, "* formatting %d.%1d%%,", &perc_1, &perc_2) == 2)
+ || (sscanf (line, "* relocating lead-out %d.%1d%%,", &perc_1, &perc_2) == 2))
+ brasero_job_set_dangerous (BRASERO_JOB (process), TRUE);
+ else
+ sscanf (line, "%d.%1d%%", &perc_1, &perc_2);
+
+ percent = (float) perc_1 / 100.0 + (float) perc_2 / 1000.0;
+ if (percent) {
+ brasero_job_start_progress (BRASERO_JOB (process), FALSE);
+ brasero_job_set_progress (BRASERO_JOB (process), percent);
+ }
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_dvd_rw_format_set_argv (BraseroProcess *process,
+ GPtrArray *argv,
+ GError **error)
+{
+ BraseroMedia media;
+ BraseroBurnFlag flags;
+ gchar *device;
+
+ g_ptr_array_add (argv, g_strdup ("dvd+rw-format"));
+
+ /* undocumented option to show progress */
+ g_ptr_array_add (argv, g_strdup ("-gui"));
+
+ brasero_job_get_media (BRASERO_JOB (process), &media);
+ brasero_job_get_flags (BRASERO_JOB (process), &flags);
+ if (!BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_BDRE)
+ && !BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_DVDRW_PLUS)
+ && !BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_DVDRW_RESTRICTED)) {
+ gchar *blank_str;
+
+ /* This creates a sequential DVD-RW */
+ blank_str = g_strdup_printf ("-blank%s",
+ (flags & BRASERO_BURN_FLAG_FAST_BLANK) ? "" : "=full");
+ g_ptr_array_add (argv, blank_str);
+ }
+ else {
+ gchar *format_str;
+
+ /* This creates a restricted overwrite DVD-RW or reformat a + */
+ format_str = g_strdup ("-force");
+ g_ptr_array_add (argv, format_str);
+ }
+
+ brasero_job_get_device (BRASERO_JOB (process), &device);
+ g_ptr_array_add (argv, device);
+
+ brasero_job_set_current_action (BRASERO_JOB (process),
+ BRASERO_BURN_ACTION_BLANKING,
+ NULL,
+ FALSE);
+ return BRASERO_BURN_OK;
+}
+
+static void
+brasero_dvd_rw_format_class_init (BraseroDvdRwFormatClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ BraseroProcessClass *process_class = BRASERO_PROCESS_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent(klass);
+ object_class->finalize = brasero_dvd_rw_format_finalize;
+
+ process_class->set_argv = brasero_dvd_rw_format_set_argv;
+ process_class->stderr_func = brasero_dvd_rw_format_read_stderr;
+ process_class->post = brasero_job_finished_session;
+}
+
+static void
+brasero_dvd_rw_format_init (BraseroDvdRwFormat *obj)
+{ }
+
+static void
+brasero_dvd_rw_format_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static BraseroBurnResult
+brasero_dvd_rw_format_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+ /* NOTE: sequential and restricted are added later on demand */
+ const BraseroMedia media = BRASERO_MEDIUM_DVD|
+ BRASERO_MEDIUM_DUAL_L|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_CLOSED|
+ BRASERO_MEDIUM_HAS_DATA|
+ BRASERO_MEDIUM_UNFORMATTED|
+ BRASERO_MEDIUM_BLANK;
+ BraseroBurnResult result;
+ GSList *output;
+
+ brasero_plugin_define (plugin,
+ "dvd+rw-format",
+ _("Dvd+rw-format erases and formats DVD+/-R(W)"),
+ "Philippe Rouquier",
+ 4);
+
+ /* First see if this plugin can be used */
+ result = brasero_process_check_path ("dvd+rw-format", error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+
+ output = brasero_caps_disc_new (media|
+ BRASERO_MEDIUM_BDRE|
+ BRASERO_MEDIUM_PLUS|
+ BRASERO_MEDIUM_RESTRICTED|
+ BRASERO_MEDIUM_SEQUENTIAL);
+ brasero_plugin_blank_caps (plugin, output);
+ g_slist_free (output);
+
+ brasero_plugin_set_blank_flags (plugin,
+ media|
+ BRASERO_MEDIUM_BDRE|
+ BRASERO_MEDIUM_PLUS|
+ BRASERO_MEDIUM_RESTRICTED,
+ BRASERO_BURN_FLAG_NOGRACE,
+ BRASERO_BURN_FLAG_NONE);
+ brasero_plugin_set_blank_flags (plugin,
+ media|
+ BRASERO_MEDIUM_SEQUENTIAL,
+ BRASERO_BURN_FLAG_NOGRACE|
+ BRASERO_BURN_FLAG_FAST_BLANK,
+ BRASERO_BURN_FLAG_NONE);
+
+ brasero_plugin_register_group (plugin, _(GROWISOFS_DESCRIPTION));
+
+ return BRASERO_BURN_OK;
+}
diff --git a/plugins/growisofs/burn-dvd-rw-format.h b/plugins/growisofs/burn-dvd-rw-format.h
new file mode 100644
index 0000000..9e25f46
--- /dev/null
+++ b/plugins/growisofs/burn-dvd-rw-format.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+ * dvd-rw-format.h
+ *
+ * sam fév 4 13:50:07 2006
+ * Copyright 2006 Rouquier Philippe
+ * brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef DVD_RW_FORMAT_H
+#define DVD_RW_FORMAT_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "burn-process.h"
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_DVD_RW_FORMAT (brasero_dvd_rw_format_get_type ())
+#define BRASERO_DVD_RW_FORMAT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_DVD_RW_FORMAT, BraseroDvdRwFormat))
+#define BRASERO_DVD_RW_FORMAT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_DVD_RW_FORMAT, BraseroDvdRwFormatClass))
+#define BRASERO_IS_DVD_RW_FORMAT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_DVD_RW_FORMAT))
+#define BRASERO_IS_DVD_RW_FORMAT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_DVD_RW_FORMAT))
+#define BRASERO_DVD_RW_FORMAT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_DVD_RW_FORMAT, BraseroDvdRwFormatClass))
+
+G_END_DECLS
+
+#endif /* DVD_RW_FORMAT_H */
diff --git a/plugins/growisofs/burn-growisofs-common.h b/plugins/growisofs/burn-growisofs-common.h
new file mode 100644
index 0000000..6250ba5
--- /dev/null
+++ b/plugins/growisofs/burn-growisofs-common.h
@@ -0,0 +1,39 @@
+/***************************************************************************
+ * burn-growisofs-common.h
+ *
+ * Mon Oct 29 12:37:28 2007
+ * Copyright 2007 Philippe Rouquier
+ * <bonfire-app wanadoo fr>
+ ****************************************************************************/
+
+/*
+ * Libbrasero-media is free software; you can redistribute it and/or modify
+fy
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA
+ */
+
+#ifndef _BURN_GROWISOFS_COMMON_H
+#define _BURN_GROWISOFS_COMMON_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define GROWISOFS_DESCRIPTION N_("Growisofs burning suite")
+
+G_END_DECLS
+
+#endif /* _BURN_GROWISOFS_COMMON_H */
+
+
diff --git a/plugins/growisofs/burn-growisofs.c b/plugins/growisofs/burn-growisofs.c
new file mode 100644
index 0000000..a544445
--- /dev/null
+++ b/plugins/growisofs/burn-growisofs.c
@@ -0,0 +1,924 @@
+/***************************************************************************
+ * growisofs.c
+ *
+ * dim jan 15:8:51 6
+ * Copyright 6 Rouquier Philippe
+ * brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.t, Fifth Floor
+ * Boston, MA 02110-1301, USA., Boston, MA 111-17, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+
+#include <gmodule.h>
+
+#include <gconf/gconf-client.h>
+
+#include "brasero-units.h"
+
+#include "brasero-plugin-registration.h"
+#include "burn-job.h"
+#include "burn-process.h"
+#include "brasero-drive.h"
+#include "burn-growisofs.h"
+#include "burn-growisofs-common.h"
+#include "brasero-track-data.h"
+#include "brasero-track-image.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroGrowisofs, brasero_growisofs, BRASERO_TYPE_PROCESS, BraseroProcess);
+
+struct BraseroGrowisofsPrivate {
+ guint use_utf8:1;
+ guint use_genisoimage:1;
+ guint use_dao:1;
+};
+typedef struct BraseroGrowisofsPrivate BraseroGrowisofsPrivate;
+
+#define BRASERO_GROWISOFS_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_GROWISOFS, BraseroGrowisofsPrivate))
+
+static GObjectClass *parent_class = NULL;
+
+#define GCONF_KEY_DAO_FLAG "/apps/brasero/config/dao_flag"
+
+/* Process start */
+static BraseroBurnResult
+brasero_growisofs_read_stdout (BraseroProcess *process, const gchar *line)
+{
+ int perc_1, perc_2;
+ int speed_1, speed_2;
+ long long b_written, b_total;
+
+ /* Newer growisofs version have a different line pattern that shows
+ * drive buffer filling. */
+ if (sscanf (line, "%10lld/%lld (%4d.%1d%%) @%2d.%1dx, remaining %*d:%*d",
+ &b_written, &b_total, &perc_1, &perc_2, &speed_1, &speed_2) == 6) {
+ BraseroJobAction action;
+
+ brasero_job_get_action (BRASERO_JOB (process), &action);
+ if (action == BRASERO_JOB_ACTION_ERASE && b_written >= 65536) {
+ /* we nullified 65536 that's enough. A signal SIGTERM
+ * will be sent in process.c. That's not the best way
+ * to do it but it works. */
+ brasero_job_finished_session (BRASERO_JOB (process));
+ return BRASERO_BURN_OK;
+ }
+
+ brasero_job_set_written_session (BRASERO_JOB (process), b_written);
+ brasero_job_set_rate (BRASERO_JOB (process), (gdouble) (speed_1 * 10 + speed_2) / 10.0 * (gdouble) DVD_RATE);
+
+ if (action == BRASERO_JOB_ACTION_ERASE) {
+ brasero_job_set_current_action (BRASERO_JOB (process),
+ BRASERO_BURN_ACTION_BLANKING,
+ NULL,
+ FALSE);
+ }
+ else
+ brasero_job_set_current_action (BRASERO_JOB (process),
+ BRASERO_BURN_ACTION_RECORDING,
+ NULL,
+ FALSE);
+
+ brasero_job_start_progress (BRASERO_JOB (process), FALSE);
+ }
+ else if (strstr (line, "About to execute") || strstr (line, "Executing"))
+ brasero_job_set_dangerous (BRASERO_JOB (process), TRUE);
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_growisofs_read_stderr (BraseroProcess *process, const gchar *line)
+{
+ int perc_1, perc_2;
+
+ if (sscanf (line, " %2d.%2d%% done, estimate finish", &perc_1, &perc_2) == 2) {
+ gdouble fraction;
+ BraseroBurnAction action;
+
+ fraction = (gdouble) ((gdouble) perc_1 +
+ ((gdouble) perc_2 / (gdouble) 100.0)) /
+ (gdouble) 100.0;
+
+ brasero_job_set_progress (BRASERO_JOB (process), fraction);
+
+ brasero_job_get_current_action (BRASERO_JOB (process), &action);
+ if (action == BRASERO_BURN_ACTION_BLANKING
+ && fraction >= 0.01) {
+ /* we nullified 1% of the medium (more than 65536)
+ * that's enough to make the filesystem unusable and
+ * looking blank. A signal SIGTERM will be sent to stop
+ * us. */
+ brasero_job_finished_session (BRASERO_JOB (process));
+ return BRASERO_BURN_OK;
+ }
+
+ brasero_job_set_current_action (BRASERO_JOB (process),
+ BRASERO_BURN_ACTION_RECORDING,
+ NULL,
+ FALSE);
+ brasero_job_start_progress (BRASERO_JOB (process), FALSE);
+ }
+ else if (strstr (line, "Total extents scheduled to be written = ")) {
+ BraseroJobAction action;
+
+ line += strlen ("Total extents scheduled to be written = ");
+ brasero_job_get_action (BRASERO_JOB (process), &action);
+ if (action == BRASERO_JOB_ACTION_SIZE) {
+ gint64 sectors;
+
+ sectors = strtoll (line, NULL, 10);
+
+ /* NOTE: this has to be a multiple of 2048 */
+ brasero_job_set_output_size_for_current_track (BRASERO_JOB (process),
+ sectors,
+ sectors * 2048ULL);
+
+ /* we better tell growisofs to stop here as it returns
+ * a value of 1 when mkisofs is run with --print-size */
+ brasero_job_finished_session (BRASERO_JOB (process));
+ }
+ }
+ else if (strstr (line, "flushing cache") != NULL) {
+ brasero_job_set_progress (BRASERO_JOB (process), 1.0);
+ brasero_job_set_current_action (BRASERO_JOB (process),
+ BRASERO_BURN_ACTION_FIXATING,
+ NULL,
+ FALSE);
+ }
+ else if (strstr (line, "unable to open")
+ || strstr (line, "unable to stat")
+ || strstr (line, "unable to proceed with recording: unable to unmount")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new_literal (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_DRIVE_BUSY,
+ _("The drive is busy")));
+ }
+ else if (strstr (line, "not enough space available")
+ || strstr (line, "end of user area encountered on this track")
+ || strstr (line, "blocks are free")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_MEDIUM_SPACE,
+ _("Not enough space available on the disc")));
+ }
+ else if (strstr (line, "Input/output error. Read error on old image")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new_literal (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_IMAGE_LAST_SESSION,
+ _("Last session import failed")));
+ }
+ else if (strstr (line, "Unable to sort directory")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new_literal (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_WRITE_IMAGE,
+ _("An image could not be created")));
+ }
+ else if (strstr (line, "have the same joliet name")
+ || strstr (line, "Joliet tree sort failed.")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new_literal (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_IMAGE_JOLIET,
+ _("An image could not be created")));
+ }
+ else if (strstr (line, "Incorrectly encoded string")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new_literal (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_INPUT_INVALID,
+ _("Some files have invalid filenames")));
+ }
+ else if (strstr (line, "Unknown charset")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new_literal (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_INPUT_INVALID,
+ _("Unknown character encoding")));
+ }
+
+ /** REMINDER! removed messages:
+ else if (strstr (line, ":-(") != NULL || strstr (line, "FATAL"))
+
+ else if (strstr (line, "already carries isofs") && strstr (line, "FATAL:")) {
+ brasero_job_error (BRASERO_JOB (process),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_MEDIUM_INVALID,
+ _("The disc is already burnt")));
+ }
+ **/
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_growisofs_set_mkisofs_argv (BraseroGrowisofs *growisofs,
+ GPtrArray *argv,
+ GError **error)
+{
+ BraseroGrowisofsPrivate *priv;
+ BraseroTrack *track = NULL;
+ gchar *excluded_path = NULL;
+ gchar *grafts_path = NULL;
+ BraseroJobAction action;
+ BraseroBurnResult result;
+ BraseroImageFS fs_type;
+ gchar *emptydir = NULL;
+ gchar *videodir = NULL;
+
+ priv = BRASERO_GROWISOFS_PRIVATE (growisofs);
+
+ if (priv->use_genisoimage) {
+ BRASERO_JOB_LOG (growisofs, "Using genisoimage");
+ }
+ else {
+ BRASERO_JOB_LOG (growisofs, "Using mkisofs");
+ }
+
+ g_ptr_array_add (argv, g_strdup ("-r"));
+
+ brasero_job_get_current_track (BRASERO_JOB (growisofs), &track);
+ fs_type = brasero_track_data_get_fs (BRASERO_TRACK_DATA (track));
+ if (fs_type & BRASERO_IMAGE_FS_JOLIET)
+ g_ptr_array_add (argv, g_strdup ("-J"));
+
+ if ((fs_type & BRASERO_IMAGE_FS_ISO)
+ && (fs_type & BRASERO_IMAGE_ISO_FS_LEVEL_3)) {
+ /* That's the safest option. A few OS don't support that though,
+ * like MacOSX and freebsd.*/
+ g_ptr_array_add (argv, g_strdup ("-iso-level"));
+ g_ptr_array_add (argv, g_strdup ("3"));
+
+ /* NOTE: the following is specific to genisoimage
+ * It allows to burn files over 4 GiB.
+ * The only problem here is which are we using? mkisofs or
+ * genisoimage? That's what we determined first. */
+ if (priv->use_genisoimage)
+ g_ptr_array_add (argv, g_strdup ("-allow-limited-size"));
+ }
+
+ if (fs_type & BRASERO_IMAGE_FS_UDF)
+ g_ptr_array_add (argv, g_strdup ("-udf"));
+
+ if (fs_type & BRASERO_IMAGE_FS_VIDEO) {
+ g_ptr_array_add (argv, g_strdup ("-dvd-video"));
+
+ result = brasero_job_get_tmp_dir (BRASERO_JOB (growisofs),
+ &videodir,
+ error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+ }
+
+ if (priv->use_utf8) {
+ g_ptr_array_add (argv, g_strdup ("-input-charset"));
+ g_ptr_array_add (argv, g_strdup ("utf8"));
+ }
+
+ g_ptr_array_add (argv, g_strdup ("-graft-points"));
+
+ if (fs_type & BRASERO_IMAGE_ISO_FS_DEEP_DIRECTORY)
+ g_ptr_array_add (argv, g_strdup ("-D")); // This is dangerous the manual says but apparently it works well
+
+ result = brasero_job_get_tmp_file (BRASERO_JOB (growisofs),
+ NULL,
+ &grafts_path,
+ error);
+ if (result != BRASERO_BURN_OK) {
+ g_free (videodir);
+ return result;
+ }
+
+ result = brasero_job_get_tmp_file (BRASERO_JOB (growisofs),
+ NULL,
+ &excluded_path,
+ error);
+ if (result != BRASERO_BURN_OK) {
+ g_free (grafts_path);
+ g_free (videodir);
+ return result;
+ }
+
+ result = brasero_job_get_tmp_dir (BRASERO_JOB (growisofs),
+ &emptydir,
+ error);
+ if (result != BRASERO_BURN_OK) {
+ g_free (videodir);
+ g_free (grafts_path);
+ g_free (excluded_path);
+ return result;
+ }
+
+ result = brasero_track_data_get_paths (BRASERO_TRACK_DATA (track),
+ (fs_type & BRASERO_IMAGE_FS_JOLIET) != 0,
+ grafts_path,
+ excluded_path,
+ emptydir,
+ videodir,
+ error);
+ g_free (emptydir);
+
+ if (result != BRASERO_BURN_OK) {
+ g_free (videodir);
+ g_free (grafts_path);
+ g_free (excluded_path);
+ return result;
+ }
+
+ g_ptr_array_add (argv, g_strdup ("-path-list"));
+ g_ptr_array_add (argv, grafts_path);
+
+ g_ptr_array_add (argv, g_strdup ("-exclude-list"));
+ g_ptr_array_add (argv, excluded_path);
+
+ brasero_job_get_action (BRASERO_JOB (growisofs), &action);
+ if (action != BRASERO_JOB_ACTION_SIZE) {
+ gchar *label = NULL;
+
+ brasero_job_get_data_label (BRASERO_JOB (growisofs), &label);
+ if (label) {
+ g_ptr_array_add (argv, g_strdup ("-V"));
+ g_ptr_array_add (argv, label);
+ }
+
+ g_ptr_array_add (argv, g_strdup ("-A"));
+ g_ptr_array_add (argv, g_strdup_printf ("Brasero-%i.%i.%i",
+ BRASERO_MAJOR_VERSION,
+ BRASERO_MINOR_VERSION,
+ BRASERO_SUB));
+
+ g_ptr_array_add (argv, g_strdup ("-sysid"));
+ g_ptr_array_add (argv, g_strdup ("LINUX"));
+
+ /* FIXME! -sort is an interesting option allowing to decide where the
+ * files are written on the disc and therefore to optimize later reading */
+ /* FIXME: -hidden --hidden-list -hide-jolie -hide-joliet-list will allow to hide
+ * some files when we will display the contents of a disc we will want to merge */
+ /* FIXME: support preparer publisher options */
+
+ g_ptr_array_add (argv, g_strdup ("-v"));
+ }
+ else {
+ /* we don't specify -q as there wouldn't be anything */
+ g_ptr_array_add (argv, g_strdup ("-print-size"));
+ }
+
+ if (videodir) {
+ g_ptr_array_add (argv, g_strdup ("-f"));
+ g_ptr_array_add (argv, videodir);
+ }
+
+ return BRASERO_BURN_OK;
+}
+
+/**
+ * Some info about use-the-force-luke options
+ * dry-run => stops after invoking mkisofs
+ * no_tty => avoids fatal error if an isofs exists and an image is piped
+ * => skip the five seconds waiting
+ *
+ */
+
+static BraseroBurnResult
+brasero_growisofs_set_argv_record (BraseroGrowisofs *growisofs,
+ GPtrArray *argv,
+ GError **error)
+{
+ BraseroBurnResult result;
+ BraseroJobAction action;
+ BraseroBurnFlag flags;
+ guint64 sectors = 0;
+ gchar *device;
+ guint speed;
+
+ /* This seems to help to eject tray after burning (at least with mine) */
+ g_ptr_array_add (argv, g_strdup ("growisofs"));
+ g_ptr_array_add (argv, g_strdup ("-use-the-force-luke=notray"));
+
+ brasero_job_get_flags (BRASERO_JOB (growisofs), &flags);
+ if (flags & BRASERO_BURN_FLAG_DUMMY)
+ g_ptr_array_add (argv, g_strdup ("-use-the-force-luke=dummy"));
+
+ /* NOTE 1: dao is not a good thing if you want to make multisession
+ * DVD+-R. It will close the disc. Which make sense since DAO means
+ * Disc At Once. That's checked in burn-caps.c with coherency checks.
+ * NOTE 2: dao is supported for DL DVD after 6.0 (think about that for
+ * BurnCaps)
+ * Moreover even for single session DVDs it doesn't work properly so
+ * there is a workaround to turn it off entirely. */
+ if (flags & BRASERO_BURN_FLAG_DAO)
+ g_ptr_array_add (argv, g_strdup ("-use-the-force-luke=dao"));
+
+ /* This is necessary for multi session discs when a new session starts
+ * beyond the 4Gio boundary since it may not be readable afterward.
+ * To work, this requires a kernel > 2.6.8.
+ * FIXME: This would deserve a flag to warn the user. */
+ g_ptr_array_add (argv, g_strdup ("-use-the-force-luke=4gms"));
+
+ if (!(flags & BRASERO_BURN_FLAG_MULTI)) {
+ /* This option seems to help creating DVD more compatible
+ * with DVD readers.
+ * NOTE: it doesn't work with DVD+RW and DVD-RW in restricted
+ * overwrite mode */
+ g_ptr_array_add (argv, g_strdup ("-dvd-compat"));
+ }
+
+ brasero_job_get_speed (BRASERO_JOB (growisofs), &speed);
+ if (speed > 0)
+ g_ptr_array_add (argv, g_strdup_printf ("-speed=%d", speed));
+
+ /* see if we're asked to merge some new data: in this case we MUST have
+ * a list of grafts. The image can't come through stdin or an already
+ * made image */
+ brasero_job_get_device (BRASERO_JOB (growisofs), &device);
+ brasero_job_get_action (BRASERO_JOB (growisofs), &action);
+ brasero_job_get_session_output_size (BRASERO_JOB (growisofs),
+ §ors,
+ NULL);
+ if (sectors) {
+ /* NOTE: tracksize is in block number (2048 bytes) */
+ g_ptr_array_add (argv,
+ g_strdup_printf ("-use-the-force-luke=tracksize:%"
+ G_GINT64_FORMAT,
+ sectors));
+ }
+
+ if (flags & BRASERO_BURN_FLAG_MERGE) {
+ g_ptr_array_add (argv, g_strdup ("-M"));
+ g_ptr_array_add (argv, device);
+
+ /* this can only happen if source->type == BRASERO_TRACK_SOURCE_GRAFTS */
+ if (action == BRASERO_JOB_ACTION_SIZE)
+ g_ptr_array_add (argv, g_strdup ("-dry-run"));
+
+ result = brasero_growisofs_set_mkisofs_argv (growisofs,
+ argv,
+ error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+ }
+ else {
+ BraseroTrack *current = NULL;
+
+ /* apparently we are not merging but growisofs will refuse to
+ * write a piped image if there is one already on the disc;
+ * except with this option */
+ g_ptr_array_add (argv, g_strdup ("-use-the-force-luke=tty"));
+
+ brasero_job_get_current_track (BRASERO_JOB (growisofs), ¤t);
+ if (brasero_job_get_fd_in (BRASERO_JOB (growisofs), NULL) == BRASERO_BURN_OK) {
+ /* set the buffer. NOTE: apparently this needs to be a power of 2 */
+ /* FIXME: is it right to mess with it ?
+ g_ptr_array_add (argv, g_strdup_printf ("-use-the-force-luke=bufsize:%im", 32)); */
+
+ if (!g_file_test ("/proc/self/fd/0", G_FILE_TEST_EXISTS)) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_FILE_NOT_FOUND,
+ _("\"%s\" could not be found"),
+ "/proc/self/fd/0");
+ return BRASERO_BURN_ERR;
+ }
+
+ /* FIXME: should we use DAO ? */
+ g_ptr_array_add (argv, g_strdup ("-Z"));
+ g_ptr_array_add (argv, g_strdup_printf ("%s=/proc/self/fd/0", device));
+ g_free (device);
+ }
+ else if (BRASERO_IS_TRACK_IMAGE (current)) {
+ gchar *localpath;
+
+ localpath = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (current), FALSE);
+ if (!localpath) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_FILE_NOT_LOCAL,
+ _("The file is not stored locally"));
+ return BRASERO_BURN_ERR;
+ }
+
+ g_ptr_array_add (argv, g_strdup ("-Z"));
+ g_ptr_array_add (argv, g_strdup_printf ("%s=%s",
+ device,
+ localpath));
+
+ g_free (device);
+ g_free (localpath);
+ }
+ else if (BRASERO_IS_TRACK_DATA (current)) {
+ g_ptr_array_add (argv, g_strdup ("-Z"));
+ g_ptr_array_add (argv, device);
+
+ /* this can only happen if source->type == BRASERO_TRACK_SOURCE_DATA */
+ if (action == BRASERO_JOB_ACTION_SIZE)
+ g_ptr_array_add (argv, g_strdup ("-dry-run"));
+
+ result = brasero_growisofs_set_mkisofs_argv (growisofs,
+ argv,
+ error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+ }
+ else
+ BRASERO_JOB_NOT_SUPPORTED (growisofs);
+ }
+
+ if (action == BRASERO_JOB_ACTION_SIZE)
+ brasero_job_set_current_action (BRASERO_JOB (growisofs),
+ BRASERO_BURN_ACTION_GETTING_SIZE,
+ NULL,
+ FALSE);
+ else
+ brasero_job_set_current_action (BRASERO_JOB (growisofs),
+ BRASERO_BURN_ACTION_START_RECORDING,
+ NULL,
+ FALSE);
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_growisofs_set_argv_blank (BraseroGrowisofs *growisofs,
+ GPtrArray *argv)
+{
+ BraseroBurnFlag flags;
+ gchar *device;
+ guint speed;
+
+ g_ptr_array_add (argv, g_strdup ("growisofs"));
+ brasero_job_get_flags (BRASERO_JOB (growisofs), &flags);
+ if (!(flags & BRASERO_BURN_FLAG_FAST_BLANK))
+ BRASERO_JOB_NOT_SUPPORTED (growisofs);
+
+ g_ptr_array_add (argv, g_strdup ("-Z"));
+
+ /* NOTE: /dev/zero works but not /dev/null. Why ? */
+ brasero_job_get_device (BRASERO_JOB (growisofs), &device);
+ g_ptr_array_add (argv, g_strdup_printf ("%s=%s", device, "/dev/zero"));
+ g_free (device);
+
+ /* That should fix a problem where when the DVD had an isofs
+ * growisofs warned that it had an isofs already on the disc */
+ g_ptr_array_add (argv, g_strdup ("-use-the-force-luke=tty"));
+
+ /* set maximum write speed */
+ brasero_job_get_max_speed (BRASERO_JOB (growisofs), &speed);
+ g_ptr_array_add (argv, g_strdup_printf ("-speed=%d", speed));
+
+ /* we only need to nullify 64 KiB: we'll stop the process when
+ * at least 65536 bytes have been written. We put a little more
+ * so in stdout parsing function remaining time is not negative
+ * if that's too fast. */
+ g_ptr_array_add (argv, g_strdup ("-use-the-force-luke=tracksize:1024"));
+
+ if (flags & BRASERO_BURN_FLAG_DUMMY)
+ g_ptr_array_add (argv, g_strdup ("-use-the-force-luke=dummy"));
+
+ brasero_job_set_current_action (BRASERO_JOB (growisofs),
+ BRASERO_BURN_ACTION_BLANKING,
+ NULL,
+ FALSE);
+ brasero_job_start_progress (BRASERO_JOB (growisofs), FALSE);
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_growisofs_set_argv (BraseroProcess *process,
+ GPtrArray *argv,
+ GError **error)
+{
+ BraseroJobAction action;
+ BraseroBurnResult result;
+
+ brasero_job_get_action (BRASERO_JOB (process), &action);
+ if (action == BRASERO_JOB_ACTION_SIZE) {
+ BraseroTrack *track = NULL;
+
+ /* only do it if that's DATA as input */
+ brasero_job_get_current_track (BRASERO_JOB (process), &track);
+ if (!BRASERO_IS_TRACK_DATA (track))
+ return BRASERO_BURN_NOT_SUPPORTED;
+
+ result = brasero_growisofs_set_argv_record (BRASERO_GROWISOFS (process),
+ argv,
+ error);
+ }
+ else if (action == BRASERO_JOB_ACTION_RECORD)
+ result = brasero_growisofs_set_argv_record (BRASERO_GROWISOFS (process),
+ argv,
+ error);
+ else if (action == BRASERO_JOB_ACTION_ERASE)
+ result = brasero_growisofs_set_argv_blank (BRASERO_GROWISOFS (process),
+ argv);
+ else
+ BRASERO_JOB_NOT_READY (process);
+
+ return result;
+}
+static void
+brasero_growisofs_class_init (BraseroGrowisofsClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ BraseroProcessClass *process_class = BRASERO_PROCESS_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (BraseroGrowisofsPrivate));
+
+ parent_class = g_type_class_peek_parent (klass);
+ object_class->finalize = brasero_growisofs_finalize;
+
+ process_class->stdout_func = brasero_growisofs_read_stdout;
+ process_class->stderr_func = brasero_growisofs_read_stderr;
+ process_class->set_argv = brasero_growisofs_set_argv;
+ process_class->post = brasero_job_finished_session;
+}
+
+static void
+brasero_growisofs_init (BraseroGrowisofs *obj)
+{
+ BraseroGrowisofsPrivate *priv;
+ gchar *standard_error = NULL;
+ gchar *prog_name;
+ gboolean res;
+
+ priv = BRASERO_GROWISOFS_PRIVATE (obj);
+
+ /* this code (remotely) comes from ncb_mkisofs_supports_utf8 */
+ /* Added a way to detect whether we'll use mkisofs or genisoimage */
+
+ prog_name = g_find_program_in_path ("mkisofs");
+ if (prog_name && g_file_test (prog_name, G_FILE_TEST_IS_EXECUTABLE)) {
+ gchar *standard_output = NULL;
+
+ res = g_spawn_command_line_sync ("mkisofs -version",
+ &standard_output,
+ NULL,
+ NULL,
+ NULL);
+ if (res) {
+ /* Really make sure it is mkisofs and not a symlink */
+ if (standard_output && strstr (standard_output, "genisoimage"))
+ priv->use_genisoimage = TRUE;
+
+ if (standard_output)
+ g_free (standard_output);
+ }
+ else
+ priv->use_genisoimage = TRUE;
+ }
+ else
+ priv->use_genisoimage = TRUE;
+
+ /* Don't use BRASERO_JOB_LOG () here!! */
+ if (priv->use_genisoimage)
+ res = g_spawn_command_line_sync ("genisoimage -input-charset utf8",
+ NULL,
+ &standard_error,
+ NULL,
+ NULL);
+ else
+ res = g_spawn_command_line_sync ("mkisofs -input-charset utf8",
+ NULL,
+ &standard_error,
+ NULL,
+ NULL);
+
+ if (res && !g_strrstr (standard_error, "Unknown charset"))
+ priv->use_utf8 = TRUE;
+ else
+ priv->use_utf8 = FALSE;
+
+ g_free (standard_error);
+}
+
+static void
+brasero_growisofs_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static BraseroBurnResult
+brasero_growisofs_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+ BraseroPluginConfOption *use_dao;
+ gboolean use_dao_gconf_key;
+ BraseroBurnResult result;
+ GSList *input_symlink;
+ GSList *input_joliet;
+ GConfClient *client;
+ GSList *output;
+ GSList *input;
+
+ brasero_plugin_define (plugin,
+ "growisofs",
+ _("Growisofs burns DVDs"),
+ "Philippe Rouquier",
+ 7);
+
+ /* First see if this plugin can be used */
+ result = brasero_process_check_path ("growisofs", error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+
+ /* growisofs can write images to any type of BD/DVD-R as long as it's blank */
+ input = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_PIPE|
+ BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_IMAGE_FORMAT_BIN);
+
+ output = brasero_caps_disc_new (BRASERO_MEDIUM_BD|
+ BRASERO_MEDIUM_SRM|
+ BRASERO_MEDIUM_POW|
+ BRASERO_MEDIUM_DVD|
+ BRASERO_MEDIUM_DUAL_L|
+ BRASERO_MEDIUM_PLUS|
+ BRASERO_MEDIUM_JUMP|
+ BRASERO_MEDIUM_SEQUENTIAL|
+ BRASERO_MEDIUM_WRITABLE|
+ BRASERO_MEDIUM_BLANK);
+
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (output);
+
+ output = brasero_caps_disc_new (BRASERO_MEDIUM_DVD|
+ BRASERO_MEDIUM_SEQUENTIAL|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_UNFORMATTED|
+ BRASERO_MEDIUM_BLANK);
+
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (output);
+
+ /* and images to BD/DVD RW +/-(restricted) whatever the status */
+ output = brasero_caps_disc_new (BRASERO_MEDIUM_BD|
+ BRASERO_MEDIUM_DVD|
+ BRASERO_MEDIUM_RAM|
+ BRASERO_MEDIUM_DUAL_L|
+ BRASERO_MEDIUM_PLUS|
+ BRASERO_MEDIUM_RESTRICTED|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_UNFORMATTED|
+ BRASERO_MEDIUM_BLANK|
+ BRASERO_MEDIUM_CLOSED|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_HAS_DATA);
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (output);
+ g_slist_free (input);
+
+ /* for DATA type recording discs can be also appended */
+ input_joliet = brasero_caps_data_new (BRASERO_IMAGE_FS_ISO|
+ BRASERO_IMAGE_FS_UDF|
+ BRASERO_IMAGE_ISO_FS_LEVEL_3|
+ BRASERO_IMAGE_ISO_FS_DEEP_DIRECTORY|
+ BRASERO_IMAGE_FS_JOLIET|
+ BRASERO_IMAGE_FS_VIDEO);
+
+ input_symlink = brasero_caps_data_new (BRASERO_IMAGE_FS_ISO|
+ BRASERO_IMAGE_ISO_FS_LEVEL_3|
+ BRASERO_IMAGE_ISO_FS_DEEP_DIRECTORY|
+ BRASERO_IMAGE_FS_SYMLINK);
+
+ output = brasero_caps_disc_new (BRASERO_MEDIUM_BD|
+ BRASERO_MEDIUM_SRM|
+ BRASERO_MEDIUM_POW|
+ BRASERO_MEDIUM_DVD|
+ BRASERO_MEDIUM_DUAL_L|
+ BRASERO_MEDIUM_RAM|
+ BRASERO_MEDIUM_PLUS|
+ BRASERO_MEDIUM_RESTRICTED|
+ BRASERO_MEDIUM_SEQUENTIAL|
+ BRASERO_MEDIUM_JUMP|
+ BRASERO_MEDIUM_WRITABLE|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_UNFORMATTED|
+ BRASERO_MEDIUM_BLANK|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_HAS_DATA);
+ brasero_plugin_link_caps (plugin, output, input_joliet);
+ brasero_plugin_link_caps (plugin, output, input_symlink);
+ g_slist_free (output);
+
+ /* growisofs has the possibility to record to closed BD/DVD+RW
+ * +/-restricted and to append some more data to them which makes them
+ * unique */
+ output = brasero_caps_disc_new (BRASERO_MEDIUM_BD|
+ BRASERO_MEDIUM_DVD|
+ BRASERO_MEDIUM_DUAL_L|
+ BRASERO_MEDIUM_RAM|
+ BRASERO_MEDIUM_PLUS|
+ BRASERO_MEDIUM_RESTRICTED|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_CLOSED|
+ BRASERO_MEDIUM_HAS_DATA);
+
+ brasero_plugin_link_caps (plugin, output, input_joliet);
+ brasero_plugin_link_caps (plugin, output, input_symlink);
+ g_slist_free (output);
+ g_slist_free (input_joliet);
+ g_slist_free (input_symlink);
+
+ /* For DVD-RW sequential */
+ BRASERO_PLUGIN_ADD_STANDARD_DVDRW_FLAGS (plugin, BRASERO_BURN_FLAG_NONE);
+
+ /* see NOTE for DVD-RW restricted overwrite */
+ BRASERO_PLUGIN_ADD_STANDARD_DVDRW_RESTRICTED_FLAGS (plugin, BRASERO_BURN_FLAG_NONE);
+
+ /* DVD+R and DVD-R. DAO and growisofs doesn't always work well with
+ * these types of media and with some drives. So don't allow it if the
+ * workaround is set in GConf (and it should be by default). */
+ client = gconf_client_get_default ();
+ use_dao_gconf_key = gconf_client_get_bool (client,
+ GCONF_KEY_DAO_FLAG,
+ NULL);
+ g_object_unref (client);
+
+ if (use_dao_gconf_key == TRUE) {
+ BRASERO_PLUGIN_ADD_STANDARD_DVDR_FLAGS (plugin, BRASERO_BURN_FLAG_NONE);
+ BRASERO_PLUGIN_ADD_STANDARD_DVDR_PLUS_FLAGS (plugin, BRASERO_BURN_FLAG_NONE);
+ }
+ else {
+ /* All above standard flags minus DAO flag support */
+ BRASERO_PLUGIN_ADD_STANDARD_DVDR_FLAGS (plugin, BRASERO_BURN_FLAG_DAO);
+ BRASERO_PLUGIN_ADD_STANDARD_DVDR_PLUS_FLAGS (plugin, BRASERO_BURN_FLAG_DAO);
+ }
+
+ /* for DVD+RW */
+ BRASERO_PLUGIN_ADD_STANDARD_DVDRW_PLUS_FLAGS (plugin, BRASERO_BURN_FLAG_NONE);
+
+ /* for BD-RE */
+ BRASERO_PLUGIN_ADD_STANDARD_BD_RE_FLAGS (plugin, BRASERO_BURN_FLAG_NONE);
+
+ /* blank caps for +/restricted RW */
+ output = brasero_caps_disc_new (BRASERO_MEDIUM_DVD|
+ BRASERO_MEDIUM_DUAL_L|
+ BRASERO_MEDIUM_PLUS|
+ BRASERO_MEDIUM_RESTRICTED|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_CLOSED|
+ BRASERO_MEDIUM_HAS_DATA|
+ BRASERO_MEDIUM_UNFORMATTED|
+ BRASERO_MEDIUM_BLANK);
+ brasero_plugin_blank_caps (plugin, output);
+ g_slist_free (output);
+
+ brasero_plugin_set_blank_flags (plugin,
+ BRASERO_MEDIUM_DVD|
+ BRASERO_MEDIUM_RESTRICTED|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_HAS_DATA|
+ BRASERO_MEDIUM_BLANK|
+ BRASERO_MEDIUM_UNFORMATTED|
+ BRASERO_MEDIUM_CLOSED,
+ BRASERO_BURN_FLAG_NOGRACE|
+ BRASERO_BURN_FLAG_FAST_BLANK,
+ BRASERO_BURN_FLAG_FAST_BLANK);
+
+ /* again DVD+RW don't support dummy */
+ brasero_plugin_set_blank_flags (plugin,
+ BRASERO_MEDIUM_DVDRW_PLUS|
+ BRASERO_MEDIUM_DUAL_L|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_HAS_DATA|
+ BRASERO_MEDIUM_BLANK|
+ BRASERO_MEDIUM_UNFORMATTED|
+ BRASERO_MEDIUM_CLOSED,
+ BRASERO_BURN_FLAG_NOGRACE|
+ BRASERO_BURN_FLAG_FAST_BLANK,
+ BRASERO_BURN_FLAG_FAST_BLANK);
+
+ use_dao = brasero_plugin_conf_option_new (GCONF_KEY_DAO_FLAG,
+ _("Allow DAO use"),
+ BRASERO_PLUGIN_OPTION_BOOL);
+
+ brasero_plugin_add_conf_option (plugin, use_dao);
+
+ brasero_plugin_register_group (plugin, _(GROWISOFS_DESCRIPTION));
+
+ return BRASERO_BURN_OK;
+}
diff --git a/plugins/growisofs/burn-growisofs.h b/plugins/growisofs/burn-growisofs.h
new file mode 100644
index 0000000..a3ab278
--- /dev/null
+++ b/plugins/growisofs/burn-growisofs.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ * growisofs.h
+ *
+ * dim jan 22 15:38:51 2006
+ * Copyright 2006 Rouquier Philippe
+ * brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef GROWISOFS_H
+#define GROWISOFS_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_GROWISOFS (brasero_growisofs_get_type ())
+#define BRASERO_GROWISOFS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_GROWISOFS, BraseroGrowisofs))
+#define BRASERO_GROWISOFS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_GROWISOFS, BraseroGrowisofsClass))
+#define BRASERO_IS_GROWISOFS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_GROWISOFS))
+#define BRASERO_IS_GROWISOFS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_GROWISOFS))
+#define BRASERO_GROWISOFS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_GROWISOFS, BraseroGrowisofsClass))
+
+G_END_DECLS
+
+#endif /* GROWISOFS_H */
diff --git a/plugins/libburnia/Makefile.am b/plugins/libburnia/Makefile.am
new file mode 100644
index 0000000..22381b9
--- /dev/null
+++ b/plugins/libburnia/Makefile.am
@@ -0,0 +1,36 @@
+
+INCLUDES = \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/libbrasero-media/ \
+ -I$(top_builddir)/libbrasero-media/ \
+ -I$(top_srcdir)/libbrasero-burn \
+ -I$(top_builddir)/libbrasero-burn/ \
+ -DBRASERO_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
+ -DBRASERO_PREFIX=\"$(prefix)\" \
+ -DBRASERO_SYSCONFDIR=\"$(sysconfdir)\" \
+ -DBRASERO_DATADIR=\"$(datadir)/brasero\" \
+ -DBRASERO_LIBDIR=\"$(libdir)\" \
+ $(DISABLE_DEPRECATED) \
+ $(BRASERO_LIBISOFS_CFLAGS) \
+ $(BRASERO_LIBBURN_CFLAGS) \
+ $(BRASERO_GLIB_CFLAGS)
+
+#libburn
+libburndir = $(libdir)/brasero/plugins
+libburn_LTLIBRARIES = libbrasero-libburn.la
+libbrasero_libburn_la_SOURCES = burn-libburn.c \
+ burn-libburn.h \
+ burn-libburn-common.c \
+ burn-libburn-common.h \
+ burn-libburnia.h
+libbrasero_libburn_la_LIBADD = $(BRASERO_GLIB_LIBS) $(BRASERO_LIBBURNIA_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_libburn_la_LDFLAGS = -module -avoid-version
+
+#libisofs (apparently libisofs needs one libburn function)
+libisofsdir = $(libdir)/brasero/plugins
+libisofs_LTLIBRARIES = libbrasero-libisofs.la
+libbrasero_libisofs_la_SOURCES = burn-libisofs.c burn-libisofs.h \
+ burn-libburn-common.c burn-libburn-common.h \
+ burn-libburnia.h
+libbrasero_libisofs_la_LIBADD = $(BRASERO_GLIB_LIBS) $(BRASERO_LIBBURNIA_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_libisofs_la_LDFLAGS = -module -avoid-version
diff --git a/plugins/libburnia/burn-libburn-common.c b/plugins/libburnia/burn-libburn-common.c
new file mode 100644
index 0000000..2d036ee
--- /dev/null
+++ b/plugins/libburnia/burn-libburn-common.c
@@ -0,0 +1,377 @@
+/***************************************************************************
+ * burn-libburn-common.c
+ *
+ * mer aoû 30 16:35:40 2006
+ * Copyright 2006 Rouquier Philippe
+ * bonfire-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+
+#include "burn-basics.h"
+#include "burn-debug.h"
+#include "burn-job.h"
+#include "burn-libburn-common.h"
+
+#include <libburn/libburn.h>
+
+static void
+brasero_libburn_common_ctx_free_real (BraseroLibburnCtx *ctx)
+{
+ BRASERO_BURN_LOG ("Drive stopped");
+
+ if (ctx->disc) {
+ burn_disc_free (ctx->disc);
+ ctx->disc = NULL;
+ }
+
+ /* This must be done in this order since:
+ * ctx->drive = ctx->drive_info->drive */
+
+ if (ctx->drive) {
+ burn_drive_release (ctx->drive, 0);
+ ctx->drive = NULL;
+ }
+
+ if (ctx->drive_info) {
+ burn_drive_info_free (ctx->drive_info);
+ ctx->drive_info = NULL;
+ }
+
+ g_free (ctx);
+
+ /* Since the library is not needed any more call burn_finish ().
+ * NOTE: it itself calls burn_abort (). */
+ burn_finish ();
+}
+
+static gboolean
+brasero_libburn_common_ctx_wait_for_idle_drive (gpointer data)
+{
+ BraseroLibburnCtx *ctx = data;
+ enum burn_drive_status status;
+
+ /* try to properly cancel the drive */
+ status = burn_drive_get_status (ctx->drive, NULL);
+ if (status == BURN_DRIVE_WRITING || status == BURN_DRIVE_READING) {
+ BRASERO_BURN_LOG ("Cancelling operation");
+ burn_drive_cancel (ctx->drive);
+ }
+
+ if (status == BURN_DRIVE_GRABBING) {
+ /* This should probably never happen */
+ BRASERO_BURN_LOG ("Grabbing state, try to forget");
+ burn_drive_info_forget (ctx->drive_info, 1);
+ }
+
+ if (status != BURN_DRIVE_IDLE) {
+ BRASERO_BURN_LOG ("Drive not idle yet");
+ return TRUE;
+ }
+
+ brasero_libburn_common_ctx_free_real (ctx);
+ return FALSE;
+}
+
+void
+brasero_libburn_common_ctx_free (BraseroLibburnCtx *ctx)
+{
+ enum burn_drive_status status;
+
+ BRASERO_BURN_LOG ("Stopping Drive");
+
+ /* try to properly cancel the drive */
+ status = burn_drive_get_status (ctx->drive, NULL);
+ if (status == BURN_DRIVE_WRITING || status == BURN_DRIVE_READING) {
+ BRASERO_BURN_LOG ("Cancelling operation");
+ burn_drive_cancel (ctx->drive);
+ }
+
+ if (status == BURN_DRIVE_GRABBING) {
+ /* This should probably never happen */
+ BRASERO_BURN_LOG ("Grabbing state, try to forget");
+ burn_drive_info_forget (ctx->drive_info, 1);
+ }
+
+ if (status != BURN_DRIVE_IDLE) {
+ /* otherwise wait for the drive to calm down */
+ BRASERO_BURN_LOG ("Drive not idle yet");
+ g_timeout_add (200,
+ brasero_libburn_common_ctx_wait_for_idle_drive,
+ ctx);
+ return;
+ }
+
+ brasero_libburn_common_ctx_free_real (ctx);
+}
+
+BraseroLibburnCtx *
+brasero_libburn_common_ctx_new (BraseroJob *job,
+ GError **error)
+{
+ gchar libburn_device [BURN_DRIVE_ADR_LEN];
+ BraseroLibburnCtx *ctx = NULL;
+ gchar *device;
+ int res;
+
+ /* initialize the library */
+ if (!burn_initialize ()) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("Libburn library could not be initialized"));
+ return NULL;
+ }
+
+ /* We want all types of messages but not them printed */
+ burn_msgs_set_severities ("ALL", "NEVER", "");
+
+ /* we just want to scan the drive proposed by drive */
+ brasero_job_get_device (job, &device);
+ res = burn_drive_convert_fs_adr (device, libburn_device);
+ g_free (device);
+ if (res <= 0) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("The drive address could not be retrieved"));
+ return NULL;
+ }
+
+ ctx = g_new0 (BraseroLibburnCtx, 1);
+ res = burn_drive_scan_and_grab (&ctx->drive_info, libburn_device, 0);
+ BRASERO_JOB_LOG (job, "Drive (%s) init result = %d", libburn_device, res);
+ if (res <= 0) {
+ g_free (ctx);
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_DRIVE_BUSY,
+ _("The drive is busy"));
+ return NULL;
+ }
+
+ ctx->drive = ctx->drive_info->drive;
+ return ctx;
+}
+
+static gboolean
+brasero_libburn_common_process_message (BraseroJob *self)
+{
+ int ret;
+ GError *error;
+ int err_code = 0;
+ int err_errno = 0;
+ char err_sev [80];
+ char err_txt [BURN_MSGS_MESSAGE_LEN] = {0};
+
+ /* Get all messages, indicating an error */
+ memset (err_txt, 0, sizeof (err_txt));
+ ret = burn_msgs_obtain ("ALL",
+ &err_code,
+ err_txt,
+ &err_errno,
+ err_sev);
+ if (ret == 0)
+ return TRUE;
+
+ if (strcmp ("FATAL", err_sev)
+ && strcmp ("ABORT", err_sev)) {
+ /* libburn didn't reported any FATAL message but maybe it did
+ * report some debugging output */
+ BRASERO_JOB_LOG (self, err_txt);
+ return TRUE;
+ }
+
+ BRASERO_JOB_LOG (self, "Libburn reported an error %s", err_txt);
+ error = g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ err_txt);
+ brasero_job_error (BRASERO_JOB (self), error);
+ return FALSE;
+}
+
+static gboolean
+brasero_libburn_common_status_changed (BraseroJob *self,
+ BraseroLibburnCtx *ctx,
+ enum burn_drive_status status,
+ struct burn_progress *progress)
+{
+ BraseroBurnAction action = BRASERO_BURN_ACTION_NONE;
+
+ switch (status) {
+ case BURN_DRIVE_WRITING:
+ /* we ignore it if it happens after leadout */
+ if (ctx->status == BURN_DRIVE_WRITING_LEADOUT
+ || ctx->status == BURN_DRIVE_CLOSING_TRACK
+ || ctx->status == BURN_DRIVE_CLOSING_SESSION)
+ return TRUE;
+
+ if (ctx->status == BURN_DRIVE_WRITING_LEADIN
+ || ctx->status == BURN_DRIVE_WRITING_PREGAP) {
+ ctx->sectors += ctx->track_sectors;
+ ctx->track_sectors = progress->sectors;
+ ctx->track_num = progress->track;
+ }
+
+ action = BRASERO_BURN_ACTION_RECORDING;
+ brasero_job_set_dangerous (BRASERO_JOB (self), TRUE);
+ break;
+
+ case BURN_DRIVE_WRITING_LEADIN: /* DAO */
+ case BURN_DRIVE_WRITING_PREGAP: /* TAO */
+ ctx->has_leadin = 1;
+ action = BRASERO_BURN_ACTION_START_RECORDING;
+ brasero_job_set_dangerous (BRASERO_JOB (self), FALSE);
+ break;
+
+ case BURN_DRIVE_WRITING_LEADOUT: /* DAO */
+ case BURN_DRIVE_CLOSING_TRACK: /* TAO */
+ case BURN_DRIVE_CLOSING_SESSION: /* Multisession end */
+ ctx->sectors += ctx->track_sectors;
+ ctx->track_sectors = progress->sectors;
+
+ action = BRASERO_BURN_ACTION_FIXATING;
+ brasero_job_set_dangerous (BRASERO_JOB (self), FALSE);
+ break;
+
+ case BURN_DRIVE_ERASING:
+ case BURN_DRIVE_FORMATTING:
+ action = BRASERO_BURN_ACTION_BLANKING;
+ brasero_job_set_dangerous (BRASERO_JOB (self), TRUE);
+ break;
+
+ case BURN_DRIVE_IDLE:
+ /* That's the end of activity */
+ return FALSE;
+
+ case BURN_DRIVE_SPAWNING:
+ if (ctx->status == BURN_DRIVE_IDLE)
+ action = BRASERO_BURN_ACTION_START_RECORDING;
+ else
+ action = BRASERO_BURN_ACTION_FIXATING;
+ brasero_job_set_dangerous (BRASERO_JOB (self), FALSE);
+ break;
+
+ case BURN_DRIVE_READING:
+ action = BRASERO_BURN_ACTION_DRIVE_COPY;
+ brasero_job_set_dangerous (BRASERO_JOB (self), FALSE);
+ break;
+
+ default:
+ BRASERO_JOB_LOG (self, "Unknown drive state (%i)", status);
+ return TRUE;
+ }
+
+ ctx->status = status;
+ brasero_job_set_current_action (self,
+ action,
+ NULL,
+ FALSE);
+ return TRUE;
+}
+
+BraseroBurnResult
+brasero_libburn_common_status (BraseroJob *self,
+ BraseroLibburnCtx *ctx)
+{
+ enum burn_drive_status status;
+ struct burn_progress progress;
+
+ /* see if there is any pending message */
+ if (!brasero_libburn_common_process_message (self))
+ return BRASERO_BURN_ERR;
+
+ if (!ctx->drive)
+ return BRASERO_BURN_ERR;
+
+ status = burn_drive_get_status (ctx->drive, &progress);
+
+ /* FIXME! for some operations that libburn can't perform the drive stays
+ * idle and we've got no way to tell that kind of use case */
+ if (ctx->status != status) {
+ gboolean running;
+
+ running = brasero_libburn_common_status_changed (self,
+ ctx,
+ status,
+ &progress);
+ if (!running)
+ return BRASERO_BURN_OK;
+ }
+
+ if (status == BURN_DRIVE_IDLE
+ || status == BURN_DRIVE_SPAWNING
+ || !progress.sectors
+ || !progress.sector) {
+ ctx->sectors = 0;
+
+ ctx->track_num = progress.track;
+ ctx->track_sectors = progress.sectors;
+ return BRASERO_BURN_RETRY;
+ }
+
+ if (status == BURN_DRIVE_CLOSING_SESSION
+ || status == BURN_DRIVE_WRITING_LEADOUT) {
+ brasero_job_set_progress (self, 1.0);
+ }
+ else if (status != BURN_DRIVE_ERASING
+ && status != BURN_DRIVE_FORMATTING) {
+ gint64 cur_sector;
+
+ if (ctx->track_num != progress.track) {
+ gchar *string;
+
+ ctx->sectors += ctx->track_sectors;
+ ctx->track_sectors = progress.sectors;
+ ctx->track_num = progress.track;
+
+ string = g_strdup_printf (_("Writing track %02i"), progress.track);
+ brasero_job_set_current_action (self,
+ BRASERO_BURN_ACTION_RECORDING,
+ string,
+ TRUE);
+ g_free (string);
+ }
+
+ cur_sector = progress.sector + ctx->sectors;
+ brasero_job_set_written_session (self, (gint64) ((gint64) cur_sector * 2048ULL));
+ }
+ else {
+ gdouble fraction;
+
+ /* when erasing only set progress */
+ fraction = (gdouble) (progress.sector) /
+ (gdouble) (progress.sectors);
+
+ brasero_job_set_progress (self, fraction);
+ }
+
+ brasero_job_start_progress (self, FALSE);
+ return BRASERO_BURN_RETRY;
+}
diff --git a/plugins/libburnia/burn-libburn-common.h b/plugins/libburnia/burn-libburn-common.h
new file mode 100644
index 0000000..4cf8b5c
--- /dev/null
+++ b/plugins/libburnia/burn-libburn-common.h
@@ -0,0 +1,71 @@
+/***************************************************************************
+ * burn-libburn-common.h
+ *
+ * mer aoû 30 16:35:40 2006
+ * Copyright 2006 Rouquier Philippe
+ * bonfire-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef BURN_LIBBURN_COMMON_H
+#define BURN_LIBBURN_COMMON_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "burn-job.h"
+
+#include <libburn/libburn.h>
+
+G_BEGIN_DECLS
+
+struct _BraseroLibburnCtx {
+ struct burn_drive_info *drive_info;
+ struct burn_drive *drive;
+ struct burn_disc *disc;
+
+ enum burn_drive_status status;
+
+ /* used detect track hops */
+ gint track_num;
+
+ /* used to report current written sector */
+ gint64 sectors;
+ gint64 cur_sector;
+ gint64 track_sectors;
+
+ gint has_leadin;
+};
+typedef struct _BraseroLibburnCtx BraseroLibburnCtx;
+
+BraseroLibburnCtx *
+brasero_libburn_common_ctx_new (BraseroJob *job,
+ GError **error);
+
+void
+brasero_libburn_common_ctx_free (BraseroLibburnCtx *ctx);
+
+BraseroBurnResult
+brasero_libburn_common_status (BraseroJob *job,
+ BraseroLibburnCtx *ctx);
+
+G_END_DECLS
+
+#endif /* BURN_LIBBURN_COMMON_H */
diff --git a/plugins/libburnia/burn-libburn.c b/plugins/libburnia/burn-libburn.c
new file mode 100644
index 0000000..2725cbe
--- /dev/null
+++ b/plugins/libburnia/burn-libburn.c
@@ -0,0 +1,1026 @@
+/***************************************************************************
+ * burn-libburn.c
+ *
+ * lun aoû 21 14:33:24 2006
+ * Copyright 2006 Rouquier Philippe
+ * bonfire-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+
+#include <libburn/libburn.h>
+
+#include "brasero-units.h"
+#include "burn-job.h"
+#include "burn-debug.h"
+#include "brasero-plugin-registration.h"
+#include "burn-libburn-common.h"
+#include "burn-libburnia.h"
+#include "burn-libburn.h"
+#include "brasero-track-image.h"
+#include "brasero-track-stream.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroLibburn, brasero_libburn, BRASERO_TYPE_JOB, BraseroJob);
+
+#define BRASERO_PVD_SIZE 32ULL * 2048ULL
+
+struct _BraseroLibburnPrivate {
+ BraseroLibburnCtx *ctx;
+
+ /* This buffer is used to capture Primary Volume Descriptor for
+ * for overwrite media so as to "grow" the latter. */
+ unsigned char *pvd;
+
+ guint sig_handler:1;
+};
+typedef struct _BraseroLibburnPrivate BraseroLibburnPrivate;
+
+#define BRASERO_LIBBURN_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_LIBBURN, BraseroLibburnPrivate))
+
+/**
+ * taken from scsi-get-configuration.h
+ */
+
+typedef enum {
+BRASERO_SCSI_PROF_DVD_RW_RESTRICTED = 0x0013,
+BRASERO_SCSI_PROF_DVD_RW_PLUS = 0x001A,
+} BraseroScsiProfile;
+
+static GObjectClass *parent_class = NULL;
+
+struct _BraseroLibburnSrcData {
+ int fd;
+ off_t size;
+
+ /* That's for the primary volume descriptor used for overwrite media */
+ int pvd_size; /* in blocks */
+ unsigned char *pvd;
+
+ int read_pvd:1;
+};
+typedef struct _BraseroLibburnSrcData BraseroLibburnSrcData;
+
+static void
+brasero_libburn_src_free_data (struct burn_source *src)
+{
+ BraseroLibburnSrcData *data;
+
+ data = src->data;
+ close (data->fd);
+ g_free (data);
+}
+
+static off_t
+brasero_libburn_src_get_size (struct burn_source *src)
+{
+ BraseroLibburnSrcData *data;
+
+ data = src->data;
+ return data->size;
+}
+
+static int
+brasero_libburn_src_set_size (struct burn_source *src,
+ off_t size)
+{
+ BraseroLibburnSrcData *data;
+
+ data = src->data;
+ data->size = size;
+ return 1;
+}
+
+/**
+ * This is a copy from burn-volume.c
+ */
+
+struct _BraseroVolDesc {
+ guchar type;
+ gchar id [5];
+ guchar version;
+};
+typedef struct _BraseroVolDesc BraseroVolDesc;
+
+static int
+brasero_libburn_src_read_xt (struct burn_source *src,
+ unsigned char *buffer,
+ int size)
+{
+ int total;
+ BraseroLibburnSrcData *data;
+
+ data = src->data;
+
+ total = 0;
+ while (total < size) {
+ int bytes;
+
+ bytes = read (data->fd, buffer + total, size - total);
+ if (bytes < 0)
+ return -1;
+
+ if (!bytes)
+ break;
+
+ total += bytes;
+ }
+
+ /* copy the primary volume descriptor if a buffer is provided */
+ if (data->pvd
+ && !data->read_pvd
+ && data->pvd_size < BRASERO_PVD_SIZE) {
+ unsigned char *current_pvd;
+ int i;
+
+ current_pvd = data->pvd + data->pvd_size;
+
+ /* read volume descriptors until we reach the end of the
+ * buffer or find a volume descriptor set end. */
+ for (i = 0; (i << 11) < size && data->pvd_size + (i << 11) < BRASERO_PVD_SIZE; i ++) {
+ BraseroVolDesc *desc;
+
+ /* No need to check the first 16 blocks */
+ if ((data->pvd_size >> 11) + i < 16)
+ continue;
+
+ desc = (BraseroVolDesc *) (buffer + sizeof (BraseroVolDesc) * i);
+ if (desc->type == 255) {
+ data->read_pvd = 1;
+ BRASERO_BURN_LOG ("found volume descriptor set end");
+ break;
+ }
+ }
+
+ memcpy (current_pvd, buffer, i << 11);
+ data->pvd_size += i << 11;
+ }
+
+ return total;
+}
+
+static struct burn_source *
+brasero_libburn_create_fd_source (int fd,
+ gint64 size,
+ unsigned char *pvd)
+{
+ struct burn_source *src;
+ BraseroLibburnSrcData *data;
+
+ data = g_new0 (BraseroLibburnSrcData, 1);
+ data->fd = fd;
+ data->size = size;
+ data->pvd = pvd;
+
+ /* FIXME: this could be wrapped into a fifo source to get a smoother
+ * data delivery. But that means another thread ... */
+ src = g_new0 (struct burn_source, 1);
+ src->version = 1;
+ src->refcount = 1;
+ src->read_xt = brasero_libburn_src_read_xt;
+ src->get_size = brasero_libburn_src_get_size;
+ src->set_size = brasero_libburn_src_set_size;
+ src->free_data = brasero_libburn_src_free_data;
+ src->data = data;
+
+ return src;
+}
+
+static BraseroBurnResult
+brasero_libburn_add_track (struct burn_session *session,
+ struct burn_track *track,
+ struct burn_source *src,
+ gint mode,
+ GError **error)
+{
+ if (burn_track_set_source (track, src) != BURN_SOURCE_OK) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("Libburn track could not be created"));
+ return BRASERO_BURN_ERR;
+ }
+
+ if (!burn_session_add_track (session, track, BURN_POS_END)) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("Libburn track could not be created"));
+ return BRASERO_BURN_ERR;
+ }
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_libburn_add_fd_track (struct burn_session *session,
+ int fd,
+ gint mode,
+ gint64 size,
+ unsigned char *pvd,
+ GError **error)
+{
+ struct burn_source *src;
+ struct burn_track *track;
+ BraseroBurnResult result;
+
+ track = burn_track_create ();
+ burn_track_define_data (track, 0, 0, 0, mode);
+
+ src = brasero_libburn_create_fd_source (fd, size, pvd);
+ result = brasero_libburn_add_track (session, track, src, mode, error);
+
+ burn_source_free (src);
+ burn_track_free (track);
+
+ return result;
+}
+
+static BraseroBurnResult
+brasero_libburn_add_file_track (struct burn_session *session,
+ const gchar *path,
+ gint mode,
+ off_t size,
+ unsigned char *pvd,
+ GError **error)
+{
+ int fd;
+
+ fd = open (path, O_RDONLY);
+ if (fd == -1) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ "%s",
+ g_strerror (errno));
+ return BRASERO_BURN_ERR;
+ }
+
+ return brasero_libburn_add_fd_track (session, fd, mode, size, pvd, error);
+}
+
+static BraseroBurnResult
+brasero_libburn_setup_session_fd (BraseroLibburn *self,
+ struct burn_session *session,
+ GError **error)
+{
+ int fd;
+ guint64 size = 0;
+ BraseroLibburnPrivate *priv;
+ BraseroTrackType *type = NULL;
+ BraseroBurnResult result = BRASERO_BURN_OK;
+
+ priv = BRASERO_LIBBURN_PRIVATE (self);
+
+ brasero_job_get_fd_in (BRASERO_JOB (self), &fd);
+
+ /* need to find out what type of track the imager will output */
+ type = brasero_track_type_new ();
+ brasero_job_get_input_type (BRASERO_JOB (self), type);
+
+ if (brasero_track_type_get_has_image (type)) {
+ gint mode;
+
+ /* FIXME: implement other IMAGE types */
+ if (brasero_track_type_get_image_format (type) == BRASERO_IMAGE_FORMAT_BIN)
+ mode = BURN_MODE1;
+ else
+ mode = BURN_MODE1|BURN_MODE_RAW|BURN_SUBCODE_R96;
+
+ brasero_track_type_free (type);
+
+ brasero_job_get_session_output_size (BRASERO_JOB (self),
+ NULL,
+ &size);
+
+ result = brasero_libburn_add_fd_track (session,
+ fd,
+ mode,
+ size,
+ priv->pvd,
+ error);
+ }
+ else if (brasero_track_type_get_has_stream (type)) {
+ GSList *tracks;
+
+ brasero_track_type_free (type);
+
+ brasero_job_get_tracks (BRASERO_JOB (self), &tracks);
+ for (; tracks; tracks = tracks->next) {
+ BraseroTrack *track;
+
+ track = tracks->data;
+ brasero_track_stream_get_length (BRASERO_TRACK_STREAM (track), &size);
+ size = BRASERO_DURATION_TO_BYTES (size);
+
+ /* we dup the descriptor so the same
+ * will be shared by all tracks */
+ result = brasero_libburn_add_fd_track (session,
+ dup (fd),
+ BURN_AUDIO,
+ size,
+ NULL,
+ error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+ }
+ }
+ else
+ BRASERO_JOB_NOT_SUPPORTED (self);
+
+ return result;
+}
+
+static BraseroBurnResult
+brasero_libburn_setup_session_file (BraseroLibburn *self,
+ struct burn_session *session,
+ GError **error)
+{
+ BraseroLibburnPrivate *priv;
+ BraseroBurnResult result;
+ GSList *tracks = NULL;
+
+ priv = BRASERO_LIBBURN_PRIVATE (self);
+
+ /* create the track(s) */
+ result = BRASERO_BURN_OK;
+ brasero_job_get_tracks (BRASERO_JOB (self), &tracks);
+ for (; tracks; tracks = tracks->next) {
+ BraseroTrack *track;
+
+ track = tracks->data;
+ if (BRASERO_IS_TRACK_STREAM (track)) {
+ gchar *audiopath;
+ guint64 size;
+
+ audiopath = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (track), FALSE);
+ brasero_track_stream_get_length (BRASERO_TRACK_STREAM (track), &size);
+ size = BRASERO_DURATION_TO_BYTES (size);
+
+ result = brasero_libburn_add_file_track (session,
+ audiopath,
+ BURN_AUDIO,
+ size,
+ NULL,
+ error);
+ if (result != BRASERO_BURN_OK)
+ break;
+ }
+ else if (BRASERO_IS_TRACK_IMAGE (track)) {
+ BraseroImageFormat format;
+ gchar *imagepath;
+ guint64 size;
+ gint mode;
+
+ format = brasero_track_image_get_format (BRASERO_TRACK_IMAGE (track));
+ if (format == BRASERO_IMAGE_FORMAT_BIN) {
+ mode = BURN_MODE1;
+ imagepath = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (track), FALSE);
+ }
+ else if (format == BRASERO_IMAGE_FORMAT_NONE) {
+ mode = BURN_MODE1;
+ imagepath = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (track), FALSE);
+ }
+ else
+ BRASERO_JOB_NOT_SUPPORTED (self);
+
+ if (!imagepath)
+ return BRASERO_BURN_ERR;
+
+ result = brasero_track_get_size (track,
+ NULL,
+ &size);
+ if (result != BRASERO_BURN_OK)
+ return BRASERO_BURN_ERR;
+
+ result = brasero_libburn_add_file_track (session,
+ imagepath,
+ mode,
+ size,
+ priv->pvd,
+ error);
+ g_free (imagepath);
+ }
+ else
+ BRASERO_JOB_NOT_SUPPORTED (self);
+ }
+
+ return result;
+}
+
+static BraseroBurnResult
+brasero_libburn_create_disc (BraseroLibburn *self,
+ struct burn_disc **retval,
+ GError **error)
+{
+ struct burn_disc *disc;
+ BraseroBurnResult result;
+ struct burn_session *session;
+
+ /* set the source image */
+ disc = burn_disc_create ();
+
+ /* create the session */
+ session = burn_session_create ();
+ burn_disc_add_session (disc, session, BURN_POS_END);
+ burn_session_free (session);
+
+ if (brasero_job_get_fd_in (BRASERO_JOB (self), NULL) == BRASERO_BURN_OK)
+ result = brasero_libburn_setup_session_fd (self, session, error);
+ else
+ result = brasero_libburn_setup_session_file (self, session, error);
+
+ if (result != BRASERO_BURN_OK) {
+ burn_disc_free (disc);
+ return result;
+ }
+
+ *retval = disc;
+ return result;
+}
+
+static BraseroBurnResult
+brasero_libburn_start_record (BraseroLibburn *self,
+ GError **error)
+{
+ guint64 rate;
+ guint64 blocks = 0;
+ BraseroMedia media;
+ BraseroBurnFlag flags;
+ BraseroBurnResult result;
+ BraseroLibburnPrivate *priv;
+ struct burn_write_opts *opts;
+ gchar reason [BURN_REASONS_LEN];
+
+ priv = BRASERO_LIBBURN_PRIVATE (self);
+
+ /* if appending a DVD+-RW get PVD */
+ brasero_job_get_flags (BRASERO_JOB (self), &flags);
+ brasero_job_get_media (BRASERO_JOB (self), &media);
+
+ if (flags & (BRASERO_BURN_FLAG_MERGE|BRASERO_BURN_FLAG_APPEND)
+ && BRASERO_MEDIUM_RANDOM_WRITABLE (media)
+ && (media & BRASERO_MEDIUM_HAS_DATA))
+ priv->pvd = g_new0 (unsigned char, BRASERO_PVD_SIZE);
+
+ result = brasero_libburn_create_disc (self, &priv->ctx->disc, error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+
+ /* Note: we don't need to call burn_drive_get_status nor
+ * burn_disc_get_status since we took care of the disc
+ * checking thing earlier ourselves. Now there is a proper
+ * disc and tray is locked. */
+ opts = burn_write_opts_new (priv->ctx->drive);
+ burn_write_opts_set_perform_opc (opts, 0);
+
+ if (flags & BRASERO_BURN_FLAG_DAO)
+ burn_write_opts_set_write_type (opts,
+ BURN_WRITE_SAO,
+ BURN_BLOCK_SAO);
+ else {
+ burn_write_opts_set_write_type (opts,
+ BURN_WRITE_TAO,
+ BURN_BLOCK_MODE1);
+
+ /* we also set the start block to write from if MERGE is set.
+ * That only for random writable media; for other media libburn
+ * handles all by himself where to start writing. */
+ if (BRASERO_MEDIUM_RANDOM_WRITABLE (media)
+ && (flags & BRASERO_BURN_FLAG_MERGE)) {
+ guint64 address = 0;
+
+ brasero_job_get_next_writable_address (BRASERO_JOB (self), &address);
+
+ BRASERO_JOB_LOG (self, "Starting to write at block = %lli and byte %lli", address, address * 2048);
+ burn_write_opts_set_start_byte (opts, address * 2048);
+ }
+ }
+
+ if (!BRASERO_MEDIUM_RANDOM_WRITABLE (media))
+ burn_write_opts_set_multi (opts, (flags & BRASERO_BURN_FLAG_MULTI) != 0);
+
+ burn_write_opts_set_underrun_proof (opts, (flags & BRASERO_BURN_FLAG_BURNPROOF) != 0);
+ burn_write_opts_set_simulate (opts, (flags & BRASERO_BURN_FLAG_DUMMY) != 0);
+
+ brasero_job_get_rate (BRASERO_JOB (self), &rate);
+ burn_drive_set_speed (priv->ctx->drive, rate, 0);
+
+ if (burn_precheck_write (opts, priv->ctx->disc, reason, 0) < 1) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ reason);
+ return BRASERO_BURN_ERR;
+ }
+
+ /* If we're writing to a disc remember that the session can't be under
+ * 300 sectors (= 614400 bytes) */
+ brasero_job_get_session_output_size (BRASERO_JOB (self), &blocks, NULL);
+ if (blocks < 300)
+ brasero_job_set_output_size_for_current_track (BRASERO_JOB (self),
+ 300L - blocks,
+ 614400L - blocks * 2048);
+
+ if (!priv->sig_handler) {
+ burn_set_signal_handling ("brasero", NULL, 0);
+ priv->sig_handler = 1;
+ }
+
+ burn_disc_write (opts, priv->ctx->disc);
+ burn_write_opts_free (opts);
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_libburn_start_erase (BraseroLibburn *self,
+ GError **error)
+{
+ char reasons [BURN_REASONS_LEN];
+ struct burn_session *session;
+ struct burn_write_opts *opts;
+ BraseroLibburnPrivate *priv;
+ BraseroBurnResult result;
+ BraseroBurnFlag flags;
+ char prof_name [80];
+ int profile;
+ int fd;
+
+ priv = BRASERO_LIBBURN_PRIVATE (self);
+ if (burn_disc_get_profile (priv->ctx->drive, &profile, prof_name) <= 0) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_MEDIUM_INVALID,
+ _("The disc is not supported"));
+ return BRASERO_BURN_ERR;
+ }
+
+ /* here we try to respect the current formatting of DVD-RW. For
+ * overwritable media fast option means erase the first 64 Kib
+ * and long a forced reformatting */
+ brasero_job_get_flags (BRASERO_JOB (self), &flags);
+ if (profile == BRASERO_SCSI_PROF_DVD_RW_RESTRICTED) {
+ if (!(flags & BRASERO_BURN_FLAG_FAST_BLANK)) {
+ /* leave libburn choose the best format */
+ if (!priv->sig_handler) {
+ burn_set_signal_handling ("brasero", NULL, 0);
+ priv->sig_handler = 1;
+ }
+
+ burn_disc_format (priv->ctx->drive,
+ (off_t) 0,
+ (1 << 4));
+ return BRASERO_BURN_OK;
+ }
+ }
+ else if (profile == BRASERO_SCSI_PROF_DVD_RW_PLUS) {
+ if (!(flags & BRASERO_BURN_FLAG_FAST_BLANK)) {
+ /* Bit 2 is for format max available size
+ * Bit 4 is enforce (re)-format if needed
+ * 0x26 is DVD+RW format is to be set from bit 8
+ * in the latter case bit 7 needs to be set as
+ * well. */
+ if (!priv->sig_handler) {
+ burn_set_signal_handling ("brasero", NULL, 0);
+ priv->sig_handler = 1;
+ }
+
+ burn_disc_format (priv->ctx->drive,
+ (off_t) 0,
+ (1 << 2)|(1 << 4));
+ return BRASERO_BURN_OK;
+ }
+ }
+ else if (burn_disc_erasable (priv->ctx->drive)) {
+ /* This is mainly for CDRW and sequential DVD-RW */
+ if (!priv->sig_handler) {
+ burn_set_signal_handling ("brasero", NULL, 0);
+ priv->sig_handler = 1;
+ }
+
+ burn_disc_erase (priv->ctx->drive, (flags & BRASERO_BURN_FLAG_FAST_BLANK) != 0);
+ return BRASERO_BURN_OK;
+ }
+ else
+ BRASERO_JOB_NOT_SUPPORTED (self);
+
+ /* This is the "fast option": basically we only write 64 Kib of 0 from
+ * /dev/null */
+ fd = open ("/dev/null", O_RDONLY);
+ if (fd == -1) {
+ int errnum = errno;
+
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ /* Translators: first %s is the filename, second %s is the error
+ * generated from errno */
+ _("\"%s\" could not be opened (%s)"),
+ "/dev/null",
+ g_strerror (errnum));
+ return BRASERO_BURN_ERR;
+ }
+
+ priv->ctx->disc = burn_disc_create ();
+
+ /* create the session */
+ session = burn_session_create ();
+ burn_disc_add_session (priv->ctx->disc, session, BURN_POS_END);
+ burn_session_free (session);
+
+ result = brasero_libburn_add_fd_track (session,
+ fd,
+ BURN_MODE1,
+ 65536, /* 32 blocks */
+ priv->pvd,
+ error);
+ close (fd);
+
+ opts = burn_write_opts_new (priv->ctx->drive);
+ burn_write_opts_set_perform_opc (opts, 0);
+ burn_write_opts_set_underrun_proof (opts, 1);
+ burn_write_opts_set_simulate (opts, (flags & BRASERO_BURN_FLAG_DUMMY));
+
+ burn_drive_set_speed (priv->ctx->drive, burn_drive_get_write_speed (priv->ctx->drive), 0);
+ burn_write_opts_set_write_type (opts,
+ BURN_WRITE_TAO,
+ BURN_BLOCK_MODE1);
+
+ if (burn_precheck_write (opts, priv->ctx->disc, reasons, 0) <= 0) {
+ burn_write_opts_free (opts);
+
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ /* Translators: %s is the error returned by libburn */
+ _("An internal error occured (%s)"),
+ reasons);
+ return BRASERO_BURN_ERR;
+ }
+
+ if (!priv->sig_handler) {
+ burn_set_signal_handling ("brasero", NULL, 0);
+ priv->sig_handler = 1;
+ }
+
+ burn_disc_write (opts, priv->ctx->disc);
+ burn_write_opts_free (opts);
+
+ return result;
+}
+
+static BraseroBurnResult
+brasero_libburn_start (BraseroJob *job,
+ GError **error)
+{
+ BraseroLibburn *self;
+ BraseroJobAction action;
+ BraseroBurnResult result;
+ BraseroLibburnPrivate *priv;
+
+ self = BRASERO_LIBBURN (job);
+ priv = BRASERO_LIBBURN_PRIVATE (self);
+
+ brasero_job_get_action (job, &action);
+ if (action == BRASERO_JOB_ACTION_RECORD) {
+ priv->ctx = brasero_libburn_common_ctx_new (job, error);
+ if (!priv->ctx)
+ return BRASERO_BURN_ERR;
+
+ result = brasero_libburn_start_record (self, error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+
+ brasero_job_set_current_action (job,
+ BRASERO_BURN_ACTION_START_RECORDING,
+ NULL,
+ FALSE);
+ }
+ else if (action == BRASERO_JOB_ACTION_ERASE) {
+ priv->ctx = brasero_libburn_common_ctx_new (job, error);
+ if (!priv->ctx)
+ return BRASERO_BURN_ERR;
+
+ result = brasero_libburn_start_erase (self, error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+
+ brasero_job_set_current_action (job,
+ BRASERO_BURN_ACTION_BLANKING,
+ NULL,
+ FALSE);
+ }
+ else
+ BRASERO_JOB_NOT_SUPPORTED (self);
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_libburn_stop (BraseroJob *job,
+ GError **error)
+{
+ BraseroLibburn *self;
+ BraseroLibburnPrivate *priv;
+
+ self = BRASERO_LIBBURN (job);
+ priv = BRASERO_LIBBURN_PRIVATE (self);
+
+ if (priv->sig_handler) {
+ priv->sig_handler = 0;
+ burn_set_signal_handling (NULL, NULL, 1);
+ }
+
+ if (priv->ctx) {
+ brasero_libburn_common_ctx_free (priv->ctx);
+ priv->ctx = NULL;
+ }
+
+ if (priv->pvd) {
+ g_free (priv->pvd);
+ priv->pvd = NULL;
+ }
+
+ if (BRASERO_JOB_CLASS (parent_class)->stop)
+ BRASERO_JOB_CLASS (parent_class)->stop (job, error);
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_libburn_clock_tick (BraseroJob *job)
+{
+ BraseroLibburnPrivate *priv;
+ BraseroBurnResult result;
+ int ret;
+
+ priv = BRASERO_LIBBURN_PRIVATE (job);
+ result = brasero_libburn_common_status (job, priv->ctx);
+
+ if (result != BRASERO_BURN_OK)
+ return BRASERO_BURN_OK;
+
+ /* Double check that everything went well */
+ if (!burn_drive_wrote_well (priv->ctx->drive)) {
+ BRASERO_JOB_LOG (job, "Something went wrong");
+ brasero_job_error (job,
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_WRITE_MEDIUM,
+ _("An error occured while writing to disc")));
+ return BRASERO_BURN_OK;
+ }
+
+ /* That's finished */
+ if (!priv->pvd) {
+ brasero_job_set_dangerous (job, FALSE);
+ brasero_job_finished_session (job);
+ return BRASERO_BURN_OK;
+ }
+
+ /* In case we append data to a DVD+RW or DVD-RW
+ * (restricted overwrite) medium , we're not
+ * done since we need to overwrite the primary
+ * volume descriptor at sector 0.
+ * NOTE: This is a synchronous call but given the size of the buffer
+ * that shouldn't block.
+ * NOTE 2: in source we read the volume descriptors until we reached
+ * either the end of the buffer or the volume descriptor set end. That's
+ * kind of useless since for a DVD 16 blocks are written at a time. */
+ BRASERO_JOB_LOG (job, "Starting to overwrite primary volume descriptor");
+ ret = burn_random_access_write (priv->ctx->drive,
+ 0,
+ (char*)priv->pvd,
+ BRASERO_PVD_SIZE,
+ 0);
+ if (ret != 1) {
+ BRASERO_JOB_LOG (job, "Random write failed");
+ brasero_job_error (job,
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_WRITE_MEDIUM,
+ _("An error occured while writing to disc")));
+ return BRASERO_BURN_OK;
+ }
+
+ brasero_job_set_dangerous (job, FALSE);
+ brasero_job_finished_session (job);
+
+ return BRASERO_BURN_OK;
+}
+
+static void
+brasero_libburn_class_init (BraseroLibburnClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ BraseroJobClass *job_class = BRASERO_JOB_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (BraseroLibburnPrivate));
+
+ parent_class = g_type_class_peek_parent(klass);
+ object_class->finalize = brasero_libburn_finalize;
+
+ job_class->start = brasero_libburn_start;
+ job_class->stop = brasero_libburn_stop;
+ job_class->clock_tick = brasero_libburn_clock_tick;
+}
+
+static void
+brasero_libburn_init (BraseroLibburn *obj)
+{
+
+}
+
+static void
+brasero_libburn_finalize (GObject *object)
+{
+ BraseroLibburn *cobj;
+ BraseroLibburnPrivate *priv;
+
+ cobj = BRASERO_LIBBURN (object);
+ priv = BRASERO_LIBBURN_PRIVATE (cobj);
+
+ if (priv->ctx) {
+ brasero_libburn_common_ctx_free (priv->ctx);
+ priv->ctx = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static BraseroBurnResult
+brasero_libburn_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+ const BraseroMedia media_cd = BRASERO_MEDIUM_CD|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_WRITABLE|
+ BRASERO_MEDIUM_BLANK|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_HAS_AUDIO|
+ BRASERO_MEDIUM_HAS_DATA;
+ const BraseroMedia media_dvd_w = BRASERO_MEDIUM_DVD|
+ BRASERO_MEDIUM_PLUS|
+ BRASERO_MEDIUM_SEQUENTIAL|
+ BRASERO_MEDIUM_WRITABLE|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_HAS_DATA|
+ BRASERO_MEDIUM_BLANK;
+ const BraseroMedia media_dvd_rw = BRASERO_MEDIUM_DVD|
+ BRASERO_MEDIUM_SEQUENTIAL|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_HAS_DATA|
+ BRASERO_MEDIUM_BLANK;
+ const BraseroMedia media_dvd_rw_plus = BRASERO_MEDIUM_DVD|
+ BRASERO_MEDIUM_DUAL_L|
+ BRASERO_MEDIUM_PLUS|
+ BRASERO_MEDIUM_RESTRICTED|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_UNFORMATTED|
+ BRASERO_MEDIUM_BLANK|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_CLOSED|
+ BRASERO_MEDIUM_HAS_DATA;
+ GSList *output;
+ GSList *input;
+
+ brasero_plugin_define (plugin,
+ "libburn",
+ _("Libburn burns CD(RW), DVD+/-(RW)"),
+ "Philippe Rouquier",
+ 15);
+
+ /* libburn has no OVERBURN capabilities */
+
+ /* CD(R)W */
+ BRASERO_PLUGIN_ADD_STANDARD_CDR_FLAGS (plugin, BRASERO_BURN_FLAG_OVERBURN);
+ BRASERO_PLUGIN_ADD_STANDARD_CDRW_FLAGS (plugin, BRASERO_BURN_FLAG_OVERBURN);
+
+ /* audio support for CDs only */
+ input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_PIPE|
+ BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_AUDIO_FORMAT_RAW|
+ BRASERO_AUDIO_FORMAT_44100);
+
+ output = brasero_caps_disc_new (media_cd);
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (input);
+
+ /* Image support for CDs ... */
+ input = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_PIPE|
+ BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_IMAGE_FORMAT_BIN);
+
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (output);
+
+ /* ... and DVD-R and DVD+R ... */
+ output = brasero_caps_disc_new (media_dvd_w);
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (output);
+
+ BRASERO_PLUGIN_ADD_STANDARD_DVDR_PLUS_FLAGS (plugin, BRASERO_BURN_FLAG_OVERBURN);
+ BRASERO_PLUGIN_ADD_STANDARD_DVDR_FLAGS (plugin, BRASERO_BURN_FLAG_OVERBURN);
+
+ /* ... and DVD-RW (sequential) */
+ output = brasero_caps_disc_new (media_dvd_rw);
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (output);
+
+ BRASERO_PLUGIN_ADD_STANDARD_DVDRW_FLAGS (plugin, BRASERO_BURN_FLAG_OVERBURN);
+
+ /* for DVD+/-RW restricted */
+ output = brasero_caps_disc_new (media_dvd_rw_plus);
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (output);
+ g_slist_free (input);
+
+ BRASERO_PLUGIN_ADD_STANDARD_DVDRW_RESTRICTED_FLAGS (plugin, BRASERO_BURN_FLAG_OVERBURN);
+ BRASERO_PLUGIN_ADD_STANDARD_DVDRW_PLUS_FLAGS (plugin, BRASERO_BURN_FLAG_OVERBURN);
+
+ /* add blank caps */
+ output = brasero_caps_disc_new (BRASERO_MEDIUM_CD|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_CLOSED|
+ BRASERO_MEDIUM_HAS_DATA|
+ BRASERO_MEDIUM_HAS_AUDIO|
+ BRASERO_MEDIUM_BLANK);
+ brasero_plugin_blank_caps (plugin, output);
+ g_slist_free (output);
+
+ output = brasero_caps_disc_new (BRASERO_MEDIUM_DVD|
+ BRASERO_MEDIUM_PLUS|
+ BRASERO_MEDIUM_SEQUENTIAL|
+ BRASERO_MEDIUM_RESTRICTED|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_CLOSED|
+ BRASERO_MEDIUM_HAS_DATA|
+ BRASERO_MEDIUM_UNFORMATTED|
+ BRASERO_MEDIUM_BLANK);
+ brasero_plugin_blank_caps (plugin, output);
+ g_slist_free (output);
+
+ brasero_plugin_set_blank_flags (plugin,
+ BRASERO_MEDIUM_CD|
+ BRASERO_MEDIUM_DVD|
+ BRASERO_MEDIUM_SEQUENTIAL|
+ BRASERO_MEDIUM_RESTRICTED|
+ BRASERO_MEDIUM_REWRITABLE|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_CLOSED|
+ BRASERO_MEDIUM_HAS_DATA|
+ BRASERO_MEDIUM_HAS_AUDIO|
+ BRASERO_MEDIUM_UNFORMATTED|
+ BRASERO_MEDIUM_BLANK,
+ BRASERO_BURN_FLAG_NOGRACE|
+ BRASERO_BURN_FLAG_FAST_BLANK,
+ BRASERO_BURN_FLAG_NONE);
+
+ /* no dummy mode for DVD+RW */
+ brasero_plugin_set_blank_flags (plugin,
+ BRASERO_MEDIUM_DVDRW_PLUS|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_CLOSED|
+ BRASERO_MEDIUM_HAS_DATA|
+ BRASERO_MEDIUM_UNFORMATTED|
+ BRASERO_MEDIUM_BLANK,
+ BRASERO_BURN_FLAG_NOGRACE|
+ BRASERO_BURN_FLAG_FAST_BLANK,
+ BRASERO_BURN_FLAG_NONE);
+
+ brasero_plugin_register_group (plugin, _(LIBBURNIA_DESCRIPTION));
+ return BRASERO_BURN_OK;
+}
diff --git a/plugins/libburnia/burn-libburn.h b/plugins/libburnia/burn-libburn.h
new file mode 100644
index 0000000..b13f5b9
--- /dev/null
+++ b/plugins/libburnia/burn-libburn.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+ * burn-libburn.h
+ *
+ * lun aoû 21 14:33:24 2006
+ * Copyright 2006 Rouquier Philippe
+ * bonfire-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib-object.h>
+
+#ifndef BURN_LIBBURN_H
+#define BURN_LIBBURN_H
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_LIBBURN (brasero_libburn_get_type ())
+#define BRASERO_LIBBURN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_LIBBURN, BraseroLibburn))
+#define BRASERO_LIBBURN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_LIBBURN, BraseroLibburnClass))
+#define BRASERO_IS_LIBBURN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_LIBBURN))
+#define BRASERO_IS_LIBBURN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_LIBBURN))
+#define BRASERO_LIBBURN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_LIBBURN, BraseroLibburnClass))
+
+G_END_DECLS
+
+#endif /* BURN_LIBBURN_H */
diff --git a/plugins/libburnia/burn-libburnia.h b/plugins/libburnia/burn-libburnia.h
new file mode 100644
index 0000000..2165e78
--- /dev/null
+++ b/plugins/libburnia/burn-libburnia.h
@@ -0,0 +1,38 @@
+/***************************************************************************
+ * burn-libburnia.h
+ *
+ * Mon Oct 29 12:30:42 2007
+ * Copyright 2007 Philippe Rouquier
+ * <bonfire-app wanadoo fr>
+ ****************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA
+ */
+
+#ifndef _BURN_LIBBURNIA_H
+#define _BURN_LIBBURNIA_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define LIBBURNIA_DESCRIPTION N_("Libburnia burning suite")
+
+G_END_DECLS
+
+#endif /* _BURN_LIBBURNIA_H */
+
+
diff --git a/plugins/libburnia/burn-libisofs.c b/plugins/libburnia/burn-libisofs.c
new file mode 100644
index 0000000..55402f9
--- /dev/null
+++ b/plugins/libburnia/burn-libisofs.c
@@ -0,0 +1,1074 @@
+/***************************************************************************
+ * burn-libisofs.c
+ *
+ * lun aoû 21 14:34:32 2006
+ * Copyright 2006 Rouquier Philippe
+ * bonfire-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gstdio.h>
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+
+#include <libisofs/libisofs.h>
+#include <libburn/libburn.h>
+
+#include "burn-libburnia.h"
+#include "burn-libisofs.h"
+#include "burn-job.h"
+#include "brasero-units.h"
+#include "brasero-plugin-registration.h"
+#include "burn-libburn-common.h"
+#include "brasero-track-data.h"
+#include "brasero-track-image.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroLibisofs, brasero_libisofs, BRASERO_TYPE_JOB, BraseroJob);
+
+struct _BraseroLibisofsPrivate {
+ struct burn_source *libburn_src;
+
+ /* that's for multisession */
+ BraseroLibburnCtx *ctx;
+
+ GError *error;
+ GThread *thread;
+ GMutex *mutex;
+ GCond *cond;
+ guint thread_id;
+
+ guint cancel:1;
+};
+typedef struct _BraseroLibisofsPrivate BraseroLibisofsPrivate;
+
+#define BRASERO_LIBISOFS_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_LIBISOFS, BraseroLibisofsPrivate))
+
+static GObjectClass *parent_class = NULL;
+
+static gboolean
+brasero_libisofs_thread_finished (gpointer data)
+{
+ BraseroLibisofs *self = data;
+ BraseroLibisofsPrivate *priv;
+
+ priv = BRASERO_LIBISOFS_PRIVATE (self);
+
+ priv->thread_id = 0;
+ if (priv->error) {
+ GError *error;
+
+ error = priv->error;
+ priv->error = NULL;
+ brasero_job_error (BRASERO_JOB (self), error);
+ return FALSE;
+ }
+
+ if (brasero_job_get_fd_out (BRASERO_JOB (self), NULL) != BRASERO_BURN_OK) {
+ BraseroTrackImage *track = NULL;
+ gchar *output = NULL;
+
+ /* Let's make a track */
+ track = brasero_track_image_new ();
+ brasero_job_get_image_output (BRASERO_JOB (self),
+ &output,
+ NULL);
+ brasero_track_image_set_source (track,
+ output,
+ NULL,
+ BRASERO_IMAGE_FORMAT_BIN);
+
+ brasero_job_add_track (BRASERO_JOB (self), BRASERO_TRACK (track));
+
+ /* It's good practice to unref the track afterwards as we don't
+ * need it anymore. BraseroBurnSession refs it. */
+ g_object_unref (track);
+ }
+
+ brasero_job_finished_track (BRASERO_JOB (self));
+ return FALSE;
+}
+
+static BraseroBurnResult
+brasero_libisofs_write_sector_to_fd (BraseroLibisofs *self,
+ int fd,
+ gpointer buffer,
+ gint bytes_remaining)
+{
+ gint bytes_written = 0;
+ BraseroLibisofsPrivate *priv;
+
+ priv = BRASERO_LIBISOFS_PRIVATE (self);
+
+ while (bytes_remaining) {
+ gint written;
+
+ written = write (fd,
+ buffer + bytes_written,
+ bytes_remaining);
+
+ if (priv->cancel)
+ break;
+
+ if (written != bytes_remaining) {
+ if (errno != EINTR && errno != EAGAIN) {
+ int errsv = errno;
+
+ /* unrecoverable error */
+ priv->error = g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("Data could not be written (%s)"),
+ g_strerror (errsv));
+ return BRASERO_BURN_ERR;
+ }
+
+ g_thread_yield ();
+ }
+
+ if (written > 0) {
+ bytes_remaining -= written;
+ bytes_written += written;
+ }
+ }
+
+ return BRASERO_BURN_OK;
+}
+
+static void
+brasero_libisofs_write_image_to_fd_thread (BraseroLibisofs *self)
+{
+ const gint sector_size = 2048;
+ BraseroLibisofsPrivate *priv;
+ gint64 written_sectors = 0;
+ BraseroBurnResult result;
+ guchar buf [sector_size];
+ int fd = -1;
+
+ priv = BRASERO_LIBISOFS_PRIVATE (self);
+
+ brasero_job_set_current_action (BRASERO_JOB (self),
+ BRASERO_BURN_ACTION_CREATING_IMAGE,
+ NULL,
+ FALSE);
+
+ brasero_job_start_progress (BRASERO_JOB (self), FALSE);
+ brasero_job_get_fd_out (BRASERO_JOB (self), &fd);
+
+ BRASERO_JOB_LOG (self, "Writing to pipe");
+ while (priv->libburn_src->read_xt (priv->libburn_src, buf, sector_size) == sector_size) {
+ if (priv->cancel)
+ break;
+
+ result = brasero_libisofs_write_sector_to_fd (self,
+ fd,
+ buf,
+ sector_size);
+ if (result != BRASERO_BURN_OK)
+ break;
+
+ written_sectors ++;
+ brasero_job_set_written_track (BRASERO_JOB (self), written_sectors << 11);
+ }
+}
+
+static void
+brasero_libisofs_write_image_to_file_thread (BraseroLibisofs *self)
+{
+ const gint sector_size = 2048;
+ BraseroLibisofsPrivate *priv;
+ gint64 written_sectors = 0;
+ guchar buf [sector_size];
+ gchar *output;
+ FILE *file;
+
+ priv = BRASERO_LIBISOFS_PRIVATE (self);
+
+ brasero_job_get_image_output (BRASERO_JOB (self), &output, NULL);
+ file = fopen (output, "w");
+ if (!file) {
+ int errnum = errno;
+
+ if (errno == EACCES)
+ priv->error = g_error_new_literal (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_PERMISSION,
+ _("You do not have the required permission to write at this location"));
+ else
+ priv->error = g_error_new_literal (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ g_strerror (errnum));
+ return;
+ }
+
+ BRASERO_JOB_LOG (self, "writing to file %s", output);
+
+ brasero_job_set_current_action (BRASERO_JOB (self),
+ BRASERO_BURN_ACTION_CREATING_IMAGE,
+ NULL,
+ FALSE);
+
+ priv = BRASERO_LIBISOFS_PRIVATE (self);
+ brasero_job_start_progress (BRASERO_JOB (self), FALSE);
+
+ while (priv->libburn_src->read_xt (priv->libburn_src, buf, sector_size) == sector_size) {
+ if (priv->cancel)
+ break;
+
+ if (fwrite (buf, 1, sector_size, file) != sector_size) {
+ int errsv = errno;
+
+ priv->error = g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("Data could not be written (%s)"),
+ g_strerror (errsv));
+ break;
+ }
+
+ if (priv->cancel)
+ break;
+
+ written_sectors ++;
+ brasero_job_set_written_track (BRASERO_JOB (self), written_sectors << 11);
+ }
+
+ fclose (file);
+ file = NULL;
+}
+
+static gpointer
+brasero_libisofs_thread_started (gpointer data)
+{
+ BraseroLibisofsPrivate *priv;
+ BraseroLibisofs *self;
+
+ self = BRASERO_LIBISOFS (data);
+ priv = BRASERO_LIBISOFS_PRIVATE (self);
+
+ BRASERO_JOB_LOG (self, "Entering thread");
+ if (brasero_job_get_fd_out (BRASERO_JOB (self), NULL) == BRASERO_BURN_OK)
+ brasero_libisofs_write_image_to_fd_thread (self);
+ else
+ brasero_libisofs_write_image_to_file_thread (self);
+
+ if (!priv->cancel)
+ priv->thread_id = g_idle_add (brasero_libisofs_thread_finished, self);
+
+ BRASERO_JOB_LOG (self, "Getting out thread");
+
+ /* End thread */
+ g_mutex_lock (priv->mutex);
+ priv->thread = NULL;
+ g_cond_signal (priv->cond);
+ g_mutex_unlock (priv->mutex);
+
+ g_thread_exit (NULL);
+ return NULL;
+}
+
+static BraseroBurnResult
+brasero_libisofs_create_image (BraseroLibisofs *self,
+ GError **error)
+{
+ BraseroLibisofsPrivate *priv;
+ GError *thread_error = NULL;
+
+ priv = BRASERO_LIBISOFS_PRIVATE (self);
+
+ if (priv->thread)
+ return BRASERO_BURN_RUNNING;
+
+ if (iso_init () < 0) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("Libisofs could not be initialized."));
+ return BRASERO_BURN_ERR;
+ }
+
+ iso_set_msgs_severities ("NEVER", "ALL", "brasero (libisofs)");
+
+ g_mutex_lock (priv->mutex);
+ priv->thread = g_thread_create (brasero_libisofs_thread_started,
+ self,
+ TRUE,
+ &thread_error);
+ g_mutex_unlock (priv->mutex);
+
+ /* Reminder: this is not necessarily an error as the thread may have finished */
+ //if (!priv->thread)
+ // return BRASERO_BURN_ERR;
+
+ if (thread_error) {
+ g_propagate_error (error, thread_error);
+ return BRASERO_BURN_ERR;
+ }
+
+ return BRASERO_BURN_OK;
+}
+
+static gboolean
+brasero_libisofs_create_volume_thread_finished (gpointer data)
+{
+ BraseroLibisofs *self = data;
+ BraseroLibisofsPrivate *priv;
+ BraseroJobAction action;
+
+ priv = BRASERO_LIBISOFS_PRIVATE (self);
+
+ priv->thread_id = 0;
+ if (priv->error) {
+ GError *error;
+
+ error = priv->error;
+ priv->error = NULL;
+ brasero_job_error (BRASERO_JOB (self), error);
+ return FALSE;
+ }
+
+ brasero_job_get_action (BRASERO_JOB (self), &action);
+ if (action == BRASERO_JOB_ACTION_IMAGE) {
+ BraseroBurnResult result;
+ GError *error = NULL;
+
+ result = brasero_libisofs_create_image (self, &error);
+ if (error)
+ brasero_job_error (BRASERO_JOB (self), error);
+ else
+ return FALSE;
+ }
+
+ brasero_job_finished_track (BRASERO_JOB (self));
+ return FALSE;
+}
+
+static gint
+brasero_libisofs_sort_graft_points (gconstpointer a, gconstpointer b)
+{
+ const BraseroGraftPt *graft_a, *graft_b;
+ gint len_a, len_b;
+
+ graft_a = a;
+ graft_b = b;
+
+ /* we only want to know if:
+ * - a is a parent of b (a > b, retval < 0)
+ * - b is a parent of a (b > a, retval > 0). */
+ len_a = strlen (graft_a->path);
+ len_b = strlen (graft_b->path);
+
+ return len_a - len_b;
+}
+
+static int
+brasero_libisofs_import_read (IsoDataSource *src, uint32_t lba, uint8_t *buffer)
+{
+ struct burn_drive *d;
+ off_t data_count;
+ gint result;
+
+ d = (struct burn_drive*)src->data;
+
+ result = burn_read_data(d,
+ (off_t) lba * (off_t) 2048,
+ (char*)buffer,
+ 2048,
+ &data_count,
+ 0);
+ if (result < 0 )
+ return -1; /* error */
+
+ return 1;
+}
+
+static int
+brasero_libisofs_import_open (IsoDataSource *src)
+{
+ return 1;
+}
+
+static int
+brasero_libisofs_import_close (IsoDataSource *src)
+{
+ return 1;
+}
+
+static void
+brasero_libisofs_import_free (IsoDataSource *src)
+{ }
+
+static BraseroBurnResult
+brasero_libisofs_import_last_session (BraseroLibisofs *self,
+ IsoImage *image,
+ IsoWriteOpts *wopts,
+ GError **error)
+{
+ int result;
+ IsoReadOpts *opts;
+ BraseroMedia media;
+ IsoDataSource *src;
+ guint64 start_block;
+ guint64 session_block;
+ BraseroLibisofsPrivate *priv;
+
+ priv = BRASERO_LIBISOFS_PRIVATE (self);
+
+ priv->ctx = brasero_libburn_common_ctx_new (BRASERO_JOB (self), error);
+ if (!priv->ctx)
+ return BRASERO_BURN_ERR;
+
+ src = g_new0 (IsoDataSource, 1);
+ src->version = 0;
+ src->refcount = 1;
+ src->read_block = brasero_libisofs_import_read;
+ src->open = brasero_libisofs_import_open;
+ src->close = brasero_libisofs_import_close;
+ src->free_data = brasero_libisofs_import_free;
+ src->data = priv->ctx->drive;
+
+ result = iso_read_opts_new (&opts, 0);
+ if (result < 0) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("Read options could not be created"));
+ return BRASERO_BURN_ERR;
+ }
+
+ brasero_job_get_last_session_address (BRASERO_JOB (self), &session_block);
+ iso_read_opts_set_start_block (opts, session_block);
+
+ /* import image */
+ result = iso_image_import (image, src, opts, NULL);
+ iso_data_source_unref (src);
+ iso_read_opts_free (opts);
+
+ /* release the drive */
+ if (priv->ctx) {
+ /* This may not be a good idea ...*/
+ brasero_libburn_common_ctx_free (priv->ctx);
+ priv->ctx = NULL;
+ }
+
+ if (result < 0) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_IMAGE_LAST_SESSION,
+ _("Last session import failed"));
+ return BRASERO_BURN_ERR;
+ }
+
+ /* check is this is a DVD+RW */
+ brasero_job_get_next_writable_address (BRASERO_JOB (self), &start_block);
+
+ brasero_job_get_media (BRASERO_JOB (self), &media);
+ if (BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_DVDRW_PLUS)
+ || BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_DVDRW_RESTRICTED)
+ || BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_DVDRW_PLUS_DL)) {
+ /* This is specific to overwrite media; the start address is the
+ * size of all the previous data written */
+ BRASERO_JOB_LOG (self, "Growing image (start %i)", start_block);
+ }
+
+ /* set the start block for the multisession image */
+ iso_write_opts_set_ms_block (wopts, start_block);
+ iso_write_opts_set_appendable (wopts, 1);
+
+ iso_tree_set_replace_mode (image, ISO_REPLACE_ALWAYS);
+ return BRASERO_BURN_OK;
+}
+
+static gpointer
+brasero_libisofs_create_volume_thread (gpointer data)
+{
+ BraseroLibisofs *self = BRASERO_LIBISOFS (data);
+ BraseroLibisofsPrivate *priv;
+ BraseroTrack *track = NULL;
+ IsoWriteOpts *opts = NULL;
+ IsoImage *image = NULL;
+ BraseroBurnFlag flags;
+ GSList *grafts = NULL;
+ gchar *label = NULL;
+ gchar *publisher;
+ GSList *excluded;
+ GSList *iter;
+
+ priv = BRASERO_LIBISOFS_PRIVATE (self);
+
+ if (priv->libburn_src) {
+ burn_source_free (priv->libburn_src);
+ priv->libburn_src = NULL;
+ }
+
+ BRASERO_JOB_LOG (self, "creating volume");
+
+ /* create volume */
+ brasero_job_get_data_label (BRASERO_JOB (self), &label);
+ if (!iso_image_new (label, &image)) {
+ priv->error = g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("Volume could not be created"));
+ g_free (label);
+ goto end;
+ }
+
+ publisher = g_strdup_printf ("Brasero-%i.%i.%i",
+ BRASERO_MAJOR_VERSION,
+ BRASERO_MINOR_VERSION,
+ BRASERO_SUB);
+
+ if (label)
+ iso_image_set_volume_id (image, label);
+
+ iso_image_set_publisher_id (image, publisher);
+ iso_image_set_data_preparer_id (image, g_get_real_name ());
+
+ g_free (publisher);
+ g_free (label);
+
+ iso_write_opts_new (&opts, 2);
+
+ brasero_job_get_flags (BRASERO_JOB (self), &flags);
+ if (flags & BRASERO_BURN_FLAG_MERGE) {
+ BraseroBurnResult result;
+
+ result = brasero_libisofs_import_last_session (self,
+ image,
+ opts,
+ &priv->error);
+ if (result != BRASERO_BURN_OK)
+ goto end;
+ }
+ else if (flags & BRASERO_BURN_FLAG_APPEND) {
+ guint64 start_block;
+
+ brasero_job_get_next_writable_address (BRASERO_JOB (self), &start_block);
+ iso_write_opts_set_ms_block (opts, start_block);
+ }
+
+
+ brasero_job_start_progress (BRASERO_JOB (self), FALSE);
+
+ /* copy the list as we're going to reorder it */
+ brasero_job_get_current_track (BRASERO_JOB (self), &track);
+ grafts = brasero_track_data_get_grafts (BRASERO_TRACK_DATA (track));
+ grafts = g_slist_copy (grafts);
+ grafts = g_slist_sort (grafts, brasero_libisofs_sort_graft_points);
+
+ /* add global exclusions */
+ for (excluded = brasero_track_data_get_excluded (BRASERO_TRACK_DATA (track), FALSE);
+ excluded; excluded = excluded->next) {
+ gchar *uri, *local;
+
+ uri = excluded->data;
+ local = g_filename_from_uri (uri, NULL, NULL);
+ iso_tree_add_exclude (image, local);
+ g_free (local);
+ }
+
+ for (iter = grafts; iter; iter = iter->next) {
+ BraseroGraftPt *graft;
+ gboolean is_directory;
+ gchar *path_parent;
+ gchar *path_name;
+ IsoNode *parent;
+
+ if (priv->cancel)
+ goto end;
+
+ graft = iter->data;
+
+ BRASERO_JOB_LOG (self,
+ "Adding graft disc path = %s, URI = %s",
+ graft->path,
+ graft->uri);
+
+ /* search for parent node.
+ * NOTE: because of mkisofs/genisoimage, we add a "/" at the end
+ * directories. So make sure there isn't one when getting the
+ * parent path or g_path_get_dirname () will return the same
+ * exact name */
+ if (g_str_has_suffix (graft->path, G_DIR_SEPARATOR_S)) {
+ gchar *tmp;
+
+ /* remove trailing "/" */
+ tmp = g_strdup (graft->path);
+ tmp [strlen (tmp) - 1] = '\0';
+ path_parent = g_path_get_dirname (tmp);
+ path_name = g_path_get_basename (tmp);
+ g_free (tmp);
+
+ is_directory = TRUE;
+ }
+ else {
+ path_parent = g_path_get_dirname (graft->path);
+ path_name = g_path_get_basename (graft->path);
+ is_directory = FALSE;
+ }
+
+ iso_tree_path_to_node (image, path_parent, &parent);
+ g_free (path_parent);
+
+ if (!parent) {
+ /* an error has occured, possibly libisofs hasn't been
+ * able to find a parent for this node */
+ g_free (path_name);
+ priv->error = g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ /* Translators: %s is the path */
+ _("No parent could be found in the tree for the path \"%s\""),
+ graft->path);
+ goto end;
+ }
+
+ BRASERO_JOB_LOG (self, "Found parent");
+
+ /* add the file/directory to the volume */
+ if (graft->uri) {
+ gchar *local_path;
+ IsoDirIter *sibling;
+
+ /* graft->uri can be a path or a URI */
+ if (graft->uri [0] == '/')
+ local_path = g_strdup (graft->uri);
+ else if (g_str_has_prefix (graft->uri, "file://"))
+ local_path = g_filename_from_uri (graft->uri, NULL, NULL);
+ else
+ local_path = NULL;
+
+ if (!local_path){
+ priv->error = g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_FILE_NOT_LOCAL,
+ _("The file is not stored locally"));
+ g_free (path_name);
+ goto end;
+ }
+
+ /* see if the node exists with the same name among the
+ * children of the parent directory. If there is a
+ * sibling destroy it. */
+ sibling = NULL;
+ iso_dir_find_children (ISO_DIR (parent),
+ iso_new_find_conditions_name (path_name),
+ &sibling);
+ if (sibling) {
+ IsoNode *node;
+
+ BRASERO_JOB_LOG (self,
+ "Looking for sibling for %s",
+ path_name);
+
+ while (iso_dir_iter_next (sibling, &node) == 1) {
+ BRASERO_JOB_LOG (self,
+ "Found sibling for %s: removing %x",
+ path_name,
+ iso_dir_iter_remove (sibling));
+ }
+
+ iso_dir_iter_free (sibling);
+ }
+
+ if (is_directory) {
+ int result;
+ IsoDir *directory;
+
+ /* add directory node */
+ result = iso_tree_add_new_dir (ISO_DIR (parent), path_name, &directory);
+ if (result < 0) {
+ BRASERO_JOB_LOG (self,
+ "ERROR %s %x",
+ path_name,
+ result);
+ priv->error = g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("Libisofs reported an error while creating directory \"%s\""),
+ graft->path);
+ g_free (path_name);
+ goto end;
+ }
+
+ /* add contents */
+ result = iso_tree_add_dir_rec (image, directory, local_path);
+ if (result < 0) {
+ BRASERO_JOB_LOG (self,
+ "ERROR %s %x",
+ path_name,
+ result);
+ priv->error = g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("Libisofs reported an error while adding contents to directory \"%s\" (%x)"),
+ graft->path,
+ result);
+ g_free (path_name);
+ goto end;
+ }
+ }
+ else {
+ IsoNode *node;
+ int err;
+
+ err = iso_tree_add_node (image,
+ ISO_DIR (parent),
+ local_path,
+ &node);
+ if (err < 0) {
+ BRASERO_JOB_LOG (self,
+ "ERROR %s %x",
+ path_name,
+ err);
+ priv->error = g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("Libisofs reported an error while adding file at path \"%s\""),
+ graft->path);
+ g_free (path_name);
+ goto end;
+ }
+
+ if (iso_node_get_name (node)
+ && strcmp (iso_node_get_name (node), path_name)) {
+ err = iso_node_set_name (node, path_name);
+ if (err < 0) {
+ BRASERO_JOB_LOG (self,
+ "ERROR %s %x",
+ path_name,
+ err);
+ priv->error = g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("Libisofs reported an error while adding file at path \"%s\""),
+ graft->path);
+ g_free (path_name);
+ goto end;
+ }
+ }
+ }
+
+ g_free (local_path);
+ }
+ else if (iso_tree_add_new_dir (ISO_DIR (parent), path_name, NULL) < 0) {
+ priv->error = g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("Libisofs reported an error while creating directory \"%s\""),
+ graft->path);
+ g_free (path_name);
+ goto end;
+
+ }
+
+ g_free (path_name);
+ }
+
+
+end:
+
+ if (grafts)
+ g_slist_free (grafts);
+
+ if (!priv->error && !priv->cancel) {
+ gint64 size;
+ BraseroImageFS image_fs;
+
+ image_fs = brasero_track_data_get_fs (BRASERO_TRACK_DATA (track));
+
+ if ((image_fs & BRASERO_IMAGE_FS_ISO)
+ && (image_fs & BRASERO_IMAGE_ISO_FS_LEVEL_3))
+ iso_write_opts_set_iso_level (opts, 3);
+ else
+ iso_write_opts_set_iso_level (opts, 2);
+
+ iso_write_opts_set_rockridge (opts, 1);
+ iso_write_opts_set_joliet (opts, (image_fs & BRASERO_IMAGE_FS_JOLIET) != 0);
+ iso_write_opts_set_allow_deep_paths (opts, (image_fs & BRASERO_IMAGE_ISO_FS_DEEP_DIRECTORY) != 0);
+
+ if (iso_image_create_burn_source (image, opts, &priv->libburn_src) >= 0) {
+ size = priv->libburn_src->get_size (priv->libburn_src);
+ brasero_job_set_output_size_for_current_track (BRASERO_JOB (self),
+ BRASERO_BYTES_TO_SECTORS (size, 2048),
+ size);
+ }
+ }
+
+ if (opts)
+ iso_write_opts_free (opts);
+
+ if (image)
+ iso_image_unref (image);
+
+ if (!priv->cancel)
+ priv->thread_id = g_idle_add (brasero_libisofs_create_volume_thread_finished, self);
+
+ /* End thread */
+ g_mutex_lock (priv->mutex);
+ priv->thread = NULL;
+ g_cond_signal (priv->cond);
+ g_mutex_unlock (priv->mutex);
+
+ g_thread_exit (NULL);
+
+ return NULL;
+}
+
+static BraseroBurnResult
+brasero_libisofs_create_volume (BraseroLibisofs *self, GError **error)
+{
+ BraseroLibisofsPrivate *priv;
+ GError *thread_error = NULL;
+
+ priv = BRASERO_LIBISOFS_PRIVATE (self);
+ if (priv->thread)
+ return BRASERO_BURN_RUNNING;
+
+ if (iso_init () < 0) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("Libisofs could not be initialized."));
+ return BRASERO_BURN_ERR;
+ }
+
+ iso_set_msgs_severities ("NEVER", "ALL", "brasero (libisofs)");
+ g_mutex_lock (priv->mutex);
+ priv->thread = g_thread_create (brasero_libisofs_create_volume_thread,
+ self,
+ TRUE,
+ &thread_error);
+ g_mutex_unlock (priv->mutex);
+
+ /* Reminder: this is not necessarily an error as the thread may have finished */
+ //if (!priv->thread)
+ // return BRASERO_BURN_ERR;
+ if (thread_error) {
+ g_propagate_error (error, thread_error);
+ return BRASERO_BURN_ERR;
+ }
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_libisofs_start (BraseroJob *job,
+ GError **error)
+{
+ BraseroLibisofs *self;
+ BraseroJobAction action;
+ BraseroLibisofsPrivate *priv;
+
+ self = BRASERO_LIBISOFS (job);
+ priv = BRASERO_LIBISOFS_PRIVATE (self);
+
+ brasero_job_get_action (job, &action);
+ if (action == BRASERO_JOB_ACTION_SIZE) {
+ brasero_job_set_current_action (BRASERO_JOB (self),
+ BRASERO_BURN_ACTION_GETTING_SIZE,
+ NULL,
+ FALSE);
+ return brasero_libisofs_create_volume (self, error);
+ }
+
+ /* we need the source before starting anything */
+ if (!priv->libburn_src)
+ return brasero_libisofs_create_volume (self, error);
+
+ return brasero_libisofs_create_image (self, error);
+}
+
+static void
+brasero_libisofs_stop_real (BraseroLibisofs *self)
+{
+ BraseroLibisofsPrivate *priv;
+
+ priv = BRASERO_LIBISOFS_PRIVATE (self);
+
+ /* NOTE: this can only happen when we're preparing the volumes for a
+ * multi session disc. At this point we're only running to get the size
+ * of the future volume and we can't race with libburn plugin that isn't
+ * operating at this stage. */
+ if (priv->ctx) {
+ brasero_libburn_common_ctx_free (priv->ctx);
+ priv->ctx = NULL;
+ }
+
+ g_mutex_lock (priv->mutex);
+ if (priv->thread) {
+ if (priv->libburn_src)
+ priv->libburn_src->cancel (priv->libburn_src);
+
+ priv->cancel = 1;
+ g_cond_wait (priv->cond, priv->mutex);
+ priv->cancel = 0;
+ }
+ g_mutex_unlock (priv->mutex);
+
+ if (priv->thread_id) {
+ g_source_remove (priv->thread_id);
+ priv->thread_id = 0;
+ }
+
+ if (priv->error) {
+ g_error_free (priv->error);
+ priv->error = NULL;
+ }
+}
+
+static BraseroBurnResult
+brasero_libisofs_stop (BraseroJob *job,
+ GError **error)
+{
+ BraseroLibisofs *self;
+
+ self = BRASERO_LIBISOFS (job);
+ brasero_libisofs_stop_real (self);
+ return BRASERO_BURN_OK;
+}
+
+static void
+brasero_libisofs_class_init (BraseroLibisofsClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ BraseroJobClass *job_class = BRASERO_JOB_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (BraseroLibisofsPrivate));
+
+ parent_class = g_type_class_peek_parent(klass);
+ object_class->finalize = brasero_libisofs_finalize;
+
+ job_class->start = brasero_libisofs_start;
+ job_class->stop = brasero_libisofs_stop;
+}
+
+static void
+brasero_libisofs_init (BraseroLibisofs *obj)
+{
+ BraseroLibisofsPrivate *priv;
+
+ priv = BRASERO_LIBISOFS_PRIVATE (obj);
+ priv->mutex = g_mutex_new ();
+ priv->cond = g_cond_new ();
+}
+
+static void
+brasero_libisofs_clean_output (BraseroLibisofs *self)
+{
+ BraseroLibisofsPrivate *priv;
+
+ priv = BRASERO_LIBISOFS_PRIVATE (self);
+
+ if (priv->libburn_src) {
+ burn_source_free (priv->libburn_src);
+ priv->libburn_src = NULL;
+ }
+
+ /* close libisofs library */
+ iso_finish ();
+}
+
+static void
+brasero_libisofs_finalize (GObject *object)
+{
+ BraseroLibisofs *cobj;
+ BraseroLibisofsPrivate *priv;
+
+ cobj = BRASERO_LIBISOFS (object);
+ priv = BRASERO_LIBISOFS_PRIVATE (object);
+
+ brasero_libisofs_stop_real (cobj);
+ brasero_libisofs_clean_output (cobj);
+
+ if (priv->mutex) {
+ g_mutex_free (priv->mutex);
+ priv->mutex = NULL;
+ }
+
+ if (priv->cond) {
+ g_cond_free (priv->cond);
+ priv->cond = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static BraseroBurnResult
+brasero_libisofs_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+ GSList *output;
+ GSList *input;
+
+ brasero_plugin_define (plugin,
+ "libisofs",
+ _("Libisofs creates disc images from files"),
+ "Philippe Rouquier",
+ 0);
+
+ brasero_plugin_set_flags (plugin,
+ BRASERO_MEDIUM_CDR|
+ BRASERO_MEDIUM_CDRW|
+ BRASERO_MEDIUM_DVDR|
+ BRASERO_MEDIUM_DVDRW|
+ BRASERO_MEDIUM_DUAL_L|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_HAS_AUDIO|
+ BRASERO_MEDIUM_HAS_DATA,
+ BRASERO_BURN_FLAG_APPEND|
+ BRASERO_BURN_FLAG_MERGE,
+ BRASERO_BURN_FLAG_NONE);
+
+ brasero_plugin_set_flags (plugin,
+ BRASERO_MEDIUM_DVDRW_PLUS|
+ BRASERO_MEDIUM_RESTRICTED|
+ BRASERO_MEDIUM_DUAL_L|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_CLOSED|
+ BRASERO_MEDIUM_HAS_DATA,
+ BRASERO_BURN_FLAG_APPEND|
+ BRASERO_BURN_FLAG_MERGE,
+ BRASERO_BURN_FLAG_NONE);
+
+ output = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE|
+ BRASERO_PLUGIN_IO_ACCEPT_PIPE,
+ BRASERO_IMAGE_FORMAT_BIN);
+
+ input = brasero_caps_data_new (BRASERO_IMAGE_FS_ISO|
+ BRASERO_IMAGE_ISO_FS_DEEP_DIRECTORY|
+ BRASERO_IMAGE_ISO_FS_LEVEL_3|
+ BRASERO_IMAGE_FS_JOLIET);
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (input);
+
+ input = brasero_caps_data_new (BRASERO_IMAGE_FS_ISO|
+ BRASERO_IMAGE_ISO_FS_DEEP_DIRECTORY|
+ BRASERO_IMAGE_ISO_FS_LEVEL_3|
+ BRASERO_IMAGE_FS_SYMLINK);
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (input);
+
+ g_slist_free (output);
+
+ brasero_plugin_register_group (plugin, _(LIBBURNIA_DESCRIPTION));
+
+ return BRASERO_BURN_OK;
+}
diff --git a/plugins/libburnia/burn-libisofs.h b/plugins/libburnia/burn-libisofs.h
new file mode 100644
index 0000000..1224e96
--- /dev/null
+++ b/plugins/libburnia/burn-libisofs.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+ * burn-libisofs.h
+ *
+ * lun aoû 21 14:34:32 2006
+ * Copyright 2006 Rouquier Philippe
+ * bonfire-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifndef BURN_LIBISOFS_H
+#define BURN_LIBISOFS_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_LIBISOFS (brasero_libisofs_get_type ())
+#define BRASERO_LIBISOFS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_LIBISOFS, BraseroLibisofs))
+#define BRASERO_LIBISOFS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_LIBISOFS, BraseroLibisofsClass))
+#define BRASERO_IS_LIBISOFS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_LIBISOFS))
+#define BRASERO_IS_LIBISOFS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_LIBISOFS))
+#define BRASERO_LIBISOFS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_LIBISOFS, BraseroLibisofsClass))
+
+G_END_DECLS
+
+#endif /* BURN_LIBISOFS_H */
diff --git a/plugins/libburnia/burn-libread-disc.h b/plugins/libburnia/burn-libread-disc.h
new file mode 100644
index 0000000..3a08a95
--- /dev/null
+++ b/plugins/libburnia/burn-libread-disc.h
@@ -0,0 +1,68 @@
+/***************************************************************************
+ * burn-libread-disc.h
+ *
+ * ven aoû 25 22:15:11 2006
+ * Copyright 2006 Rouquier Philippe
+ * bonfire-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef BURN_LIBREAD_DISC_H
+#define BURN_LIBREAD_DISC_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "burn-libburn-common.h"
+
+#ifdef HAVE_LIBBURN
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_LIBREAD_DISC (brasero_libread_disc_get_type ())
+#define BRASERO_LIBREAD_DISC(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_LIBREAD_DISC, BraseroLibreadDisc))
+#define BRASERO_LIBREAD_DISC_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_LIBREAD_DISC, BraseroLibreadDiscClass))
+#define BRASERO_IS_LIBREAD_DISC(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_LIBREAD_DISC))
+#define BRASERO_IS_LIBREAD_DISC_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_LIBREAD_DISC))
+#define BRASERO_LIBREAD_DISC_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_LIBREAD_DISC, BraseroLibreadDiscClass))
+
+typedef struct _BraseroLibreadDisc BraseroLibreadDisc;
+typedef struct _BraseroLibreadDiscPrivate BraseroLibreadDiscPrivate;
+typedef struct _BraseroLibreadDiscClass BraseroLibreadDiscClass;
+
+struct _BraseroLibreadDisc {
+ BraseroLibburnCommon parent;
+ BraseroLibreadDiscPrivate *priv;
+};
+
+struct _BraseroLibreadDiscClass {
+ BraseroLibburnCommonClass parent_class;
+};
+
+GType brasero_libread_disc_get_type ();
+BraseroLibreadDisc *brasero_libread_disc_new ();
+
+G_END_DECLS
+
+#else
+
+#define BRASERO_TYPE_LIBREAD_DISC G_TYPE_NONE
+
+#endif /* HAVE_LIBBURN*/
+
+#endif /* BURN_LIBREAD_DISC_H */
diff --git a/plugins/local-track/Makefile.am b/plugins/local-track/Makefile.am
new file mode 100644
index 0000000..fad0244
--- /dev/null
+++ b/plugins/local-track/Makefile.am
@@ -0,0 +1,31 @@
+
+INCLUDES = \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/libbrasero-media/ \
+ -I$(top_builddir)/libbrasero-media/ \
+ -I$(top_srcdir)/libbrasero-burn \
+ -I$(top_builddir)/libbrasero-burn/ \
+ -DBRASERO_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
+ -DBRASERO_PREFIX=\"$(prefix)\" \
+ -DBRASERO_SYSCONFDIR=\"$(sysconfdir)\" \
+ -DBRASERO_DATADIR=\"$(datadir)/brasero\" \
+ -DBRASERO_LIBDIR=\"$(libdir)\" \
+ $(DISABLE_DEPRECATED) \
+ $(BRASERO_GLIB_CFLAGS) \
+ $(BRASERO_GIO_CFLAGS)
+
+#local-track
+local_trackdir = $(libdir)/brasero/plugins
+local_track_LTLIBRARIES = libbrasero-local-track.la
+
+libbrasero_local_track_la_SOURCES = burn-local-image.c burn-local-image.h
+libbrasero_local_track_la_LIBADD = $(BRASERO_GLIB_LIBS) $(BRASERO_GIO_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_local_track_la_LDFLAGS = -module -avoid-version
+
+#burn-uri
+burn_uridir = $(libdir)/brasero/plugins
+burn_uri_LTLIBRARIES = libbrasero-burn-uri.la
+
+libbrasero_burn_uri_la_SOURCES = burn-uri.c burn-uri.h
+libbrasero_burn_uri_la_LIBADD = $(BRASERO_GLIB_LIBS) $(BRASERO_GIO_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_burn_uri_la_LDFLAGS = -module -avoid-version
diff --git a/plugins/local-track/burn-local-image.c b/plugins/local-track/burn-local-image.c
new file mode 100644
index 0000000..e0e50e8
--- /dev/null
+++ b/plugins/local-track/burn-local-image.c
@@ -0,0 +1,946 @@
+/***************************************************************************
+ * burn-local-image.c
+ *
+ * dim jui 9 10:54:14 2006
+ * Copyright 2006 Rouquier Philippe
+ * brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* This is for getline() and isblank() */
+#define _GNU_SOURCE
+
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+
+#include <gio/gio.h>
+
+#include <gmodule.h>
+
+#include "burn-job.h"
+#include "brasero-plugin-registration.h"
+#include "burn-local-image.h"
+#include "brasero-xfer.h"
+#include "brasero-track-image.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroLocalTrack, brasero_local_track, BRASERO_TYPE_JOB, BraseroJob);
+
+struct _BraseroLocalTrackPrivate {
+ GCancellable *cancel;
+ BraseroXferCtx *xfer_ctx;
+
+ gchar *checksum;
+ gchar *checksum_path;
+ GChecksumType gchecksum_type;
+ BraseroChecksumType checksum_type;
+
+ GHashTable *nonlocals;
+
+ guint thread_id;
+ GThread *thread;
+ GMutex *mutex;
+ GCond *cond;
+
+ GSList *src_list;
+ GSList *dest_list;
+
+ GError *error;
+
+ guint download_checksum:1;
+};
+typedef struct _BraseroLocalTrackPrivate BraseroLocalTrackPrivate;
+
+#define BRASERO_LOCAL_TRACK_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_LOCAL_TRACK, BraseroLocalTrackPrivate))
+
+static GObjectClass *parent_class = NULL;
+
+static BraseroBurnResult
+brasero_local_track_clock_tick (BraseroJob *job)
+{
+ BraseroLocalTrackPrivate *priv;
+ goffset written = 0;
+ goffset total = 0;
+
+ priv = BRASERO_LOCAL_TRACK_PRIVATE (job);
+
+ if (!priv->xfer_ctx)
+ return BRASERO_BURN_OK;
+
+ brasero_job_start_progress (job, FALSE);
+
+ brasero_xfer_get_progress (priv->xfer_ctx,
+ &written,
+ &total);
+ brasero_job_set_progress (job, (gdouble) written / (gdouble) total);
+
+ return BRASERO_BURN_OK;
+}
+
+/**
+ * That's for URI translation ...
+ */
+
+static gchar *
+brasero_local_track_translate_uri (BraseroLocalTrack *self,
+ const gchar *uri)
+{
+ gchar *newuri;
+ gchar *parent;
+ BraseroLocalTrackPrivate *priv;
+
+ priv = BRASERO_LOCAL_TRACK_PRIVATE (self);
+
+ if (!uri)
+ return NULL;
+
+ /* see if it is a local file */
+ if (g_str_has_prefix (uri, "file://"))
+ return g_strdup (uri);
+
+ /* see if it was downloaded itself */
+ newuri = g_hash_table_lookup (priv->nonlocals, uri);
+ if (newuri) {
+ /* we copy this string as it will be freed when freeing
+ * downloaded GSList */
+ return g_strdup (newuri);
+ }
+
+ /* see if one of its parent will be downloaded */
+ parent = g_path_get_dirname (uri);
+ while (parent [1] != '\0') {
+ gchar *tmp;
+
+ tmp = g_hash_table_lookup (priv->nonlocals, parent);
+ if (tmp) {
+ newuri = g_build_path (G_DIR_SEPARATOR_S,
+ tmp,
+ uri + strlen (parent),
+ NULL);
+ g_free (parent);
+ return newuri;
+ }
+
+ tmp = parent;
+ parent = g_path_get_dirname (tmp);
+ g_free (tmp);
+ }
+
+ /* that should not happen */
+ BRASERO_JOB_LOG (self, "Can't find a downloaded parent for %s", uri);
+
+ g_free (parent);
+ return NULL;
+}
+
+static BraseroBurnResult
+brasero_local_track_read_checksum (BraseroLocalTrack *self)
+{
+ gint size;
+ FILE *file;
+ gchar *name;
+ gchar *source;
+ gchar *line = NULL;
+ size_t line_len = 0;
+ BraseroTrack *track = NULL;
+ BraseroLocalTrackPrivate *priv;
+
+ priv = BRASERO_LOCAL_TRACK_PRIVATE (self);
+
+ /* get the file_checksum from the checksum file */
+ file = fopen (priv->checksum_path, "r");
+
+ /* get the name of the file that was downloaded */
+ brasero_job_get_current_track (BRASERO_JOB (self), &track);
+ source = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (track), TRUE);
+ name = g_path_get_basename (source);
+ g_free (source);
+
+ if (!file) {
+ g_free (name);
+ BRASERO_JOB_LOG (self, "Impossible to open the downloaded checksum file");
+ return BRASERO_BURN_ERR;
+ }
+
+ /* find a line with the name of our file (there could be several ones) */
+ BRASERO_JOB_LOG (self, "Searching %s in file", name);
+ while ((size = getline (&line, &line_len, file)) > 0) {
+ if (strstr (line, name)) {
+ gchar *ptr;
+
+ /* Skip blanks */
+ ptr = line;
+ while (isblank (*ptr)) { ptr ++; size --; }
+
+ if (g_checksum_type_get_length (priv->checksum_type) * 2 > size) {
+ g_free (line);
+ line = NULL;
+ continue;
+ }
+
+ ptr [g_checksum_type_get_length (priv->gchecksum_type) * 2] = '\0';
+ priv->checksum = g_strdup (ptr);
+ g_free (line);
+ BRASERO_JOB_LOG (self, "Found checksum %s", priv->checksum);
+ break;
+ }
+
+ g_free (line);
+ line = NULL;
+ }
+ fclose (file);
+
+ return (priv->checksum? BRASERO_BURN_OK:BRASERO_BURN_ERR);
+}
+
+static BraseroBurnResult
+brasero_local_track_download_checksum (BraseroLocalTrack *self)
+{
+ BraseroLocalTrackPrivate *priv;
+ BraseroBurnResult result;
+ BraseroTrack *track;
+ gchar *checksum_src;
+ GFile *src, *dest;
+ GFile *tmp;
+ gchar *uri;
+
+ priv = BRASERO_LOCAL_TRACK_PRIVATE (self);
+
+ BRASERO_JOB_LOG (self, "Copying checksum file");
+
+ /* generate a unique name for destination */
+ result = brasero_job_get_tmp_file (BRASERO_JOB (self),
+ NULL,
+ &priv->checksum_path,
+ NULL);
+ if (result != BRASERO_BURN_OK)
+ goto error;
+
+ brasero_job_set_current_action (BRASERO_JOB (self),
+ BRASERO_BURN_ACTION_FILE_COPY,
+ _("Copying checksum file"),
+ TRUE);
+
+ /* This is an image. See if there is any checksum sitting in the same
+ * directory to check our download integrity.
+ * Try all types of checksum. */
+ brasero_job_get_current_track (BRASERO_JOB (self), &track);
+ uri = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (track), TRUE);
+ dest = g_file_new_for_path (priv->checksum_path);
+
+ /* Try with three difference sources */
+ checksum_src = g_strdup_printf ("%s.md5", uri);
+ src = g_file_new_for_uri (checksum_src);
+ g_free (checksum_src);
+
+ result = brasero_xfer_start (priv->xfer_ctx,
+ src,
+ dest,
+ priv->cancel,
+ NULL);
+ g_object_unref (src);
+
+ if (result == BRASERO_BURN_OK) {
+ priv->gchecksum_type = G_CHECKSUM_MD5;
+ priv->checksum_type = BRASERO_CHECKSUM_MD5;
+ goto end;
+ }
+
+ checksum_src = g_strdup_printf ("%s.sha1", uri);
+ src = g_file_new_for_uri (checksum_src);
+ g_free (checksum_src);
+
+ result = brasero_xfer_start (priv->xfer_ctx,
+ src,
+ dest,
+ priv->cancel,
+ NULL);
+ g_object_unref (src);
+
+ if (result == BRASERO_BURN_OK) {
+ priv->gchecksum_type = G_CHECKSUM_SHA1;
+ priv->checksum_type = BRASERO_CHECKSUM_SHA1;
+ goto end;
+ }
+
+ checksum_src = g_strdup_printf ("%s.sha256", uri);
+ src = g_file_new_for_uri (checksum_src);
+ g_free (checksum_src);
+
+ result = brasero_xfer_start (priv->xfer_ctx,
+ src,
+ dest,
+ priv->cancel,
+ NULL);
+ g_object_unref (src);
+
+ if (result == BRASERO_BURN_OK) {
+ priv->gchecksum_type = G_CHECKSUM_SHA256;
+ priv->checksum_type = BRASERO_CHECKSUM_SHA256;
+ goto end;
+ }
+
+ /* There are also ftp sites that includes all images checksum in one big
+ * SHA1 file. */
+ tmp = g_file_new_for_uri (uri);
+ src = g_file_get_parent (tmp);
+ g_object_unref (tmp);
+
+ tmp = src;
+ src = g_file_get_child_for_display_name (tmp, "SHA1SUM", NULL);
+ g_object_unref (tmp);
+
+ result = brasero_xfer_start (priv->xfer_ctx,
+ src,
+ dest,
+ priv->cancel,
+ NULL);
+ g_object_unref (src);
+
+ if (result != BRASERO_BURN_OK) {
+ g_free (uri);
+ g_object_unref (dest);
+ goto error;
+ }
+
+ priv->gchecksum_type = G_CHECKSUM_SHA1;
+ priv->checksum_type = BRASERO_CHECKSUM_SHA1;
+
+end:
+
+ g_object_unref (dest);
+ g_free (uri);
+
+ return result;
+
+error:
+
+ /* we give up */
+ BRASERO_JOB_LOG (self, "No checksum file available");
+ g_free (priv->checksum_path);
+ priv->checksum_path = NULL;
+ return result;
+}
+
+static BraseroBurnResult
+brasero_local_track_update_track (BraseroLocalTrack *self)
+{
+ BraseroTrack *track;
+ BraseroTrack *current = NULL;
+ BraseroLocalTrackPrivate *priv;
+
+ priv = BRASERO_LOCAL_TRACK_PRIVATE (self);
+
+ /* now we update all the track with the local uris in retval */
+ brasero_job_get_current_track (BRASERO_JOB (self), ¤t);
+
+ /* make a copy of the tracks instead of modifying them */
+ if (BRASERO_IS_TRACK_DATA (current)) {
+ GSList *next;
+ GSList *grafts;
+ GSList *unreadable;
+ guint64 file_num = 0;
+
+ track = BRASERO_TRACK (brasero_track_data_new ());
+ brasero_track_tag_copy_missing (BRASERO_TRACK (track), current);
+
+ brasero_track_data_add_fs (BRASERO_TRACK_DATA (track), brasero_track_data_get_fs (BRASERO_TRACK_DATA (current)));
+
+ brasero_track_data_get_file_num (BRASERO_TRACK_DATA (current), &file_num);
+ brasero_track_data_set_file_num (BRASERO_TRACK_DATA (track), file_num);
+
+ grafts = brasero_track_data_get_grafts (BRASERO_TRACK_DATA (current));
+ for (; grafts; grafts = grafts->next) {
+ BraseroGraftPt *graft;
+ gchar *uri;
+
+ graft = grafts->data;
+ uri = brasero_local_track_translate_uri (self, graft->uri);
+ if (uri) {
+ g_free (graft->uri);
+ graft->uri = uri;
+ }
+ }
+
+ BRASERO_JOB_LOG (self, "Translating unreadable");
+
+ /* Translate the globally excluded.
+ * NOTE: if we can't find a parent for an excluded URI that
+ * means it shouldn't be included. */
+ unreadable = brasero_track_data_get_excluded (BRASERO_TRACK_DATA (current), FALSE);
+ for (; unreadable; unreadable = next) {
+ gchar *new_uri;
+
+ next = unreadable->next;
+ new_uri = brasero_local_track_translate_uri (self, unreadable->data);
+ g_free (unreadable->data);
+
+ if (new_uri)
+ unreadable->data = new_uri;
+ else
+ unreadable = g_slist_remove (unreadable, unreadable->data);
+ }
+ }
+ else if (BRASERO_IS_TRACK_STREAM (track)) {
+ gchar *uri;
+ gchar *newuri;
+
+ uri = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (current), TRUE);
+ newuri = brasero_local_track_translate_uri (self, uri);
+
+ track = BRASERO_TRACK (brasero_track_stream_new ());
+ brasero_track_tag_copy_missing (BRASERO_TRACK (track), current);
+ brasero_track_stream_set_source (BRASERO_TRACK_STREAM (track), newuri);
+ brasero_track_stream_set_format (BRASERO_TRACK_STREAM (track), brasero_track_stream_get_format (BRASERO_TRACK_STREAM (current)));
+ brasero_track_stream_set_boundaries (BRASERO_TRACK_STREAM (track),
+ brasero_track_stream_get_start (BRASERO_TRACK_STREAM (current)),
+ brasero_track_stream_get_end (BRASERO_TRACK_STREAM (current)),
+ brasero_track_stream_get_gap (BRASERO_TRACK_STREAM (current)));
+ g_free (uri);
+ }
+ else if (BRASERO_IS_TRACK_IMAGE (track)) {
+ gchar *uri;
+ gchar *newtoc;
+ gchar *newimage;
+ guint64 blocks = 0;
+
+ uri = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (current), TRUE);
+ newimage = brasero_local_track_translate_uri (self, uri);
+ g_free (uri);
+
+ uri = brasero_track_image_get_toc_source (BRASERO_TRACK_IMAGE (current), TRUE);
+ newtoc = brasero_local_track_translate_uri (self, uri);
+ g_free (uri);
+
+ brasero_track_get_size (current, &blocks, NULL);
+
+ track = BRASERO_TRACK (brasero_track_image_new ());
+ brasero_track_tag_copy_missing (BRASERO_TRACK (track), current);
+ brasero_track_image_set_source (BRASERO_TRACK_IMAGE (track),
+ newimage,
+ newtoc,
+ brasero_track_image_get_format (BRASERO_TRACK_IMAGE (current)));
+ brasero_track_image_set_block_num (BRASERO_TRACK_IMAGE (track), blocks);
+ }
+ else
+ BRASERO_JOB_NOT_SUPPORTED (self);
+
+ if (priv->download_checksum)
+ brasero_track_set_checksum (track,
+ priv->checksum_type,
+ priv->checksum);
+
+ brasero_job_add_track (BRASERO_JOB (self), track);
+
+ /* It's good practice to unref the track afterwards as we don't need it
+ * anymore. BraseroTaskCtx refs it. */
+ g_object_unref (track);
+
+ return BRASERO_BURN_OK;
+}
+
+static gboolean
+brasero_local_track_thread_finished (BraseroLocalTrack *self)
+{
+ BraseroLocalTrackPrivate *priv;
+
+ priv = BRASERO_LOCAL_TRACK_PRIVATE (self);
+
+ priv->thread_id = 0;
+
+ if (priv->xfer_ctx) {
+ brasero_xfer_free (priv->xfer_ctx);
+ priv->xfer_ctx = NULL;
+ }
+
+ if (priv->cancel) {
+ g_object_unref (priv->cancel);
+ priv->cancel = NULL;
+ if (g_cancellable_is_cancelled (priv->cancel))
+ return FALSE;
+ }
+
+ if (priv->error) {
+ GError *error;
+
+ error = priv->error;
+ priv->error = NULL;
+ brasero_job_error (BRASERO_JOB (self), error);
+ return FALSE;
+ }
+
+ brasero_local_track_update_track (self);
+
+ brasero_job_finished_track (BRASERO_JOB (self));
+ return FALSE;
+}
+
+static gpointer
+brasero_local_track_thread (gpointer data)
+{
+ BraseroLocalTrack *self = BRASERO_LOCAL_TRACK (data);
+ BraseroLocalTrackPrivate *priv;
+ GSList *src, *dest;
+
+ priv = BRASERO_LOCAL_TRACK_PRIVATE (self);
+ brasero_job_set_current_action (BRASERO_JOB (self),
+ BRASERO_BURN_ACTION_FILE_COPY,
+ _("Copying files locally"),
+ TRUE);
+
+ for (src = priv->src_list, dest = priv->dest_list;
+ src && dest;
+ src = src->next, dest = dest->next) {
+ gchar *name;
+ gchar *string;
+ GFile *src_file;
+ GFile *dest_file;
+ BraseroBurnResult result;
+
+ src_file = src->data;
+ dest_file = dest->data;
+
+ name = g_file_get_basename (src_file);
+ BRASERO_JOB_LOG (self, "Downloading %s", name);
+ string = g_strdup_printf (_("Copying `%s` locally"), name);
+ g_free (name);
+
+ result = brasero_xfer_start (priv->xfer_ctx,
+ src_file,
+ dest_file,
+ priv->cancel,
+ &priv->error);
+
+ if (g_cancellable_is_cancelled (priv->cancel))
+ goto end;
+
+ if (result != BRASERO_BURN_OK)
+ goto end;
+ }
+
+ /* successfully downloaded files, get a checksum if we can. */
+ if (priv->download_checksum
+ && !priv->checksum_path
+ && brasero_local_track_download_checksum (self) == BRASERO_BURN_OK)
+ brasero_local_track_read_checksum (self);
+
+end:
+
+ if (!g_cancellable_is_cancelled (priv->cancel))
+ priv->thread_id = g_idle_add ((GSourceFunc) brasero_local_track_thread_finished, self);
+
+ /* End thread */
+ g_mutex_lock (priv->mutex);
+ priv->thread = NULL;
+ g_cond_signal (priv->cond);
+ g_mutex_unlock (priv->mutex);
+
+ g_thread_exit (NULL);
+
+ return NULL;
+}
+
+static BraseroBurnResult
+brasero_local_track_start_thread (BraseroLocalTrack *self,
+ GError **error)
+{
+ BraseroLocalTrackPrivate *priv;
+ GError *thread_error = NULL;
+
+ priv = BRASERO_LOCAL_TRACK_PRIVATE (self);
+
+ if (priv->thread)
+ return BRASERO_BURN_RUNNING;
+
+ priv->cancel = g_cancellable_new ();
+ priv->xfer_ctx = brasero_xfer_new ();
+
+ g_mutex_lock (priv->mutex);
+ priv->thread = g_thread_create (brasero_local_track_thread,
+ self,
+ TRUE,
+ &thread_error);
+ g_mutex_unlock (priv->mutex);
+
+ /* Reminder: this is not necessarily an error as the thread may have finished */
+ //if (!priv->thread)
+ // return BRASERO_BURN_ERR;
+ if (thread_error) {
+ g_propagate_error (error, thread_error);
+ return BRASERO_BURN_ERR;
+ }
+
+ return BRASERO_BURN_OK;
+}
+
+static gboolean
+_foreach_non_local_cb (const gchar *uri,
+ const gchar *localuri,
+ gpointer *data)
+{
+ BraseroLocalTrack *self = BRASERO_LOCAL_TRACK (data);
+ BraseroLocalTrackPrivate *priv;
+ GFile *file, *tmpfile;
+ gchar *parent;
+ gchar *tmp;
+
+ priv = BRASERO_LOCAL_TRACK_PRIVATE (data);
+
+ /* check that is hasn't any parent in the hash */
+ parent = g_path_get_dirname (uri);
+ while (parent [1] != '\0') {
+ gchar *uri_local;
+
+ uri_local = g_hash_table_lookup (priv->nonlocals, parent);
+ if (uri_local) {
+ BRASERO_JOB_LOG (self, "Parent for %s was found %s", uri, parent);
+ g_free (parent);
+ return TRUE;
+ }
+
+ tmp = parent;
+ parent = g_path_get_dirname (tmp);
+ g_free (tmp);
+ }
+ g_free (parent);
+
+ file = g_file_new_for_uri (uri);
+ priv->src_list = g_slist_append (priv->src_list, file);
+
+ tmpfile = g_file_new_for_uri (localuri);
+ priv->dest_list = g_slist_append (priv->dest_list, tmpfile);
+
+ BRASERO_JOB_LOG (self, "%s set to be downloaded to %s", uri, localuri);
+ return FALSE;
+}
+
+static BraseroBurnResult
+brasero_local_track_add_if_non_local (BraseroLocalTrack *self,
+ const gchar *uri,
+ GError **error)
+{
+ BraseroLocalTrackPrivate *priv;
+ BraseroBurnResult result;
+ gchar *localuri = NULL;
+
+ priv = BRASERO_LOCAL_TRACK_PRIVATE (self);
+
+ if (!uri
+ || uri [0] == '\0'
+ || uri [0] == '/'
+ || g_str_has_prefix (uri, "file://")
+ || g_str_has_prefix (uri, "burn://"))
+ return BRASERO_BURN_OK;
+
+ /* add it to the list or uris to download */
+ if (!priv->nonlocals)
+ priv->nonlocals = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ NULL,
+ g_free);
+
+ /* generate a unique name */
+ result = brasero_job_get_tmp_file (BRASERO_JOB (self),
+ NULL,
+ &localuri,
+ error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+
+ if (!g_str_has_prefix (localuri, "file://")) {
+ gchar *tmp;
+
+ tmp = localuri;
+ localuri = g_strconcat ("file://", tmp, NULL);
+ g_free (tmp);
+ }
+
+ /* we don't want to replace it if it has already been downloaded */
+ if (!g_hash_table_lookup (priv->nonlocals, uri))
+ g_hash_table_insert (priv->nonlocals, g_strdup (uri), localuri);
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_local_track_start (BraseroJob *job,
+ GError **error)
+{
+ BraseroLocalTrackPrivate *priv;
+ BraseroBurnResult result;
+ BraseroJobAction action;
+ BraseroLocalTrack *self;
+ BraseroTrack *track;
+ GSList *grafts;
+ gchar *uri;
+
+ self = BRASERO_LOCAL_TRACK (job);
+ priv = BRASERO_LOCAL_TRACK_PRIVATE (self);
+
+ /* skip that part */
+ brasero_job_get_action (job, &action);
+ if (action == BRASERO_JOB_ACTION_SIZE) {
+ /* say we won't write to disc */
+ brasero_job_set_output_size_for_current_track (job, 0, 0);
+ return BRASERO_BURN_NOT_RUNNING;
+ }
+
+ if (action != BRASERO_JOB_ACTION_IMAGE)
+ return BRASERO_BURN_NOT_SUPPORTED;
+
+ /* can't be piped so brasero_job_get_current_track will work */
+ brasero_job_get_current_track (job, &track);
+
+ result = BRASERO_BURN_OK;
+
+ /* make a list of all non local uris to be downloaded and put them in a
+ * list to avoid to download the same file twice. */
+ if (BRASERO_IS_TRACK_DATA (track)) {
+ /* we put all the non local graft point uris in the hash */
+ grafts = brasero_track_data_get_grafts (BRASERO_TRACK_DATA (track));
+ for (; grafts; grafts = grafts->next) {
+ BraseroGraftPt *graft;
+
+ graft = grafts->data;
+ result = brasero_local_track_add_if_non_local (self, graft->uri, error);
+ if (result != BRASERO_BURN_OK)
+ break;
+ }
+ }
+ else if (BRASERO_IS_TRACK_STREAM (track)) {
+ /* NOTE: don't delete URI as they will be inserted in hash */
+ uri = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (track), TRUE);
+ result = brasero_local_track_add_if_non_local (self, uri, error);
+ g_free (uri);
+ }
+ else if (BRASERO_IS_TRACK_IMAGE (track)) {
+ /* NOTE: don't delete URI as they will be inserted in hash */
+ uri = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (track), TRUE);
+ result = brasero_local_track_add_if_non_local (self, uri, error);
+ g_free (uri);
+
+ if (result == BRASERO_BURN_OK) {
+ priv->download_checksum = TRUE;
+
+ uri = brasero_track_image_get_toc_source (BRASERO_TRACK_IMAGE (track), TRUE);
+ result = brasero_local_track_add_if_non_local (self, uri, error);
+ g_free (uri);
+ }
+ }
+ else
+ BRASERO_JOB_NOT_SUPPORTED (self);
+
+ if (result != BRASERO_BURN_OK)
+ return result;
+
+ /* see if there is anything to download */
+ if (!priv->nonlocals) {
+ BRASERO_JOB_LOG (self, "no remote URIs");
+ return BRASERO_BURN_NOT_RUNNING;
+ }
+
+ /* first we create a list of all the non local files that need to be
+ * downloaded. To be elligible a file must not have one of his parent
+ * in the hash. */
+ g_hash_table_foreach_remove (priv->nonlocals,
+ (GHRFunc) _foreach_non_local_cb,
+ job);
+
+ return brasero_local_track_start_thread (self, error);
+}
+
+static BraseroBurnResult
+brasero_local_track_stop (BraseroJob *job,
+ GError **error)
+{
+ BraseroLocalTrackPrivate *priv = BRASERO_LOCAL_TRACK_PRIVATE (job);
+
+ if (priv->cancel) {
+ /* signal that we've been cancelled */
+ g_cancellable_cancel (priv->cancel);
+ }
+
+ g_mutex_lock (priv->mutex);
+ if (priv->thread)
+ g_cond_wait (priv->cond, priv->mutex);
+ g_mutex_unlock (priv->mutex);
+
+ if (priv->xfer_ctx) {
+ brasero_xfer_free (priv->xfer_ctx);
+ priv->xfer_ctx = NULL;
+ }
+
+ if (priv->cancel) {
+ /* unref it after the thread has stopped */
+ g_object_unref (priv->cancel);
+ priv->cancel = NULL;
+ }
+
+ if (priv->thread_id) {
+ g_source_remove (priv->thread_id);
+ priv->thread_id = 0;
+ }
+
+ if (priv->error) {
+ g_error_free (priv->error);
+ priv->error = NULL;
+ }
+
+ if (priv->src_list) {
+ g_slist_foreach (priv->src_list, (GFunc) g_object_unref, NULL);
+ g_slist_free (priv->src_list);
+ priv->src_list = NULL;
+ }
+
+ if (priv->dest_list) {
+ g_slist_foreach (priv->dest_list, (GFunc) g_object_unref, NULL);
+ g_slist_free (priv->dest_list);
+ priv->dest_list = NULL;
+ }
+
+ if (priv->nonlocals) {
+ g_hash_table_destroy (priv->nonlocals);
+ priv->nonlocals = NULL;
+ }
+
+ if (priv->checksum_path) {
+ g_free (priv->checksum_path);
+ priv->checksum_path = NULL;
+ }
+
+ if (priv->checksum) {
+ g_free (priv->checksum);
+ priv->checksum = NULL;
+ }
+
+ return BRASERO_BURN_OK;
+}
+
+static void
+brasero_local_track_finalize (GObject *object)
+{
+ BraseroLocalTrackPrivate *priv = BRASERO_LOCAL_TRACK_PRIVATE (object);
+
+ if (priv->mutex) {
+ g_mutex_free (priv->mutex);
+ priv->mutex = NULL;
+ }
+
+ if (priv->cond) {
+ g_cond_free (priv->cond);
+ priv->cond = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+brasero_local_track_class_init (BraseroLocalTrackClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ BraseroJobClass *job_class = BRASERO_JOB_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (BraseroLocalTrackPrivate));
+
+ parent_class = g_type_class_peek_parent (klass);
+ object_class->finalize = brasero_local_track_finalize;
+
+ job_class->start = brasero_local_track_start;
+ job_class->stop = brasero_local_track_stop;
+ job_class->clock_tick = brasero_local_track_clock_tick;
+}
+
+static void
+brasero_local_track_init (BraseroLocalTrack *obj)
+{
+ BraseroLocalTrackPrivate *priv = BRASERO_LOCAL_TRACK_PRIVATE (obj);
+
+ priv->mutex = g_mutex_new ();
+ priv->cond = g_cond_new ();
+}
+
+static BraseroBurnResult
+brasero_local_track_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+ GSList *caps;
+
+ brasero_plugin_define (plugin,
+ /* Translators: this is the name of the plugin
+ * which will be translated only when it needs
+ * displaying. */
+ N_("File Downloader"),
+ _("Allows to burn files not stored locally"),
+ "Philippe Rouquier",
+ 10);
+
+ caps = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_IMAGE_FORMAT_ANY);
+ brasero_plugin_process_caps (plugin, caps);
+ g_slist_free (caps);
+
+ caps = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_AUDIO_FORMAT_UNDEFINED|
+ BRASERO_AUDIO_FORMAT_4_CHANNEL|
+ BRASERO_AUDIO_FORMAT_RAW|
+ BRASERO_VIDEO_FORMAT_UNDEFINED|
+ BRASERO_VIDEO_FORMAT_VCD|
+ BRASERO_VIDEO_FORMAT_VIDEO_DVD|
+ BRASERO_AUDIO_FORMAT_AC3|
+ BRASERO_AUDIO_FORMAT_MP2|
+ BRASERO_AUDIO_FORMAT_44100|
+ BRASERO_AUDIO_FORMAT_48000|
+ BRASERO_METADATA_INFO);
+ brasero_plugin_process_caps (plugin, caps);
+ g_slist_free (caps);
+
+ caps = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_AUDIO_FORMAT_UNDEFINED|
+ BRASERO_AUDIO_FORMAT_4_CHANNEL|
+ BRASERO_AUDIO_FORMAT_RAW|
+ BRASERO_VIDEO_FORMAT_UNDEFINED|
+ BRASERO_VIDEO_FORMAT_VCD|
+ BRASERO_VIDEO_FORMAT_VIDEO_DVD|
+ BRASERO_AUDIO_FORMAT_AC3|
+ BRASERO_AUDIO_FORMAT_MP2|
+ BRASERO_AUDIO_FORMAT_44100|
+ BRASERO_AUDIO_FORMAT_48000);
+ brasero_plugin_process_caps (plugin, caps);
+ g_slist_free (caps);
+ caps = brasero_caps_data_new (BRASERO_IMAGE_FS_ANY);
+ brasero_plugin_process_caps (plugin, caps);
+ g_slist_free (caps);
+
+ brasero_plugin_set_process_flags (plugin, BRASERO_PLUGIN_RUN_PREPROCESSING);
+
+ brasero_plugin_set_compulsory (plugin, FALSE);
+
+ return BRASERO_BURN_OK;
+}
diff --git a/plugins/local-track/burn-local-image.h b/plugins/local-track/burn-local-image.h
new file mode 100644
index 0000000..697dea2
--- /dev/null
+++ b/plugins/local-track/burn-local-image.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ * burn-local-track.h
+ *
+ * dim jui 9 10:54:14 2006
+ * Copyright 2006 Rouquier Philippe
+ * brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef BURN_LOCAL_TRACK_H
+#define BURN_LOCAL_TRACK_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_LOCAL_TRACK (brasero_local_track_get_type ())
+#define BRASERO_LOCAL_TRACK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_LOCAL_TRACK, BraseroLocalTrack))
+#define BRASERO_LOCAL_TRACK_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_LOCAL_TRACK, BraseroLocalTrackClass))
+#define BRASERO_IS_LOCAL_TRACK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_LOCAL_TRACK))
+#define BRASERO_IS_LOCAL_TRACK_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_LOCAL_TRACK))
+#define BRASERO_LOCAL_TRACK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_LOCAL_TRACK, BraseroLocalTrackClass))
+
+G_END_DECLS
+
+#endif /* BURN_LOCAL_TRACK_H */
diff --git a/plugins/local-track/burn-uri.c b/plugins/local-track/burn-uri.c
new file mode 100644
index 0000000..e420548
--- /dev/null
+++ b/plugins/local-track/burn-uri.c
@@ -0,0 +1,746 @@
+/***************************************************************************
+ * burn-local-image.c
+ *
+ * dim jui 9 10:54:14 2006
+ * Copyright 2006 Rouquier Philippe
+ * brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+
+#include <gio/gio.h>
+
+#include <gmodule.h>
+
+#include "brasero-units.h"
+#include "burn-job.h"
+#include "brasero-plugin-registration.h"
+#include "burn-uri.h"
+
+#include "brasero-track.h"
+#include "brasero-track-data.h"
+#include "brasero-track-image.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroBurnURI, brasero_burn_uri, BRASERO_TYPE_JOB, BraseroJob);
+
+struct _BraseroBurnURIPrivate {
+ GCancellable *cancel;
+
+ BraseroTrack *track;
+
+ guint thread_id;
+ GThread *thread;
+ GMutex *mutex;
+ GCond *cond;
+
+ GError *error;
+};
+typedef struct _BraseroBurnURIPrivate BraseroBurnURIPrivate;
+
+#define BRASERO_BURN_URI_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_BURN_URI, BraseroBurnURIPrivate))
+
+static GObjectClass *parent_class = NULL;
+
+
+static gboolean
+brasero_burn_uri_thread_finished (BraseroBurnURI *self)
+{
+ BraseroBurnURIPrivate *priv;
+
+ priv = BRASERO_BURN_URI_PRIVATE (self);
+
+ priv->thread_id = 0;
+
+ if (priv->cancel) {
+ g_object_unref (priv->cancel);
+ priv->cancel = NULL;
+ if (g_cancellable_is_cancelled (priv->cancel))
+ return FALSE;
+ }
+
+ if (priv->error) {
+ GError *error;
+
+ error = priv->error;
+ priv->error = NULL;
+ brasero_job_error (BRASERO_JOB (self), error);
+ return FALSE;
+ }
+
+ brasero_job_add_track (BRASERO_JOB (self), priv->track);
+ brasero_job_finished_track (BRASERO_JOB (self));
+
+ return FALSE;
+}
+
+static gint
+brasero_burn_uri_find_graft (gconstpointer A, gconstpointer B)
+{
+ const BraseroGraftPt *graft = A;
+
+ if (graft && graft->path)
+ return strcmp (graft->path, B);
+
+ return 1;
+}
+
+static GSList *
+brasero_burn_uri_explore_directory (BraseroBurnURI *self,
+ GSList *grafts,
+ GFile *file,
+ const gchar *path,
+ GCancellable *cancel,
+ GError **error)
+{
+ BraseroTrack *current = NULL;
+ GFileEnumerator *enumerator;
+ GSList *current_grafts;
+ GFileInfo *info;
+
+ enumerator = g_file_enumerate_children (file,
+ G_FILE_ATTRIBUTE_STANDARD_NAME ","
+ G_FILE_ATTRIBUTE_STANDARD_TYPE ","
+ "burn::backing-file",
+ G_FILE_QUERY_INFO_NONE,
+ cancel,
+ error);
+
+ if (!enumerator) {
+ g_slist_foreach (grafts, (GFunc) brasero_graft_point_free, NULL);
+ g_slist_free (grafts);
+ return NULL;
+ }
+
+ brasero_job_get_current_track (BRASERO_JOB (self), ¤t);
+ current_grafts = brasero_track_data_get_grafts (BRASERO_TRACK_DATA (current));
+
+ while ((info = g_file_enumerator_next_file (enumerator, cancel, error))) {
+ if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) {
+ gchar *disc_path;
+ GFile *directory;
+ BraseroGraftPt *graft;
+
+ /* Make sure it's not one of the original grafts */
+ /* we need to know if that's a directory or not since if
+ * it is then mkisofs (but not genisoimage) requires the
+ * disc path to end with '/'; if there isn't '/' at the
+ * end then only the directory contents are added. */
+ disc_path = g_build_filename (path, g_file_info_get_name (info), G_DIR_SEPARATOR_S, NULL);
+ if (g_slist_find_custom (current_grafts, disc_path, (GCompareFunc) brasero_burn_uri_find_graft)) {
+ BRASERO_JOB_LOG (self, "Graft already in list %s", disc_path);
+ g_object_unref (info);
+ g_free (disc_path);
+ continue;
+ }
+
+ /* we need a dummy directory */
+ graft = g_new0 (BraseroGraftPt, 1);
+ graft->uri = NULL;
+ graft->path = disc_path;
+ grafts = g_slist_prepend (grafts, graft);
+
+ BRASERO_JOB_LOG (self, "Adding directory %s at %s", graft->uri, graft->path);
+
+ directory = g_file_get_child (file, g_file_info_get_name (info));
+ grafts = brasero_burn_uri_explore_directory (self,
+ grafts,
+ directory,
+ graft->path,
+ cancel,
+ error);
+ g_object_unref (directory);
+
+ if (!grafts) {
+ g_object_unref (info);
+ g_object_unref (enumerator);
+ return NULL;
+ }
+ }
+ else if (g_file_info_get_file_type (info) == G_FILE_TYPE_REGULAR
+ /* NOTE: burn:// URI allows symlink */
+ || g_file_info_get_file_type (info) == G_FILE_TYPE_SYMBOLIC_LINK) {
+ const gchar *real_path;
+ BraseroGraftPt *graft;
+ gchar *disc_path;
+
+ real_path = g_file_info_get_attribute_byte_string (info, "burn::backing-file");
+ if (!real_path) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("Impossible to retrieve local file path"));
+
+ g_slist_foreach (grafts, (GFunc) brasero_graft_point_free, NULL);
+ g_slist_free (grafts);
+ g_object_unref (info);
+ g_object_unref (file);
+ return NULL;
+ }
+
+ /* Make sure it's not one of the original grafts */
+ disc_path = g_build_filename (path, g_file_info_get_name (info), NULL);
+ if (g_slist_find_custom (current_grafts, disc_path, (GCompareFunc) brasero_burn_uri_find_graft)) {
+ BRASERO_JOB_LOG (self, "Graft already in list %s", disc_path);
+ g_object_unref (info);
+ g_free (disc_path);
+ continue;
+ }
+
+ graft = g_new0 (BraseroGraftPt, 1);
+ graft->path = disc_path;
+ graft->uri = g_strdup (real_path);
+ /* FIXME: maybe one day, graft->uri will always be an URI */
+ /* graft->uri = g_filename_to_uri (real_path, NULL, NULL); */
+
+ /* Make sure it's not one of the original grafts */
+
+ grafts = g_slist_prepend (grafts, graft);
+
+ BRASERO_JOB_LOG (self, "Added file %s at %s", graft->uri, graft->path);
+ }
+
+ g_object_unref (info);
+ }
+ g_object_unref (enumerator);
+
+ return grafts;
+}
+
+static gboolean
+brasero_burn_uri_retrieve_path (BraseroBurnURI *self,
+ const gchar *uri,
+ gchar **path)
+{
+ GFile *file;
+ GFileInfo *info;
+ BraseroBurnURIPrivate *priv;
+
+ priv = BRASERO_BURN_URI_PRIVATE (self);
+
+ file = g_file_new_for_uri (uri);
+ info = g_file_query_info (file,
+ G_FILE_ATTRIBUTE_STANDARD_NAME ","
+ G_FILE_ATTRIBUTE_STANDARD_TYPE ","
+ "burn::backing-file",
+ G_FILE_QUERY_INFO_NONE,
+ priv->cancel,
+ &priv->error);
+
+ if (priv->error) {
+ g_object_unref (file);
+ return FALSE;
+ }
+
+ if (g_cancellable_is_cancelled (priv->cancel)) {
+ g_object_unref (file);
+ return FALSE;
+ }
+
+ if (!info) {
+ /* Error */
+ g_object_unref (file);
+ g_object_unref (info);
+ return FALSE;
+ }
+
+ if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) {
+ *path = NULL;
+ }
+ else if (g_file_info_get_file_type (info) == G_FILE_TYPE_REGULAR
+ /* NOTE: burn:// URI allows symlink */
+ || g_file_info_get_file_type (info) == G_FILE_TYPE_SYMBOLIC_LINK) {
+ const gchar *real_path;
+
+ real_path = g_file_info_get_attribute_byte_string (info, "burn::backing-file");
+ if (!real_path) {
+ priv->error = g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("Impossible to retrieve local file path"));
+ g_object_unref (info);
+ g_object_unref (file);
+ return FALSE;
+ }
+
+ *path = g_strdup (real_path);
+ }
+
+ g_object_unref (file);
+ g_object_unref (info);
+ return TRUE;
+}
+
+static gpointer
+brasero_burn_uri_thread (gpointer data)
+{
+ BraseroBurnURI *self = BRASERO_BURN_URI (data);
+ BraseroTrack *current = NULL;
+ BraseroBurnURIPrivate *priv;
+ BraseroTrackData *track;
+ GSList *excluded = NULL;
+ GSList *grafts = NULL;
+ guint64 num = 0;
+ GSList *src;
+
+ priv = BRASERO_BURN_URI_PRIVATE (self);
+ brasero_job_set_current_action (BRASERO_JOB (self),
+ BRASERO_BURN_ACTION_FILE_COPY,
+ _("Copying files locally"),
+ TRUE);
+
+ brasero_job_get_current_track (BRASERO_JOB (self), ¤t);
+
+ /* This is for IMAGE tracks */
+ if (BRASERO_IS_TRACK_IMAGE (current)) {
+ gchar *uri;
+ gchar *path_toc;
+ gchar *path_image;
+ guint64 blocks = 0;
+ BraseroTrackImage *image;
+
+ path_image = NULL;
+ uri = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (current), TRUE);
+ if (!brasero_burn_uri_retrieve_path (self, uri, &path_image)) {
+ g_free (uri);
+ goto end;
+ }
+ g_free (uri);
+
+ path_toc = NULL;
+ uri = brasero_track_image_get_toc_source (BRASERO_TRACK_IMAGE (current), TRUE);
+ if (!brasero_burn_uri_retrieve_path (self, uri, &path_toc)) {
+ g_free (path_image);
+ g_free (uri);
+ goto end;
+ }
+ g_free (uri);
+
+ brasero_track_get_size (current, &blocks, NULL);
+
+ image = brasero_track_image_new ();
+ brasero_track_tag_copy_missing (BRASERO_TRACK (image), current);
+ brasero_track_image_set_source (image,
+ path_image,
+ path_toc,
+ brasero_track_image_get_format (BRASERO_TRACK_IMAGE (current)));
+ brasero_track_image_set_block_num (image, blocks);
+
+ priv->track = BRASERO_TRACK (image);
+
+ g_free (path_toc);
+ g_free (path_image);
+ goto end;
+ }
+
+ /* This is for DATA tracks */
+ for (src = brasero_track_data_get_grafts (BRASERO_TRACK_DATA (current)); src; src = src->next) {
+ GFile *file;
+ GFileInfo *info;
+ BraseroGraftPt *graft;
+
+ graft = src->data;
+
+ if (!graft->uri) {
+ grafts = g_slist_prepend (grafts, brasero_graft_point_copy (graft));
+ continue;
+ }
+
+ if (!g_str_has_prefix (graft->uri, "burn://")) {
+ grafts = g_slist_prepend (grafts, brasero_graft_point_copy (graft));
+ continue;
+ }
+
+ BRASERO_JOB_LOG (self, "Information retrieval for %s", graft->uri);
+
+ file = g_file_new_for_uri (graft->uri);
+ info = g_file_query_info (file,
+ G_FILE_ATTRIBUTE_STANDARD_NAME ","
+ G_FILE_ATTRIBUTE_STANDARD_TYPE ","
+ "burn::backing-file",
+ G_FILE_QUERY_INFO_NONE,
+ priv->cancel,
+ &priv->error);
+
+ if (priv->error) {
+ g_object_unref (file);
+ goto end;
+ }
+
+ if (g_cancellable_is_cancelled (priv->cancel)) {
+ g_object_unref (file);
+ goto end;
+ }
+
+ if (!info) {
+ /* Error */
+ g_object_unref (file);
+ g_object_unref (info);
+ goto end;
+ }
+
+ /* See if we were passed the burn:/// uri itself (the root).
+ * Then skip graft point addition */
+ if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) {
+ if (g_file_info_get_name (info)
+ && strcmp (g_file_info_get_name (info), "/")) {
+ BraseroGraftPt *newgraft;
+
+ /* we need a dummy directory */
+ newgraft = g_new0 (BraseroGraftPt, 1);
+ newgraft->uri = NULL;
+ newgraft->path = g_strdup (graft->path);
+ grafts = g_slist_prepend (grafts, newgraft);
+
+ BRASERO_JOB_LOG (self,
+ "Adding directory %s at %s",
+ newgraft->uri,
+ newgraft->path);
+ grafts = brasero_burn_uri_explore_directory (self,
+ grafts,
+ file,
+ newgraft->path,
+ priv->cancel,
+ &priv->error);
+ }
+ else {
+ BRASERO_JOB_LOG (self, "Directory is root");
+ grafts = brasero_burn_uri_explore_directory (self,
+ grafts,
+ file,
+ "/",
+ priv->cancel,
+ &priv->error);
+ }
+
+ if (!grafts) {
+ g_object_unref (info);
+ g_object_unref (file);
+ goto end;
+ }
+ }
+ else if (g_file_info_get_file_type (info) == G_FILE_TYPE_REGULAR
+ /* NOTE: burn:// URI allows symlink */
+ || g_file_info_get_file_type (info) == G_FILE_TYPE_SYMBOLIC_LINK) {
+ const gchar *real_path;
+ BraseroGraftPt *newgraft;
+
+ real_path = g_file_info_get_attribute_byte_string (info, "burn::backing-file");
+ if (!real_path) {
+ priv->error = g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("Impossible to retrieve local file path"));
+
+ g_slist_foreach (grafts, (GFunc) brasero_graft_point_free, NULL);
+ g_slist_free (grafts);
+ g_object_unref (info);
+ g_object_unref (file);
+ goto end;
+ }
+
+ newgraft = brasero_graft_point_copy (graft);
+ g_free (newgraft->uri);
+
+ newgraft->uri = g_strdup (real_path);
+ /* FIXME: maybe one day, graft->uri will always be an URI */
+ /* newgraft->uri = g_filename_to_uri (real_path, NULL, NULL); */
+
+ BRASERO_JOB_LOG (self,
+ "Added file %s at %s",
+ newgraft->uri,
+ newgraft->path);
+ grafts = g_slist_prepend (grafts, newgraft);
+ }
+
+ g_object_unref (info);
+ g_object_unref (file);
+ }
+ grafts = g_slist_reverse (grafts);
+
+ /* remove all excluded starting by burn:// from the list */
+ for (src = brasero_track_data_get_excluded (BRASERO_TRACK_DATA (current), FALSE); src; src = src->next) {
+ gchar *uri;
+
+ uri = src->data;
+
+ if (uri && g_str_has_prefix (uri, "burn://"))
+ continue;
+
+ uri = g_strdup (uri);
+ excluded = g_slist_prepend (excluded, uri);
+
+ BRASERO_JOB_LOG (self, "Added excluded file %s", uri);
+ }
+ excluded = g_slist_reverse (excluded);
+
+ track = brasero_track_data_new ();
+ brasero_track_tag_copy_missing (BRASERO_TRACK (track), current);
+
+ brasero_track_data_add_fs (track, brasero_track_data_get_fs (BRASERO_TRACK_DATA (current)));
+
+ brasero_track_data_get_file_num (BRASERO_TRACK_DATA (current), &num);
+ brasero_track_data_set_file_num (track, num);
+
+ brasero_track_data_set_source (track,
+ grafts,
+ excluded);
+ priv->track = BRASERO_TRACK (track);
+
+end:
+
+ if (!g_cancellable_is_cancelled (priv->cancel))
+ priv->thread_id = g_idle_add ((GSourceFunc) brasero_burn_uri_thread_finished, self);
+
+ /* End thread */
+ g_mutex_lock (priv->mutex);
+ g_atomic_pointer_set (&priv->thread, NULL);
+ g_cond_signal (priv->cond);
+ g_mutex_unlock (priv->mutex);
+
+ g_thread_exit (NULL);
+
+ return NULL;
+}
+
+static BraseroBurnResult
+brasero_burn_uri_start_thread (BraseroBurnURI *self,
+ GError **error)
+{
+ BraseroBurnURIPrivate *priv;
+ GError *thread_error = NULL;
+
+ priv = BRASERO_BURN_URI_PRIVATE (self);
+
+ if (priv->thread)
+ return BRASERO_BURN_RUNNING;
+
+ priv->cancel = g_cancellable_new ();
+
+ g_mutex_lock (priv->mutex);
+ priv->thread = g_thread_create (brasero_burn_uri_thread,
+ self,
+ TRUE,
+ &thread_error);
+ g_mutex_unlock (priv->mutex);
+
+ /* Reminder: this is not necessarily an error as the thread may have finished */
+ //if (!priv->thread)
+ // return BRASERO_BURN_ERR;
+ if (thread_error) {
+ g_propagate_error (error, thread_error);
+ return BRASERO_BURN_ERR;
+ }
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_burn_uri_start_if_found (BraseroBurnURI *self,
+ const gchar *uri,
+ GError **error)
+{
+ if (!uri)
+ return BRASERO_BURN_NOT_RUNNING;
+
+ /* Find any graft point with burn:// URI */
+ if (!g_str_has_prefix (uri, "burn://"))
+ return BRASERO_BURN_NOT_RUNNING;
+
+ BRASERO_JOB_LOG (self, "burn:// URI found %s", uri);
+ brasero_burn_uri_start_thread (self, error);
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_burn_uri_start (BraseroJob *job,
+ GError **error)
+{
+ BraseroBurnURIPrivate *priv;
+ BraseroBurnResult result;
+ BraseroJobAction action;
+ BraseroBurnURI *self;
+ BraseroTrack *track;
+ GSList *grafts;
+ gchar *uri;
+
+ self = BRASERO_BURN_URI (job);
+ priv = BRASERO_BURN_URI_PRIVATE (self);
+
+ /* skip that part */
+ brasero_job_get_action (job, &action);
+ if (action == BRASERO_JOB_ACTION_SIZE) {
+ /* say we won't write to disc */
+ brasero_job_set_output_size_for_current_track (job, 0, 0);
+ return BRASERO_BURN_NOT_RUNNING;
+ }
+
+ if (action != BRASERO_JOB_ACTION_IMAGE)
+ return BRASERO_BURN_NOT_SUPPORTED;
+
+ /* can't be piped so brasero_job_get_current_track will work */
+ brasero_job_get_current_track (job, &track);
+
+ result = BRASERO_BURN_NOT_RUNNING;
+
+ /* make a list of all non local uris to be downloaded and put them in a
+ * list to avoid to download the same file twice. */
+ if (BRASERO_IS_TRACK_DATA (track)) {
+ /* we put all the non local graft point uris in the hash */
+ grafts = brasero_track_data_get_grafts (BRASERO_TRACK_DATA (track));
+ for (; grafts; grafts = grafts->next) {
+ BraseroGraftPt *graft;
+
+ graft = grafts->data;
+ result = brasero_burn_uri_start_if_found (self, graft->uri, error);
+ if (result != BRASERO_BURN_NOT_RUNNING)
+ break;
+ }
+ }
+ else if (BRASERO_IS_TRACK_IMAGE (track)) {
+ /* NOTE: don't delete URI as they will be inserted in hash */
+ uri = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (track), TRUE);
+ result = brasero_burn_uri_start_if_found (self, uri, error);
+ g_free (uri);
+
+ if (result == BRASERO_BURN_NOT_RUNNING) {
+ uri = brasero_track_image_get_toc_source (BRASERO_TRACK_IMAGE (track), TRUE);
+ result = brasero_burn_uri_start_if_found (self, uri, error);
+ g_free (uri);
+ }
+ }
+ else
+ BRASERO_JOB_NOT_SUPPORTED (self);
+
+ if (!priv->thread)
+ BRASERO_JOB_LOG (self, "no burn:// URI found");
+
+ return result;
+}
+
+static BraseroBurnResult
+brasero_burn_uri_stop (BraseroJob *job,
+ GError **error)
+{
+ BraseroBurnURIPrivate *priv = BRASERO_BURN_URI_PRIVATE (job);
+
+ if (priv->cancel) {
+ /* signal that we've been cancelled */
+ g_cancellable_cancel (priv->cancel);
+ }
+
+ g_mutex_lock (priv->mutex);
+ if (priv->thread)
+ g_cond_wait (priv->cond, priv->mutex);
+ g_mutex_unlock (priv->mutex);
+
+ if (priv->cancel) {
+ /* unref it after the thread has stopped */
+ g_object_unref (priv->cancel);
+ priv->cancel = NULL;
+ }
+
+ if (priv->thread_id) {
+ g_source_remove (priv->thread_id);
+ priv->thread_id = 0;
+ }
+
+ if (priv->error) {
+ g_error_free (priv->error);
+ priv->error = NULL;
+ }
+
+ return BRASERO_BURN_OK;
+}
+
+static void
+brasero_burn_uri_finalize (GObject *object)
+{
+ BraseroBurnURIPrivate *priv = BRASERO_BURN_URI_PRIVATE (object);
+
+ if (priv->mutex) {
+ g_mutex_free (priv->mutex);
+ priv->mutex = NULL;
+ }
+
+ if (priv->cond) {
+ g_cond_free (priv->cond);
+ priv->cond = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+brasero_burn_uri_class_init (BraseroBurnURIClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ BraseroJobClass *job_class = BRASERO_JOB_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (BraseroBurnURIPrivate));
+
+ parent_class = g_type_class_peek_parent (klass);
+ object_class->finalize = brasero_burn_uri_finalize;
+
+ job_class->start = brasero_burn_uri_start;
+ job_class->stop = brasero_burn_uri_stop;
+}
+
+static void
+brasero_burn_uri_init (BraseroBurnURI *obj)
+{
+ BraseroBurnURIPrivate *priv = BRASERO_BURN_URI_PRIVATE (obj);
+
+ priv->mutex = g_mutex_new ();
+ priv->cond = g_cond_new ();
+}
+
+static BraseroBurnResult
+brasero_burn_uri_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+ GSList *caps;
+
+ brasero_plugin_define (plugin,
+ /* Translators: this is the name of the plugin
+ * which will be translated only when it needs
+ * displaying. */
+ N_("CD/DVD Creator Folder"),
+ _("Allows to burn files added to \"CD/DVD Creator Folder\" in Nautilus"),
+ "Philippe Rouquier",
+ 11);
+
+ caps = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_IMAGE_FORMAT_ANY);
+ brasero_plugin_process_caps (plugin, caps);
+ g_slist_free (caps);
+
+ caps = brasero_caps_data_new (BRASERO_IMAGE_FS_ANY);
+ brasero_plugin_process_caps (plugin, caps);
+ g_slist_free (caps);
+
+ brasero_plugin_set_process_flags (plugin, BRASERO_PLUGIN_RUN_PREPROCESSING);
+
+ return BRASERO_BURN_OK;
+}
diff --git a/plugins/local-track/burn-uri.h b/plugins/local-track/burn-uri.h
new file mode 100644
index 0000000..199cb4a
--- /dev/null
+++ b/plugins/local-track/burn-uri.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ * burn-local-track.h
+ *
+ * dim jui 9 10:54:14 2006
+ * Copyright 2006 Rouquier Philippe
+ * brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _BURN_URI_H_
+#define _BURN_URI_H_
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_BURN_URI (brasero_burn_uri_get_type ())
+#define BRASERO_BURN_URI(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_BURN_URI, BraseroBurnURI))
+#define BRASERO_BURN_URI_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_BURN_URI, BraseroBurnURIClass))
+#define BRASERO_IS_BURN_URI(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_BURN_URI))
+#define BRASERO_IS_BURN_URI_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_BURN_URI))
+#define BRASERO_BURN_URI_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_BURN_URI, BraseroBurnURIClass))
+
+G_END_DECLS
+
+#endif /* _BURN_URI_H */
diff --git a/plugins/transcode/Makefile.am b/plugins/transcode/Makefile.am
new file mode 100644
index 0000000..e2ff2c7
--- /dev/null
+++ b/plugins/transcode/Makefile.am
@@ -0,0 +1,36 @@
+
+INCLUDES = \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/libbrasero-media/ \
+ -I$(top_builddir)/libbrasero-media/ \
+ -I$(top_srcdir)/libbrasero-burn \
+ -I$(top_builddir)/libbrasero-burn/ \
+ -DBRASERO_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
+ -DBRASERO_PREFIX=\"$(prefix)\" \
+ -DBRASERO_SYSCONFDIR=\"$(sysconfdir)\" \
+ -DBRASERO_DATADIR=\"$(datadir)/brasero\" \
+ -DBRASERO_LIBDIR=\"$(libdir)\" \
+ $(DISABLE_DEPRECATED) \
+ $(BRASERO_GLIB_CFLAGS) \
+ $(BRASERO_GSTREAMER_CFLAGS)
+
+transcodedir = $(libdir)/brasero/plugins
+transcode_LTLIBRARIES = libbrasero-transcode.la
+
+libbrasero_transcode_la_SOURCES = burn-transcode.c burn-transcode.h burn-normalize.h
+libbrasero_transcode_la_LIBADD = $(BRASERO_GLIB_LIBS) $(BRASERO_GSTREAMER_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_transcode_la_LDFLAGS = -module -avoid-version
+
+normalizedir = $(libdir)/brasero/plugins
+normalize_LTLIBRARIES = libbrasero-normalize.la
+
+libbrasero_normalize_la_SOURCES = burn-normalize.c burn-normalize.h
+libbrasero_normalize_la_LIBADD = $(BRASERO_GLIB_LIBS) $(BRASERO_GSTREAMER_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_normalize_la_LDFLAGS = -module -avoid-version
+
+vobdir = $(libdir)/brasero/plugins
+vob_LTLIBRARIES = libbrasero-vob.la
+
+libbrasero_vob_la_SOURCES = burn-vob.c burn-vob.h
+libbrasero_vob_la_LIBADD = $(BRASERO_GLIB_LIBS) $(BRASERO_GSTREAMER_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_vob_la_LDFLAGS = -module -avoid-version
diff --git a/plugins/transcode/burn-normalize.c b/plugins/transcode/burn-normalize.c
new file mode 100644
index 0000000..f510fe0
--- /dev/null
+++ b/plugins/transcode/burn-normalize.c
@@ -0,0 +1,628 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * brasero-normalize.c
+ * Copyright (C) Rouquier Philippe 2008 <bonfire-app wanadoo fr>
+ *
+ * brasero-normalize.c is free software.
+ *
+ * You may redistribute it and/or modify it under the terms of the
+ * GNU General Public License, as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * brasero-normalize.c is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with brasero-normalize.c. If not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+
+#include <gst/gst.h>
+
+#include "burn-job.h"
+#include "brasero-plugin-registration.h"
+#include "burn-normalize.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroNormalize, brasero_normalize, BRASERO_TYPE_JOB, BraseroJob);
+
+typedef struct _BraseroNormalizePrivate BraseroNormalizePrivate;
+struct _BraseroNormalizePrivate
+{
+ GstElement *pipeline;
+ GstElement *analysis;
+ GstElement *decode;
+ GstElement *resample;
+ GstElement *source;
+
+ GSList *tracks;
+ BraseroTrack *track;
+
+ gdouble album_peak;
+ gdouble album_gain;
+ gdouble track_peak;
+ gdouble track_gain;
+};
+
+#define BRASERO_NORMALIZE_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_NORMALIZE, BraseroNormalizePrivate))
+
+static GObjectClass *parent_class = NULL;
+
+
+static gboolean
+brasero_normalize_bus_messages (GstBus *bus,
+ GstMessage *msg,
+ BraseroNormalize *normalize);
+
+static gboolean
+brasero_normalize_set_next_track (BraseroJob *job,
+ BraseroTrack *track,
+ GError **error)
+{
+ gchar *uri;
+ GstBus *bus = NULL;
+ GstElement *source;
+ BraseroNormalizePrivate *priv;
+
+ priv = BRASERO_NORMALIZE_PRIVATE (job);
+
+ /* destroy previous source */
+ if (priv->source) {
+ gst_element_unlink (priv->source, priv->decode);
+ gst_bin_remove (GST_BIN (priv->pipeline), priv->source);
+ priv->source = NULL;
+ }
+
+ /* create a new one */
+ uri = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (track), TRUE);
+ source = gst_element_make_from_uri (GST_URI_SRC, uri, NULL);
+ if (source == NULL) {
+ g_free (uri);
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Source\"");
+ return FALSE;
+ }
+ gst_bin_add (GST_BIN (priv->pipeline), source);
+ g_object_set (source,
+ "typefind", FALSE,
+ NULL);
+
+ priv->source = source;
+ if (!gst_element_link_many (source, priv->decode, NULL)) {
+ BRASERO_JOB_LOG (job, "Elements could not be linked");
+ return FALSE;
+ }
+
+ /* reconnect to the bus */
+ bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline));
+ gst_bus_add_watch (bus,
+ (GstBusFunc) brasero_normalize_bus_messages,
+ job);
+ gst_object_unref (bus);
+
+ priv->track = track;
+
+ BRASERO_JOB_LOG (job, "Analysing track %s", uri);
+ g_free (uri);
+
+ return TRUE;
+}
+
+static void
+brasero_normalize_stop_pipeline (BraseroNormalize *normalize)
+{
+ BraseroNormalizePrivate *priv;
+
+ priv = BRASERO_NORMALIZE_PRIVATE (normalize);
+ if (!priv->pipeline)
+ return;
+
+ gst_element_set_state (priv->pipeline, GST_STATE_NULL);
+ gst_object_unref (GST_OBJECT (priv->pipeline));
+ priv->pipeline = NULL;
+ priv->resample = NULL;
+ priv->analysis = NULL;
+ priv->decode = NULL;
+ priv->source = NULL;
+}
+
+static BraseroBurnResult
+brasero_normalize_stop (BraseroJob *job,
+ GError **error)
+{
+ BraseroNormalizePrivate *priv;
+
+ priv = BRASERO_NORMALIZE_PRIVATE (job);
+
+ brasero_normalize_stop_pipeline (BRASERO_NORMALIZE (job));
+ if (priv->tracks) {
+ g_slist_free (priv->tracks);
+ priv->tracks = NULL;
+ }
+
+ priv->track = NULL;
+
+ return BRASERO_BURN_OK;
+}
+
+static void
+foreach_tag (const GstTagList *list,
+ const gchar *tag,
+ BraseroNormalize *normalize)
+{
+ gdouble value = 0.0;
+ BraseroNormalizePrivate *priv;
+
+ priv = BRASERO_NORMALIZE_PRIVATE (normalize);
+
+ /* Those next two are generated at the end only */
+ if (!strcmp (tag, GST_TAG_ALBUM_GAIN)) {
+ gst_tag_list_get_double (list, tag, &value);
+ priv->album_gain = value;
+ }
+ else if (!strcmp (tag, GST_TAG_ALBUM_PEAK)) {
+ gst_tag_list_get_double (list, tag, &value);
+ priv->album_peak = value;
+ }
+ else if (!strcmp (tag, GST_TAG_TRACK_PEAK)) {
+ gst_tag_list_get_double (list, tag, &value);
+ priv->track_peak = value;
+ }
+ else if (!strcmp (tag, GST_TAG_TRACK_GAIN)) {
+ gst_tag_list_get_double (list, tag, &value);
+ priv->track_gain = value;
+ }
+}
+
+static void
+brasero_normalize_song_end_reached (BraseroNormalize *normalize)
+{
+ GValue *value;
+ BraseroTrack *track;
+ GError *error = NULL;
+ BraseroNormalizePrivate *priv;
+
+ priv = BRASERO_NORMALIZE_PRIVATE (normalize);
+
+ /* finished track: set tags */
+ BRASERO_JOB_LOG (normalize,
+ "Setting track peak (%lf) and gain (%lf)",
+ priv->track_peak,
+ priv->track_gain);
+
+ value = g_new0 (GValue, 1);
+ g_value_init (value, G_TYPE_DOUBLE);
+ g_value_set_double (value, priv->track_peak);
+ brasero_track_tag_add (priv->track,
+ BRASERO_TRACK_PEAK_VALUE,
+ value);
+
+ value = g_new0 (GValue, 1);
+ g_value_init (value, G_TYPE_DOUBLE);
+ g_value_set_double (value, priv->track_gain);
+ brasero_track_tag_add (priv->track,
+ BRASERO_TRACK_GAIN_VALUE,
+ value);
+
+ priv->track_peak = 0.0;
+ priv->track_gain = 0.0;
+
+ if (!priv->tracks) {
+ BRASERO_JOB_LOG (normalize,
+ "Setting album peak (%lf) and gain (%lf)",
+ priv->album_peak,
+ priv->album_gain);
+
+ /* finished: set tags */
+ value = g_new0 (GValue, 1);
+ g_value_init (value, G_TYPE_DOUBLE);
+ g_value_set_double (value, priv->album_peak);
+ brasero_job_tag_add (BRASERO_JOB (normalize),
+ BRASERO_ALBUM_PEAK_VALUE,
+ value);
+
+ value = g_new0 (GValue, 1);
+ g_value_init (value, G_TYPE_DOUBLE);
+ g_value_set_double (value, priv->album_gain);
+ brasero_job_tag_add (BRASERO_JOB (normalize),
+ BRASERO_ALBUM_GAIN_VALUE,
+ value);
+
+ brasero_job_finished_session (BRASERO_JOB (normalize));
+ return;
+ }
+
+ /* jump to next track */
+ /* NOTE: why lock state? because otherwise analysis would lose all
+ * information about tracks already analysed by going into the NULL
+ * state. */
+ gst_element_set_locked_state (priv->analysis, TRUE);
+ gst_element_set_state (priv->pipeline, GST_STATE_NULL);
+
+ track = priv->tracks->data;
+ priv->tracks = g_slist_remove (priv->tracks, track);
+ if (!brasero_normalize_set_next_track (BRASERO_JOB (normalize), track, &error)) {
+ gst_element_set_locked_state (priv->analysis, FALSE);
+ brasero_job_error (BRASERO_JOB (normalize), error);
+ return;
+ }
+
+ gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
+ gst_element_set_locked_state (priv->analysis, FALSE);
+}
+
+static gboolean
+brasero_normalize_bus_messages (GstBus *bus,
+ GstMessage *msg,
+ BraseroNormalize *normalize)
+{
+ BraseroNormalizePrivate *priv;
+ GstTagList *tags = NULL;
+ GError *error = NULL;
+ gchar *debug;
+
+ priv = BRASERO_NORMALIZE_PRIVATE (normalize);
+ switch (GST_MESSAGE_TYPE (msg)) {
+ case GST_MESSAGE_TAG:
+ /* This is the information we've been waiting for.
+ * NOTE: levels for whole album is delivered at the end */
+ gst_message_parse_tag (msg, &tags);
+ gst_tag_list_foreach (tags, (GstTagForeachFunc) foreach_tag, normalize);
+ gst_tag_list_free (tags);
+ return TRUE;
+
+ case GST_MESSAGE_ERROR:
+ gst_message_parse_error (msg, &error, &debug);
+ BRASERO_JOB_LOG (normalize, debug);
+ g_free (debug);
+
+ brasero_job_error (BRASERO_JOB (normalize), error);
+ return FALSE;
+
+ case GST_MESSAGE_EOS:
+ brasero_normalize_song_end_reached (normalize);
+ return FALSE;
+
+ case GST_MESSAGE_STATE_CHANGED:
+ break;
+
+ default:
+ return TRUE;
+ }
+
+ return TRUE;
+}
+
+static void
+brasero_normalize_new_decoded_pad_cb (GstElement *decode,
+ GstPad *pad,
+ gboolean arg2,
+ BraseroNormalize *normalize)
+{
+ GstPad *sink;
+ GstCaps *caps;
+ GstStructure *structure;
+ BraseroNormalizePrivate *priv;
+
+ priv = BRASERO_NORMALIZE_PRIVATE (normalize);
+
+ sink = gst_element_get_pad (priv->resample, "sink");
+ if (GST_PAD_IS_LINKED (sink)) {
+ BRASERO_JOB_LOG (normalize, "New decoded pad already linked");
+ return;
+ }
+
+ /* make sure we only have audio */
+ caps = gst_pad_get_caps (pad);
+ if (!caps)
+ return;
+
+ structure = gst_caps_get_structure (caps, 0);
+ if (structure && g_strrstr (gst_structure_get_name (structure), "audio")) {
+ if (gst_pad_link (pad, sink) != GST_PAD_LINK_OK) {
+ BRASERO_JOB_LOG (normalize, "New decoded pad can't be linked");
+ brasero_job_error (BRASERO_JOB (normalize), NULL);
+ }
+ else
+ BRASERO_JOB_LOG (normalize, "New decoded pad linked");
+ }
+ else
+ BRASERO_JOB_LOG (normalize, "New decoded pad with unsupported stream time");
+
+ gst_object_unref (sink);
+ gst_caps_unref (caps);
+}
+
+static gboolean
+brasero_normalize_build_pipeline (BraseroNormalize *normalize,
+ GError **error)
+{
+ GstElement *decode;
+ GstElement *pipeline;
+ GstElement *sink = NULL;
+ GstElement *convert = NULL;
+ GstElement *analysis = NULL;
+ GstElement *resample = NULL;
+ BraseroNormalizePrivate *priv;
+
+ priv = BRASERO_NORMALIZE_PRIVATE (normalize);
+
+ BRASERO_JOB_LOG (normalize, "Creating new pipeline");
+
+ /* create filesrc ! decodebin ! audioresample ! audioconvert ! rganalysis ! fakesink */
+ pipeline = gst_pipeline_new (NULL);
+ priv->pipeline = pipeline;
+
+ /* NOTE: a new source is created at start of every track */
+
+ /* decode */
+ decode = gst_element_factory_make ("decodebin", NULL);
+ if (decode == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Decodebin\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (pipeline), decode);
+ priv->decode = decode;
+
+ /* audioconvert */
+ convert = gst_element_factory_make ("audioconvert", NULL);
+ if (convert == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Audioconvert\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (pipeline), convert);
+
+ /* audioresample */
+ resample = gst_element_factory_make ("audioresample", NULL);
+ if (resample == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Audioresample\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (pipeline), resample);
+ priv->resample = resample;
+
+ /* rganalysis: set the number of tracks to be expected */
+ analysis = gst_element_factory_make ("rganalysis", NULL);
+ if (analysis == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Rganalysis\"");
+ goto error;
+ }
+ priv->analysis = analysis;
+ gst_bin_add (GST_BIN (pipeline), analysis);
+
+ /* sink */
+ sink = gst_element_factory_make ("fakesink", NULL);
+ if (!sink) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Fakesink\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (pipeline), sink);
+ g_object_set (sink,
+ "sync", FALSE,
+ NULL);
+
+ /* link everything */
+ g_signal_connect (G_OBJECT (decode),
+ "new-decoded-pad",
+ G_CALLBACK (brasero_normalize_new_decoded_pad_cb),
+ normalize);
+ gst_element_link_many (resample,
+ convert,
+ analysis,
+ sink,
+ NULL);
+ return TRUE;
+
+error:
+
+ if (error && (*error))
+ BRASERO_JOB_LOG (normalize,
+ "can't create object : %s \n",
+ (*error)->message);
+
+ gst_object_unref (GST_OBJECT (pipeline));
+ return FALSE;
+}
+
+static BraseroBurnResult
+brasero_normalize_start (BraseroJob *job,
+ GError **error)
+{
+ BraseroNormalizePrivate *priv;
+ BraseroTrack *track;
+
+ priv = BRASERO_NORMALIZE_PRIVATE (job);
+
+ priv->album_gain = -1.0;
+ priv->album_peak = -1.0;
+
+ /* get tracks */
+ brasero_job_get_tracks (job, &priv->tracks);
+ if (!priv->tracks)
+ return BRASERO_BURN_ERR;
+
+ priv->tracks = g_slist_copy (priv->tracks);
+ track = priv->tracks->data;
+ priv->tracks = g_slist_remove (priv->tracks, track);
+
+ if (!brasero_normalize_build_pipeline (BRASERO_NORMALIZE (job), error))
+ return BRASERO_BURN_ERR;
+
+ g_object_set (priv->analysis,
+ "num-tracks", g_slist_length (priv->tracks),
+ NULL);
+
+ if (!brasero_normalize_set_next_track (job, track, error))
+ return BRASERO_BURN_ERR;
+
+ /* ready to go */
+ brasero_job_set_current_action (job,
+ BRASERO_BURN_ACTION_ANALYSING,
+ _("Normalizing tracks"),
+ FALSE);
+ gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_normalize_activate (BraseroJob *job,
+ GError **error)
+{
+ GSList *tracks;
+ BraseroJobAction action;
+
+ brasero_job_get_action (job, &action);
+ if (action != BRASERO_JOB_ACTION_IMAGE)
+ return BRASERO_BURN_NOT_RUNNING;
+
+ /* check we have more than one track */
+ brasero_job_get_tracks (job, &tracks);
+ if (g_slist_length (tracks) < 2)
+ return BRASERO_BURN_NOT_RUNNING;
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_normalize_clock_tick (BraseroJob *job)
+{
+ gint64 position = 0.0;
+ gint64 duration = 0.0;
+ BraseroNormalizePrivate *priv;
+ GstFormat format = GST_FORMAT_TIME;
+
+ priv = BRASERO_NORMALIZE_PRIVATE (job);
+
+ gst_element_query_duration (priv->pipeline, &format, &duration);
+ gst_element_query_position (priv->pipeline, &format, &position);
+
+ if (duration > 0) {
+ GSList *tracks;
+ gdouble progress;
+
+ brasero_job_get_tracks (job, &tracks);
+ progress = (gdouble) position / (gdouble) duration;
+
+ if (tracks) {
+ gdouble num_tracks;
+
+ num_tracks = g_slist_length (tracks);
+ progress = (gdouble) (num_tracks - 1.0 - (gdouble) g_slist_length (priv->tracks) + progress) / (gdouble) num_tracks;
+ brasero_job_set_progress (job, progress);
+ }
+ }
+
+ return BRASERO_BURN_OK;
+}
+
+static void
+brasero_normalize_init (BraseroNormalize *object)
+{}
+
+static void
+brasero_normalize_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+brasero_normalize_class_init (BraseroNormalizeClass *klass)
+{
+ GObjectClass* object_class = G_OBJECT_CLASS (klass);
+ BraseroJobClass *job_class = BRASERO_JOB_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (BraseroNormalizePrivate));
+
+ object_class->finalize = brasero_normalize_finalize;
+
+ job_class->activate = brasero_normalize_activate;
+ job_class->start = brasero_normalize_start;
+ job_class->clock_tick = brasero_normalize_clock_tick;
+ job_class->stop = brasero_normalize_stop;
+}
+
+static BraseroBurnResult
+brasero_normalize_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+ GSList *input;
+ GstElement *element;
+
+ brasero_plugin_define (plugin,
+ N_("Normalize"),
+ _("Normalize allows to set consistent sound levels between tracks"),
+ "Philippe Rouquier",
+ 0);
+
+ /* Let's see if we've got the plugins we need */
+ element = gst_element_factory_make ("rgvolume", NULL);
+ if (!element) {
+ *error = g_strdup_printf (_("%s element could not be created"),
+ "\"Rgvolume\"");
+ return BRASERO_BURN_ERR;
+ }
+ gst_object_unref (element);
+
+ element = gst_element_factory_make ("rganalysis", NULL);
+ if (!element) {
+ *error = g_strdup_printf (_("%s element could not be created"),
+ "\"Rganalysis\"");
+ return BRASERO_BURN_ERR;
+ }
+ gst_object_unref (element);
+
+ input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_AUDIO_FORMAT_UNDEFINED|
+ BRASERO_METADATA_INFO);
+ brasero_plugin_process_caps (plugin, input);
+ g_slist_free (input);
+
+ input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_AUDIO_FORMAT_UNDEFINED);
+ brasero_plugin_process_caps (plugin, input);
+ g_slist_free (input);
+
+ /* We should run first */
+ brasero_plugin_set_process_flags (plugin, BRASERO_PLUGIN_RUN_PREPROCESSING);
+
+ brasero_plugin_set_compulsory (plugin, FALSE);
+
+ return BRASERO_BURN_OK;
+}
diff --git a/plugins/transcode/burn-normalize.h b/plugins/transcode/burn-normalize.h
new file mode 100644
index 0000000..0a5d138
--- /dev/null
+++ b/plugins/transcode/burn-normalize.h
@@ -0,0 +1,48 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * brasero-normalize.c
+ * Copyright (C) Rouquier Philippe 2008 <bonfire-app wanadoo fr>
+ *
+ * brasero-normalize.c is free software.
+ *
+ * You may redistribute it and/or modify it under the terms of the
+ * GNU General Public License, as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * brasero-normalize.c is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with brasero-normalize.c. If not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _BRASERO_NORMALIZE_H_
+#define _BRASERO_NORMALIZE_H_
+
+#include <glib-object.h>
+
+#include "burn-job.h"
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_NORMALIZE (brasero_normalize_get_type ())
+#define BRASERO_NORMALIZE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BRASERO_TYPE_NORMALIZE, BraseroNormalize))
+#define BRASERO_NORMALIZE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), BRASERO_TYPE_NORMALIZE, BraseroNormalizeClass))
+#define BRASERO_IS_NORMALIZE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BRASERO_TYPE_NORMALIZE))
+#define BRASERO_IS_NORMALIZE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), BRASERO_TYPE_NORMALIZE))
+#define BRASERO_NORMALIZE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), BRASERO_TYPE_NORMALIZE, BraseroNormalizeClass))
+
+#define BRASERO_ALBUM_PEAK_VALUE "peak_value"
+#define BRASERO_ALBUM_GAIN_VALUE "gain_value"
+#define BRASERO_TRACK_PEAK_VALUE "peak_value"
+#define BRASERO_TRACK_GAIN_VALUE "gain_value"
+
+G_END_DECLS
+
+#endif /* _BRASERO_NORMALIZE_H_ */
diff --git a/plugins/transcode/burn-transcode.c b/plugins/transcode/burn-transcode.c
new file mode 100644
index 0000000..5b67160
--- /dev/null
+++ b/plugins/transcode/burn-transcode.c
@@ -0,0 +1,1647 @@
+/***************************************************************************
+ * transcode.c
+ *
+ * ven jui 8 16:15:04 2005
+ * Copyright 2005 Philippe Rouquier
+ * Brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+#include <math.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+#include <gmodule.h>
+
+#include <gst/gst.h>
+
+#include "burn-basics.h"
+#include "brasero-medium.h"
+#include "brasero-tags.h"
+#include "burn-job.h"
+#include "brasero-plugin-registration.h"
+#include "burn-transcode.h"
+#include "burn-normalize.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroTranscode, brasero_transcode, BRASERO_TYPE_JOB, BraseroJob);
+
+static gboolean brasero_transcode_bus_messages (GstBus *bus,
+ GstMessage *msg,
+ BraseroTranscode *transcode);
+static void brasero_transcode_new_decoded_pad_cb (GstElement *decode,
+ GstPad *pad,
+ gboolean arg2,
+ BraseroTranscode *transcode);
+
+struct BraseroTranscodePrivate {
+ GstElement *pipeline;
+ GstElement *convert;
+ GstElement *source;
+ GstElement *decode;
+ GstElement *sink;
+
+ /* element to link decode to */
+ GstElement *link;
+
+ gint pad_size;
+ gint pad_fd;
+ gint pad_id;
+
+ gint64 size;
+ gint64 pos;
+
+ gulong probe;
+ gint64 segment_start;
+ gint64 segment_end;
+
+ guint set_active_state:1;
+ guint mp3_size_pipeline:1;
+};
+typedef struct BraseroTranscodePrivate BraseroTranscodePrivate;
+
+#define BRASERO_TRANSCODE_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_TRANSCODE, BraseroTranscodePrivate))
+
+static GObjectClass *parent_class = NULL;
+
+static gboolean
+brasero_transcode_buffer_handler (GstPad *pad,
+ GstBuffer *buffer,
+ BraseroTranscode *self)
+{
+ BraseroTranscodePrivate *priv;
+ GstPad *peer;
+ gint64 size;
+
+ priv = BRASERO_TRANSCODE_PRIVATE (self);
+
+ size = GST_BUFFER_SIZE (buffer);
+
+ if (priv->segment_start <= 0 && priv->segment_end <= 0)
+ return TRUE;
+
+ /* what we do here is more or less what gstreamer does when seeking:
+ * it reads and process from 0 to the seek position (I tried).
+ * It even forwards the data before the seek position to the sink (which
+ * is a problem in our case as it would be written) */
+ if (priv->size > priv->segment_end) {
+ priv->size += size;
+ return FALSE;
+ }
+
+ if (priv->size + size > priv->segment_end) {
+ GstBuffer *new_buffer;
+ int data_size;
+
+ /* the entire the buffer is not interesting for us */
+ /* create a new buffer and push it on the pad:
+ * NOTE: we're going to receive it ... */
+ data_size = priv->segment_end - priv->size;
+ new_buffer = gst_buffer_new_and_alloc (data_size);
+ memcpy (GST_BUFFER_DATA (new_buffer), GST_BUFFER_DATA (buffer), data_size);
+
+ /* Recursive: the following calls ourselves BEFORE we finish */
+ peer = gst_pad_get_peer (pad);
+ gst_pad_push (peer, new_buffer);
+
+ priv->size += size - data_size;
+
+ /* post an EOS event to stop pipeline */
+ gst_pad_push_event (peer, gst_event_new_eos ());
+ gst_object_unref (peer);
+ return FALSE;
+ }
+
+ /* see if the buffer is in the segment */
+ if (priv->size < priv->segment_start) {
+ GstBuffer *new_buffer;
+ gint data_size;
+
+ /* see if all the buffer is interesting for us */
+ if (priv->size + size < priv->segment_start) {
+ priv->size += size;
+ return FALSE;
+ }
+
+ /* create a new buffer and push it on the pad:
+ * NOTE: we're going to receive it ... */
+ data_size = priv->size + size - priv->segment_start;
+ new_buffer = gst_buffer_new_and_alloc (data_size);
+ memcpy (GST_BUFFER_DATA (new_buffer),
+ GST_BUFFER_DATA (buffer) +
+ GST_BUFFER_SIZE (buffer) -
+ data_size,
+ data_size);
+ GST_BUFFER_TIMESTAMP (new_buffer) = GST_BUFFER_TIMESTAMP (buffer) + data_size;
+
+ /* move forward by the size of bytes we dropped */
+ priv->size += size - data_size;
+
+ /* this is recursive the following calls ourselves
+ * BEFORE we finish */
+ peer = gst_pad_get_peer (pad);
+ gst_pad_push (peer, new_buffer);
+ gst_object_unref (peer);
+
+ return FALSE;
+ }
+
+ priv->size += size;
+ priv->pos += size;
+
+ return TRUE;
+}
+
+static BraseroBurnResult
+brasero_transcode_set_boundaries (BraseroTranscode *transcode)
+{
+ BraseroTranscodePrivate *priv;
+ BraseroTrack *track;
+ gint64 start;
+ gint64 end;
+
+ priv = BRASERO_TRANSCODE_PRIVATE (transcode);
+
+ /* we need to reach the song start and set a possible end; this is only
+ * needed when it is decoding a song. Otherwise*/
+ brasero_job_get_current_track (BRASERO_JOB (transcode), &track);
+ start = brasero_track_stream_get_start (BRASERO_TRACK_STREAM (track));
+ end = brasero_track_stream_get_end (BRASERO_TRACK_STREAM (track));
+
+ priv->segment_start = BRASERO_DURATION_TO_BYTES (start);
+ priv->segment_end = BRASERO_DURATION_TO_BYTES (end);
+
+ BRASERO_JOB_LOG (transcode, "settings track boundaries time = %lli %lli / bytes = %lli %lli",
+ start, end,
+ priv->segment_start, priv->segment_end);
+
+ return BRASERO_BURN_OK;
+}
+
+static void
+brasero_transcode_send_volume_event (BraseroTranscode *transcode)
+{
+ BraseroTranscodePrivate *priv;
+ gdouble track_peak = 0.0;
+ gdouble track_gain = 0.0;
+ GstTagList *tag_list;
+ BraseroTrack *track;
+ GstEvent *event;
+ GValue *value;
+
+ priv = BRASERO_TRANSCODE_PRIVATE (transcode);
+
+ brasero_job_get_current_track (BRASERO_JOB (transcode), &track);
+
+ BRASERO_JOB_LOG (transcode, "Sending audio levels tags");
+ if (brasero_track_tag_lookup (track, BRASERO_TRACK_PEAK_VALUE, &value) == BRASERO_BURN_OK)
+ track_peak = g_value_get_double (value);
+
+ if (brasero_track_tag_lookup (track, BRASERO_TRACK_GAIN_VALUE, &value) == BRASERO_BURN_OK)
+ track_gain = g_value_get_double (value);
+
+ /* it's possible we fail */
+ tag_list = gst_tag_list_new ();
+ gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE,
+ GST_TAG_TRACK_GAIN, track_gain,
+ GST_TAG_TRACK_PEAK, track_peak,
+ NULL);
+
+ /* NOTE: that event is goind downstream */
+ event = gst_event_new_tag (tag_list);
+ if (!gst_element_send_event (priv->convert, event))
+ BRASERO_JOB_LOG (transcode, "Couldn't send tags to rgvolume");
+
+ BRASERO_JOB_LOG (transcode, "Set volume level %lf %lf", track_gain, track_peak);
+}
+
+static GstElement *
+brasero_transcode_create_volume (BraseroTranscode *transcode,
+ BraseroTrack *track)
+{
+ GstElement *volume = NULL;
+
+ /* see if we need a volume object */
+ if (brasero_track_tag_lookup (track, BRASERO_TRACK_PEAK_VALUE, NULL) == BRASERO_BURN_OK
+ || brasero_track_tag_lookup (track, BRASERO_TRACK_GAIN_VALUE, NULL) == BRASERO_BURN_OK) {
+ BRASERO_JOB_LOG (transcode, "Found audio levels tags");
+ volume = gst_element_factory_make ("rgvolume", NULL);
+ if (volume)
+ g_object_set (volume,
+ "album-mode", FALSE,
+ NULL);
+ else
+ BRASERO_JOB_LOG (transcode, "rgvolume object couldn't be created");
+ }
+
+ return volume;
+}
+
+static gboolean
+brasero_transcode_create_pipeline_size_mp3 (BraseroTranscode *transcode,
+ GstElement *pipeline,
+ GstElement *source, GError **error)
+{
+ BraseroTranscodePrivate *priv;
+ GstElement *parse;
+ GstElement *sink;
+
+ priv = BRASERO_TRANSCODE_PRIVATE (transcode);
+
+ BRASERO_JOB_LOG (transcode, "Creating specific pipeline for MP3s");
+
+ parse = gst_element_factory_make ("mp3parse", NULL);
+ if (!parse) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Mp3parse\"");
+ g_object_unref (pipeline);
+ return FALSE;
+ }
+ gst_bin_add (GST_BIN (pipeline), parse);
+
+ sink = gst_element_factory_make ("fakesink", NULL);
+ if (!sink) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Fakesink\"");
+ g_object_unref (pipeline);
+ return FALSE;
+ }
+ gst_bin_add (GST_BIN (pipeline), sink);
+
+ /* Link */
+ if (!gst_element_link_many (source, parse, sink, NULL)) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("Impossible to link plugin pads"));
+ BRASERO_JOB_LOG (transcode, "Impossible to link elements");
+ g_object_unref (pipeline);
+ return FALSE;
+ }
+
+ priv->convert = NULL;
+
+ priv->sink = sink;
+ priv->source = source;
+ priv->pipeline = pipeline;
+
+ /* Get it going */
+ gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
+ return TRUE;
+}
+
+static gboolean
+brasero_transcode_create_pipeline (BraseroTranscode *transcode,
+ GError **error)
+{
+ gchar *uri;
+ GstElement *decode;
+ GstElement *source;
+ GstBus *bus = NULL;
+ GstCaps *filtercaps;
+ GstElement *pipeline;
+ GstElement *sink = NULL;
+ BraseroJobAction action;
+ GstElement *filter = NULL;
+ GstElement *volume = NULL;
+ GstElement *convert = NULL;
+ BraseroTrack *track = NULL;
+ GstElement *resample = NULL;
+ BraseroTranscodePrivate *priv;
+
+ priv = BRASERO_TRANSCODE_PRIVATE (transcode);
+
+ BRASERO_JOB_LOG (transcode, "Creating new pipeline");
+
+ priv->set_active_state = 0;
+
+ /* free the possible current pipeline and create a new one */
+ if (priv->pipeline) {
+ gst_element_set_state (priv->pipeline, GST_STATE_NULL);
+ gst_object_unref (G_OBJECT (priv->pipeline));
+ priv->link = NULL;
+ priv->sink = NULL;
+ priv->source = NULL;
+ priv->convert = NULL;
+ priv->pipeline = NULL;
+ }
+
+ /* create three types of pipeline according to the needs: (possibly adding grvolume)
+ * - filesrc ! decodebin ! audioconvert ! fakesink (find size) and filesrc!mp3parse!fakesink for mp3s
+ * - filesrc ! decodebin ! audioresample ! audioconvert ! audio/x-raw-int,rate=44100,width=16,depth=16,endianness=4321,signed ! filesink
+ * - filesrc ! decodebin ! audioresample ! audioconvert ! audio/x-raw-int,rate=44100,width=16,depth=16,endianness=4321,signed ! fdsink
+ */
+ pipeline = gst_pipeline_new (NULL);
+
+ bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
+ gst_bus_add_watch (bus,
+ (GstBusFunc) brasero_transcode_bus_messages,
+ transcode);
+ gst_object_unref (bus);
+
+ /* source */
+ brasero_job_get_current_track (BRASERO_JOB (transcode), &track);
+ uri = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (track), TRUE);
+ source = gst_element_make_from_uri (GST_URI_SRC, uri, NULL);
+ g_free (uri);
+
+ if (source == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ /* Translators: %s is the name of the GstElement that
+ * could not be created */
+ _("%s element could not be created"),
+ "\"Source\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (pipeline), source);
+ g_object_set (source,
+ "typefind", FALSE,
+ NULL);
+
+ /* sink */
+ brasero_job_get_action (BRASERO_JOB (transcode), &action);
+ switch (action) {
+ case BRASERO_JOB_ACTION_SIZE:
+ if (priv->mp3_size_pipeline)
+ return brasero_transcode_create_pipeline_size_mp3 (transcode, pipeline, source, error);
+
+ sink = gst_element_factory_make ("fakesink", NULL);
+ break;
+
+ case BRASERO_JOB_ACTION_IMAGE:
+ volume = brasero_transcode_create_volume (transcode, track);
+
+ if (brasero_job_get_fd_out (BRASERO_JOB (transcode), NULL) != BRASERO_BURN_OK) {
+ gchar *output;
+
+ brasero_job_get_image_output (BRASERO_JOB (transcode),
+ &output,
+ NULL);
+ sink = gst_element_factory_make ("filesink", NULL);
+ g_object_set (sink,
+ "location", output,
+ NULL);
+ }
+ else {
+ int fd;
+
+ brasero_job_get_fd_out (BRASERO_JOB (transcode), &fd);
+ sink = gst_element_factory_make ("fdsink", NULL);
+ g_object_set (sink,
+ "fd", fd,
+ NULL);
+ }
+ break;
+
+ default:
+ goto error;
+ }
+
+ if (!sink) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Sink\"");
+ goto error;
+ }
+
+ gst_bin_add (GST_BIN (pipeline), sink);
+ g_object_set (sink,
+ "sync", FALSE,
+ NULL);
+
+ /* audioconvert */
+ convert = gst_element_factory_make ("audioconvert", NULL);
+ if (convert == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Audioconvert\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (pipeline), convert);
+
+ if (action == BRASERO_JOB_ACTION_IMAGE) {
+ /* audioresample */
+ resample = gst_element_factory_make ("audioresample", NULL);
+ if (resample == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Audioresample\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (pipeline), resample);
+
+ /* filter */
+ filter = gst_element_factory_make ("capsfilter", NULL);
+ if (!filter) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Filter\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (pipeline), filter);
+ filtercaps = gst_caps_new_full (gst_structure_new ("audio/x-raw-int",
+ "channels", G_TYPE_INT, 2,
+ "width", G_TYPE_INT, 16,
+ "depth", G_TYPE_INT, 16,
+ "endianness", G_TYPE_INT, 1234,
+ "rate", G_TYPE_INT, 44100,
+ "signed", G_TYPE_BOOLEAN, TRUE,
+ NULL),
+ NULL);
+ g_object_set (GST_OBJECT (filter), "caps", filtercaps, NULL);
+ gst_caps_unref (filtercaps);
+ }
+
+ /* decode */
+ decode = gst_element_factory_make ("decodebin", NULL);
+ if (decode == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Decodebin\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (pipeline), decode);
+
+ priv->sink = sink;
+ priv->decode = decode;
+ priv->source = source;
+ priv->convert = convert;
+ priv->pipeline = pipeline;
+
+ if (action == BRASERO_JOB_ACTION_IMAGE) {
+ GstPad *sinkpad;
+
+ gst_element_link_many (source, decode, NULL);
+ priv->link = resample;
+ g_signal_connect (G_OBJECT (decode),
+ "new-decoded-pad",
+ G_CALLBACK (brasero_transcode_new_decoded_pad_cb),
+ transcode);
+
+ if (volume) {
+ gst_bin_add (GST_BIN (pipeline), volume);
+ gst_element_link_many (resample,
+ convert,
+ volume,
+ filter,
+ sink,
+ NULL);
+ }
+ else
+ gst_element_link_many (resample,
+ convert,
+ filter,
+ sink,
+ NULL);
+
+ /* This is an ugly workaround for the lack of accuracy with
+ * gstreamer. Yet this is unfortunately a necessary evil. */
+ priv->pos = 0;
+ priv->size = 0;
+ sinkpad = gst_element_get_pad (priv->sink, "sink");
+ priv->probe = gst_pad_add_buffer_probe (sinkpad,
+ G_CALLBACK (brasero_transcode_buffer_handler),
+ transcode);
+ gst_object_unref (sinkpad);
+ }
+ else {
+ gst_element_link (source, decode);
+ gst_element_link (convert, sink);
+
+ priv->link = convert;
+ g_signal_connect (G_OBJECT (decode),
+ "new-decoded-pad",
+ G_CALLBACK (brasero_transcode_new_decoded_pad_cb),
+ transcode);
+ }
+
+ gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
+ return TRUE;
+
+error:
+
+ if (error && (*error))
+ BRASERO_JOB_LOG (transcode,
+ "can't create object : %s \n",
+ (*error)->message);
+
+ gst_object_unref (GST_OBJECT (pipeline));
+ return FALSE;
+}
+
+static void
+brasero_transcode_set_track_size (BraseroTranscode *transcode,
+ gint64 duration)
+{
+ gchar *uri;
+ BraseroTrack *track;
+
+ brasero_job_get_current_track (BRASERO_JOB (transcode), &track);
+ brasero_track_stream_set_boundaries (BRASERO_TRACK_STREAM (track), -1, duration, -1);
+ duration += brasero_track_stream_get_gap (BRASERO_TRACK_STREAM (track));
+
+ /* if transcoding on the fly we should add some length just to make
+ * sure we won't be too short (gstreamer duration discrepancy) */
+ brasero_job_set_output_size_for_current_track (BRASERO_JOB (transcode),
+ BRASERO_DURATION_TO_SECTORS (duration),
+ BRASERO_DURATION_TO_BYTES (duration));
+
+ uri = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (track), FALSE);
+ BRASERO_JOB_LOG (transcode,
+ "Song %s"
+ "\nsectors %" G_GINT64_FORMAT
+ "\ntime %" G_GINT64_FORMAT,
+ uri,
+ BRASERO_DURATION_TO_SECTORS (duration),
+ duration);
+ g_free (uri);
+}
+
+/**
+ * These functions are to deal with siblings
+ */
+
+static BraseroBurnResult
+brasero_transcode_create_sibling_size (BraseroTranscode *transcode,
+ BraseroTrack *src,
+ GError **error)
+{
+ BraseroTrack *dest;
+ guint64 duration;
+
+ /* it means the same file uri is in the selection and was already
+ * checked. Simply get the values for the length and other information
+ * and copy them. */
+ /* NOTE: no need to copy the length since if they are sibling that means
+ * that they have the same length */
+ brasero_track_stream_get_length (BRASERO_TRACK_STREAM (src), &duration);
+ brasero_job_set_output_size_for_current_track (BRASERO_JOB (transcode),
+ BRASERO_DURATION_TO_SECTORS (duration),
+ BRASERO_DURATION_TO_BYTES (duration));
+
+ /* copy the info we are missing */
+ brasero_job_get_current_track (BRASERO_JOB (transcode), &dest);
+ brasero_track_tag_copy_missing (dest, src);
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_transcode_create_sibling_image (BraseroTranscode *transcode,
+ BraseroTrack *src,
+ GError **error)
+{
+ BraseroTrackStream *dest;
+ BraseroTrack *track;
+ guint64 length = 0;
+ gchar *path_dest;
+ gchar *path_src;
+
+ /* it means the file is already in the selection. Simply create a
+ * symlink pointing to first file in the selection with the same uri */
+ path_src = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (src), FALSE);
+ brasero_job_get_audio_output (BRASERO_JOB (transcode), &path_dest);
+
+ if (symlink (path_src, path_dest) == -1) {
+ int errsv = errno;
+
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ /* Translators: the %s is the error message from errno */
+ _("An internal error occured (%s)"),
+ g_strerror (errsv));
+
+ goto error;
+ }
+
+ dest = brasero_track_stream_new ();
+ brasero_track_stream_set_source (dest, path_dest);
+ brasero_track_stream_set_format (dest,
+ BRASERO_AUDIO_FORMAT_RAW|
+ BRASERO_AUDIO_FORMAT_44100);
+
+ /* NOTE: there is no gap and start = 0 since these tracks are the result
+ * of the transformation of previous ones */
+ brasero_track_stream_get_length (BRASERO_TRACK_STREAM (src), &length);
+ brasero_track_stream_set_boundaries (dest, 0, length, 0);
+
+ /* copy all infos but from the current track */
+ brasero_job_get_current_track (BRASERO_JOB (transcode), &track);
+ brasero_track_tag_copy_missing (BRASERO_TRACK (dest), track);
+ brasero_job_add_track (BRASERO_JOB (transcode), BRASERO_TRACK (dest));
+
+ /* It's good practice to unref the track afterwards as we don't need it
+ * anymore. BraseroTaskCtx refs it. */
+ g_object_unref (dest);
+
+ g_free (path_src);
+ g_free (path_dest);
+
+ return BRASERO_BURN_NOT_RUNNING;
+
+error:
+ g_free (path_src);
+ g_free (path_dest);
+
+ return BRASERO_BURN_ERR;
+}
+
+static BraseroTrack *
+brasero_transcode_search_for_sibling (BraseroTranscode *transcode)
+{
+ BraseroJobAction action;
+ GSList *iter, *songs;
+ BraseroTrack *track;
+ gint64 start;
+ gint64 end;
+ gchar *uri;
+
+ brasero_job_get_action (BRASERO_JOB (transcode), &action);
+
+ brasero_job_get_current_track (BRASERO_JOB (transcode), &track);
+ start = brasero_track_stream_get_start (BRASERO_TRACK_STREAM (track));
+ end = brasero_track_stream_get_end (BRASERO_TRACK_STREAM (track));
+ uri = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (track), TRUE);
+
+ brasero_job_get_done_tracks (BRASERO_JOB (transcode), &songs);
+
+ for (iter = songs; iter; iter = iter->next) {
+ gchar *iter_uri;
+ gint64 iter_end;
+ gint64 iter_start;
+ BraseroTrack *iter_track;
+
+ iter_track = iter->data;
+ iter_uri = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (iter_track), TRUE);
+
+ if (strcmp (iter_uri, uri))
+ continue;
+
+ iter_end = brasero_track_stream_get_end (BRASERO_TRACK_STREAM (iter_track));
+ if (!iter_end)
+ continue;
+
+ if (iter_end != end)
+ continue;
+
+ iter_start = brasero_track_stream_get_start (BRASERO_TRACK_STREAM (track));
+ if (iter_start == start) {
+ g_free (uri);
+ return iter_track;
+ }
+ }
+
+ g_free (uri);
+ return NULL;
+}
+
+static BraseroBurnResult
+brasero_transcode_has_track_sibling (BraseroTranscode *transcode,
+ GError **error)
+{
+ BraseroJobAction action;
+ BraseroTrack *sibling = NULL;
+ BraseroBurnResult result = BRASERO_BURN_OK;
+
+ if (brasero_job_get_fd_out (BRASERO_JOB (transcode), NULL) == BRASERO_BURN_OK)
+ return BRASERO_BURN_OK;
+
+ sibling = brasero_transcode_search_for_sibling (transcode);
+ if (!sibling)
+ return BRASERO_BURN_OK;
+
+ BRASERO_JOB_LOG (transcode, "found sibling: skipping");
+ brasero_job_get_action (BRASERO_JOB (transcode), &action);
+ if (action == BRASERO_JOB_ACTION_IMAGE)
+ result = brasero_transcode_create_sibling_image (transcode,
+ sibling,
+ error);
+ else if (action == BRASERO_JOB_ACTION_SIZE)
+ result = brasero_transcode_create_sibling_size (transcode,
+ sibling,
+ error);
+
+ return result;
+}
+
+static BraseroBurnResult
+brasero_transcode_start (BraseroJob *job,
+ GError **error)
+{
+ BraseroTranscode *transcode;
+ BraseroBurnResult result;
+ BraseroJobAction action;
+
+ transcode = BRASERO_TRANSCODE (job);
+
+ brasero_job_get_action (job, &action);
+ brasero_job_set_use_average_rate (job, TRUE);
+
+ if (action == BRASERO_JOB_ACTION_SIZE) {
+ BraseroTrack *track;
+
+ /* see if the track size was already set since then no need to
+ * carry on with a lengthy get size and the library will do it
+ * itself. */
+ brasero_job_get_current_track (job, &track);
+ if (brasero_track_stream_get_end (BRASERO_TRACK_STREAM (track)) > 0)
+ return BRASERO_BURN_NOT_SUPPORTED;
+
+ if (!brasero_transcode_create_pipeline (transcode, error))
+ return BRASERO_BURN_ERR;
+
+ brasero_job_set_current_action (job,
+ BRASERO_BURN_ACTION_GETTING_SIZE,
+ NULL,
+ TRUE);
+
+ brasero_job_start_progress (job, FALSE);
+ return BRASERO_BURN_OK;
+ }
+
+ if (action == BRASERO_JOB_ACTION_IMAGE) {
+ /* Look for a sibling to avoid transcoding twice. In this case
+ * though start and end of this track must be inside start and
+ * end of the previous track. Of course if we are piping that
+ * operation is simply impossible. */
+ if (brasero_job_get_fd_out (job, NULL) != BRASERO_BURN_OK) {
+ result = brasero_transcode_has_track_sibling (BRASERO_TRANSCODE (job), error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+ }
+
+ brasero_transcode_set_boundaries (transcode);
+ if (!brasero_transcode_create_pipeline (transcode, error))
+ return BRASERO_BURN_ERR;
+ }
+ else
+ BRASERO_JOB_NOT_SUPPORTED (transcode);
+
+ return BRASERO_BURN_OK;
+}
+
+static void
+brasero_transcode_stop_pipeline (BraseroTranscode *transcode)
+{
+ BraseroTranscodePrivate *priv;
+ GstPad *sinkpad;
+
+ priv = BRASERO_TRANSCODE_PRIVATE (transcode);
+ if (!priv->pipeline)
+ return;
+
+ sinkpad = gst_element_get_pad (priv->sink, "sink");
+ if (priv->probe)
+ gst_pad_remove_buffer_probe (sinkpad, priv->probe);
+
+ gst_object_unref (sinkpad);
+
+ gst_element_set_state (priv->pipeline, GST_STATE_NULL);
+ gst_object_unref (GST_OBJECT (priv->pipeline));
+
+ priv->link = NULL;
+ priv->sink = NULL;
+ priv->source = NULL;
+ priv->convert = NULL;
+ priv->pipeline = NULL;
+
+ priv->set_active_state = 0;
+}
+
+static BraseroBurnResult
+brasero_transcode_stop (BraseroJob *job,
+ GError **error)
+{
+ BraseroTranscodePrivate *priv;
+
+ priv = BRASERO_TRANSCODE_PRIVATE (job);
+
+ priv->mp3_size_pipeline = 0;
+
+ if (priv->pad_id) {
+ g_source_remove (priv->pad_id);
+ priv->pad_id = 0;
+ }
+
+ brasero_transcode_stop_pipeline (BRASERO_TRANSCODE (job));
+ return BRASERO_BURN_OK;
+}
+
+/* we must make sure that the track size is a multiple
+ * of 2352 to be burnt by cdrecord with on the fly */
+
+static gint64
+brasero_transcode_pad_real (BraseroTranscode *transcode,
+ int fd,
+ gint64 bytes2write,
+ GError **error)
+{
+ const int buffer_size = 512;
+ char buffer [buffer_size];
+ gint64 b_written;
+ gint64 size;
+
+ b_written = 0;
+ bzero (buffer, sizeof (buffer));
+ for (; bytes2write; bytes2write -= b_written) {
+ size = bytes2write > buffer_size ? buffer_size : bytes2write;
+ b_written = write (fd, buffer, (int) size);
+
+ BRASERO_JOB_LOG (transcode,
+ "written %" G_GINT64_FORMAT " bytes for padding",
+ b_written);
+
+ /* we should not handle EINTR and EAGAIN as errors */
+ if (b_written < 0) {
+ if (errno == EINTR || errno == EAGAIN) {
+ BRASERO_JOB_LOG (transcode, "got EINTR / EAGAIN, retrying");
+
+ /* we'll try later again */
+ return bytes2write;
+ }
+ }
+
+ if (size != b_written) {
+ int errsv = errno;
+
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ /* Translators: %s is the string error from errno */
+ _("Error while padding file (%s)"),
+ g_strerror (errsv));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static void
+brasero_transcode_push_track (BraseroTranscode *transcode)
+{
+ guint64 length = 0;
+ gchar *output = NULL;
+ BraseroTrack *src = NULL;
+ BraseroTrackStream *track;
+
+ brasero_job_get_audio_output (BRASERO_JOB (transcode), &output);
+ brasero_job_get_current_track (BRASERO_JOB (transcode), &src);
+
+ brasero_track_stream_get_length (BRASERO_TRACK_STREAM (src), &length);
+
+ track = brasero_track_stream_new ();
+ brasero_track_stream_set_source (track, output);
+ brasero_track_stream_set_format (track,
+ BRASERO_AUDIO_FORMAT_RAW|
+ BRASERO_AUDIO_FORMAT_44100);
+ brasero_track_stream_set_boundaries (track, 0, length, 0);
+ brasero_track_tag_copy_missing (BRASERO_TRACK (track), src);
+
+ brasero_job_add_track (BRASERO_JOB (transcode), BRASERO_TRACK (track));
+
+ /* It's good practice to unref the track afterwards as we don't need it
+ * anymore. BraseroTaskCtx refs it. */
+ g_object_unref (track);
+
+ brasero_job_finished_track (BRASERO_JOB (transcode));
+}
+
+static gboolean
+brasero_transcode_pad_idle (BraseroTranscode *transcode)
+{
+ gint64 bytes2write;
+ GError *error = NULL;
+ BraseroTranscodePrivate *priv;
+
+ priv = BRASERO_TRANSCODE_PRIVATE (transcode);
+ bytes2write = brasero_transcode_pad_real (transcode,
+ priv->pad_fd,
+ priv->pad_size,
+ &error);
+
+ if (bytes2write == -1) {
+ priv->pad_id = 0;
+ brasero_job_error (BRASERO_JOB (transcode), error);
+ return FALSE;
+ }
+
+ if (bytes2write) {
+ priv->pad_size = bytes2write;
+ return TRUE;
+ }
+
+ /* we are finished with padding */
+ priv->pad_id = 0;
+ close (priv->pad_fd);
+ priv->pad_fd = -1;
+
+ /* set the next song or finish */
+ brasero_transcode_push_track (transcode);
+ return FALSE;
+}
+
+static gboolean
+brasero_transcode_pad (BraseroTranscode *transcode, int fd, GError **error)
+{
+ guint64 length = 0;
+ gint64 bytes2write = 0;
+ BraseroTrack *track = NULL;
+ BraseroTranscodePrivate *priv;
+
+ priv = BRASERO_TRANSCODE_PRIVATE (transcode);
+ if (priv->pos < 0)
+ return TRUE;
+
+ /* Padding is important for two reasons:
+ * - first if didn't output enough bytes compared to what we should have
+ * - second we must output a multiple of 2352 to respect sector
+ * boundaries */
+ brasero_job_get_current_track (BRASERO_JOB (transcode), &track);
+ brasero_track_stream_get_length (BRASERO_TRACK_STREAM (track), &length);
+
+ if (priv->pos < BRASERO_DURATION_TO_BYTES (length)) {
+ gint64 b_written = 0;
+
+ /* Check bytes boundary for length */
+ b_written = BRASERO_DURATION_TO_BYTES (length);
+ b_written += (b_written % 2352) ? 2352 - (b_written % 2352):0;
+ bytes2write = b_written - priv->pos;
+
+ BRASERO_JOB_LOG (transcode,
+ "wrote %lli bytes (= %lli ns) out of %lli (= %lli ns)"
+ "\n=> padding %lli bytes",
+ priv->pos,
+ BRASERO_BYTES_TO_DURATION (priv->pos),
+ BRASERO_DURATION_TO_BYTES (length),
+ length,
+ bytes2write);
+ }
+ else {
+ gint64 b_written = 0;
+
+ /* wrote more or the exact amount of bytes. Check bytes boundary */
+ b_written = priv->pos;
+ bytes2write = (b_written % 2352) ? 2352 - (b_written % 2352):0;
+ BRASERO_JOB_LOG (transcode,
+ "wrote %lli bytes (= %lli ns)"
+ "\n=> padding %lli bytes",
+ b_written,
+ priv->pos,
+ bytes2write);
+ }
+
+ if (!bytes2write)
+ return TRUE;
+
+ bytes2write = brasero_transcode_pad_real (transcode,
+ fd,
+ bytes2write,
+ error);
+ if (bytes2write == -1)
+ return TRUE;
+
+ if (bytes2write) {
+ BraseroTranscodePrivate *priv;
+
+ priv = BRASERO_TRANSCODE_PRIVATE (transcode);
+ /* when writing to a pipe it can happen that its buffer is full
+ * because cdrecord is not fast enough. Therefore we couldn't
+ * write/pad it and we'll have to wait for the pipe to become
+ * available again */
+ priv->pad_fd = fd;
+ priv->pad_size = bytes2write;
+ priv->pad_id = g_timeout_add (50,
+ (GSourceFunc) brasero_transcode_pad_idle,
+ transcode);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+brasero_transcode_pad_pipe (BraseroTranscode *transcode, GError **error)
+{
+ int fd;
+ gboolean result;
+
+ brasero_job_get_fd_out (BRASERO_JOB (transcode), &fd);
+ fd = dup (fd);
+
+ result = brasero_transcode_pad (transcode, fd, error);
+ if (result)
+ close (fd);
+
+ return result;
+}
+
+static gboolean
+brasero_transcode_pad_file (BraseroTranscode *transcode, GError **error)
+{
+ int fd;
+ gchar *output;
+ gboolean result;
+
+ output = NULL;
+ brasero_job_get_audio_output (BRASERO_JOB (transcode), &output);
+ fd = open (output, O_WRONLY | O_CREAT | O_APPEND, S_IRWXU | S_IRGRP | S_IROTH);
+ g_free (output);
+
+ if (fd == -1) {
+ int errsv = errno;
+
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ /* Translators: %s is the string error from errno */
+ _("Error while padding file (%s)"),
+ g_strerror (errsv));
+ return FALSE;
+ }
+
+ result = brasero_transcode_pad (transcode, fd, error);
+ if (result)
+ close (fd);
+
+ return result;
+}
+
+static gboolean
+brasero_transcode_is_mp3 (BraseroTranscode *transcode)
+{
+ BraseroTranscodePrivate *priv;
+ GstElement *typefind;
+ GstCaps *caps = NULL;
+ const gchar *mime;
+
+ priv = BRASERO_TRANSCODE_PRIVATE (transcode);
+
+ /* find the type of the file */
+ typefind = gst_bin_get_by_name (GST_BIN (priv->decode), "typefind");
+ g_object_get (typefind, "caps", &caps, NULL);
+ if (!caps) {
+ gst_object_unref (typefind);
+ return TRUE;
+ }
+
+ if (caps && gst_caps_get_size (caps) > 0) {
+ mime = gst_structure_get_name (gst_caps_get_structure (caps, 0));
+ gst_object_unref (typefind);
+
+ if (mime && !strcmp (mime, "application/x-id3"))
+ return TRUE;
+
+ if (!strcmp (mime, "audio/mpeg"))
+ return TRUE;
+ }
+ else
+ gst_object_unref (typefind);
+
+ return FALSE;
+}
+
+static gint64
+brasero_transcode_get_duration (BraseroTranscode *transcode)
+{
+ gint64 duration = -1;
+ BraseroTranscodePrivate *priv;
+ GstFormat format = GST_FORMAT_TIME;
+
+ priv = BRASERO_TRANSCODE_PRIVATE (transcode);
+
+ /* This part is specific to MP3s */
+ if (priv->mp3_size_pipeline) {
+ /* This is the most reliable way to get the duration for mp3
+ * read them till the end and get the position. */
+ gst_element_query_position (priv->pipeline,
+ &format,
+ &duration);
+ }
+
+ /* This is for any sort of files */
+ if (duration == -1 || duration == 0)
+ gst_element_query_duration (priv->pipeline,
+ &format,
+ &duration);
+
+ BRASERO_JOB_LOG (transcode, "got duration %"G_GINT64_FORMAT, duration);
+
+ if (duration == -1 || duration == 0)
+ brasero_job_error (BRASERO_JOB (transcode),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("Error while getting duration")));
+ return duration;
+}
+
+static gboolean
+brasero_transcode_song_end_reached (BraseroTranscode *transcode)
+{
+ GError *error = NULL;
+ BraseroJobAction action;
+
+ brasero_job_get_action (BRASERO_JOB (transcode), &action);
+ if (action == BRASERO_JOB_ACTION_SIZE) {
+ gint64 duration;
+
+ /* this is when we need to write infs:
+ * - when asked to create infs
+ * - when decoding to a file */
+ duration = brasero_transcode_get_duration (transcode);
+ if (duration == -1)
+ return FALSE;
+
+ brasero_transcode_set_track_size (transcode, duration);
+ brasero_job_finished_track (BRASERO_JOB (transcode));
+ return TRUE;
+ }
+
+ if (action == BRASERO_JOB_ACTION_IMAGE) {
+ gboolean result;
+
+ /* pad file so it is a multiple of 2352 (= 1 sector) */
+ if (brasero_job_get_fd_out (BRASERO_JOB (transcode), NULL) == BRASERO_BURN_OK)
+ result = brasero_transcode_pad_pipe (transcode, &error);
+ else
+ result = brasero_transcode_pad_file (transcode, &error);
+
+ if (error) {
+ brasero_job_error (BRASERO_JOB (transcode), error);
+ return FALSE;
+ }
+
+ if (!result) {
+ brasero_transcode_stop_pipeline (transcode);
+ return FALSE;
+ }
+ }
+
+ brasero_transcode_push_track (transcode);
+ return TRUE;
+}
+
+static void
+foreach_tag (const GstTagList *list,
+ const gchar *tag,
+ BraseroTranscode *transcode)
+{
+ BraseroTrack *track;
+ BraseroJobAction action;
+
+ brasero_job_get_action (BRASERO_JOB (transcode), &action);
+ brasero_job_get_current_track (BRASERO_JOB (transcode), &track);
+
+ BRASERO_JOB_LOG (transcode, "Retrieving tags");
+
+ if (!strcmp (tag, GST_TAG_TITLE)) {
+ if (!brasero_track_tag_lookup_string (track, BRASERO_TRACK_STREAM_TITLE_TAG)) {
+ gchar *title = NULL;
+
+ gst_tag_list_get_string (list, tag, &title);
+ brasero_track_tag_add_string (track,
+ BRASERO_TRACK_STREAM_TITLE_TAG,
+ title);
+ g_free (title);
+ }
+ }
+ else if (!strcmp (tag, GST_TAG_ARTIST)) {
+ if (!brasero_track_tag_lookup_string (track, BRASERO_TRACK_STREAM_ARTIST_TAG)) {
+ gchar *artist = NULL;
+
+ gst_tag_list_get_string (list, tag, &artist);
+ brasero_track_tag_add_string (track,
+ BRASERO_TRACK_STREAM_ARTIST_TAG,
+ artist);
+ g_free (artist);
+ }
+ }
+ else if (!strcmp (tag, GST_TAG_ISRC)) {
+ if (!brasero_track_tag_lookup_int (track, BRASERO_TRACK_STREAM_ISRC_TAG)) {
+ gint isrc = 0;
+
+ gst_tag_list_get_int (list, tag, &isrc);
+ brasero_track_tag_add_int (track,
+ BRASERO_TRACK_STREAM_ARTIST_TAG,
+ isrc);
+ }
+ }
+ else if (!strcmp (tag, GST_TAG_PERFORMER)) {
+ if (!brasero_track_tag_lookup_string (track, BRASERO_TRACK_STREAM_ARTIST_TAG)) {
+ gchar *artist = NULL;
+
+ gst_tag_list_get_string (list, tag, &artist);
+ brasero_track_tag_add_string (track,
+ BRASERO_TRACK_STREAM_ARTIST_TAG,
+ artist);
+ g_free (artist);
+ }
+ }
+ else if (action == BRASERO_JOB_ACTION_SIZE
+ && !strcmp (tag, GST_TAG_DURATION)) {
+ guint64 duration;
+
+ /* this is only useful when we try to have the size */
+ gst_tag_list_get_uint64 (list, tag, &duration);
+ brasero_track_stream_set_boundaries (BRASERO_TRACK_STREAM (track), 0, duration, -1);
+ }
+}
+
+/* NOTE: the return value is whether or not we should stop the bus callback */
+static gboolean
+brasero_transcode_active_state (BraseroTranscode *transcode)
+{
+ BraseroTranscodePrivate *priv;
+ gchar *name, *string, *uri;
+ BraseroJobAction action;
+ BraseroTrack *track;
+
+ priv = BRASERO_TRANSCODE_PRIVATE (transcode);
+
+ if (priv->set_active_state)
+ return TRUE;
+
+ priv->set_active_state = TRUE;
+
+ brasero_job_get_current_track (BRASERO_JOB (transcode), &track);
+ uri = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (track), FALSE);
+
+ brasero_job_get_action (BRASERO_JOB (transcode), &action);
+ if (action == BRASERO_JOB_ACTION_SIZE) {
+ BRASERO_JOB_LOG (transcode,
+ "Analysing Track %s",
+ uri);
+
+ if (priv->mp3_size_pipeline) {
+ /* Run the pipeline till the end */
+ BRASERO_GET_BASENAME_FOR_DISPLAY (uri, name);
+ string = g_strdup_printf (_("Analysing \"%s\""), name);
+ g_free (name);
+
+ brasero_job_set_current_action (BRASERO_JOB (transcode),
+ BRASERO_BURN_ACTION_ANALYSING,
+ string,
+ TRUE);
+ g_free (string);
+
+ brasero_job_start_progress (BRASERO_JOB (transcode), FALSE);
+ g_free (uri);
+ return TRUE;
+ }
+
+ if (brasero_transcode_is_mp3 (transcode)) {
+ GError *error = NULL;
+
+ /* Rebuild another pipeline which is specific to MP3s. */
+ priv->mp3_size_pipeline = TRUE;
+ brasero_transcode_stop_pipeline (transcode);
+
+ if (!brasero_transcode_create_pipeline (transcode, &error))
+ brasero_job_error (BRASERO_JOB (transcode), error);
+ }
+ else
+ brasero_transcode_song_end_reached (transcode);
+
+ g_free (uri);
+ return FALSE;
+ }
+ else {
+ BRASERO_GET_BASENAME_FOR_DISPLAY (uri, name);
+ string = g_strdup_printf (_("Transcoding \"%s\""), name);
+ g_free (name);
+
+ brasero_job_set_current_action (BRASERO_JOB (transcode),
+ BRASERO_BURN_ACTION_TRANSCODING,
+ string,
+ TRUE);
+ g_free (string);
+ brasero_job_start_progress (BRASERO_JOB (transcode), FALSE);
+
+ if (brasero_job_get_fd_out (BRASERO_JOB (transcode), NULL) != BRASERO_BURN_OK) {
+ gchar *dest = NULL;
+
+ brasero_job_get_audio_output (BRASERO_JOB (transcode), &dest);
+ BRASERO_JOB_LOG (transcode,
+ "start decoding %s to %s",
+ uri,
+ dest);
+ }
+ else
+ BRASERO_JOB_LOG (transcode,
+ "start piping %s",
+ uri)
+ }
+
+ g_free (uri);
+ return TRUE;
+}
+
+static gboolean
+brasero_transcode_bus_messages (GstBus *bus,
+ GstMessage *msg,
+ BraseroTranscode *transcode)
+{
+ BraseroTranscodePrivate *priv;
+ GstTagList *tags = NULL;
+ GError *error = NULL;
+ GstState state;
+ gchar *debug;
+
+ priv = BRASERO_TRANSCODE_PRIVATE (transcode);
+ switch (GST_MESSAGE_TYPE (msg)) {
+ case GST_MESSAGE_TAG:
+ /* we use the information to write an .inf file
+ * for the time being just store the information */
+ gst_message_parse_tag (msg, &tags);
+ gst_tag_list_foreach (tags, (GstTagForeachFunc) foreach_tag, transcode);
+ gst_tag_list_free (tags);
+ return TRUE;
+
+ case GST_MESSAGE_ERROR:
+ gst_message_parse_error (msg, &error, &debug);
+ BRASERO_JOB_LOG (transcode, debug);
+ g_free (debug);
+
+ brasero_job_error (BRASERO_JOB (transcode), error);
+ return FALSE;
+
+ case GST_MESSAGE_EOS:
+ brasero_transcode_song_end_reached (transcode);
+ return FALSE;
+
+ case GST_MESSAGE_STATE_CHANGED: {
+ GstStateChangeReturn result;
+
+ result = gst_element_get_state (priv->pipeline,
+ &state,
+ NULL,
+ 1);
+
+ if (result != GST_STATE_CHANGE_SUCCESS)
+ return TRUE;
+
+ if (state == GST_STATE_PLAYING)
+ return brasero_transcode_active_state (transcode);
+
+ break;
+ }
+
+ default:
+ return TRUE;
+ }
+
+ return TRUE;
+}
+
+static void
+brasero_transcode_error_on_pad_linking (BraseroTranscode *self)
+{
+ BraseroTranscodePrivate *priv;
+ GstMessage *message;
+ GstBus *bus;
+
+ priv = BRASERO_TRANSCODE_PRIVATE (self);
+
+ BRASERO_JOB_LOG (self, "Error on pad linking");
+ message = gst_message_new_error (GST_OBJECT (priv->pipeline),
+ g_error_new (BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ /* Translators: This message is sent
+ * when brasero could not link together
+ * two gstreamer plugins so that one
+ * sends its data to the second for further
+ * processing. This data transmission is
+ * done through a pad. Maybe this is a bit
+ * too technical and should be removed? */
+ _("Impossible to link plugin pads")),
+ "Sent by brasero_metadata_error_on_pad_linking");
+
+ bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline));
+ gst_bus_post (bus, message);
+ g_object_unref (bus);
+}
+
+static void
+brasero_transcode_new_decoded_pad_cb (GstElement *decode,
+ GstPad *pad,
+ gboolean arg2,
+ BraseroTranscode *transcode)
+{
+ GstCaps *caps;
+ GstStructure *structure;
+ BraseroTranscodePrivate *priv;
+
+ priv = BRASERO_TRANSCODE_PRIVATE (transcode);
+
+ BRASERO_JOB_LOG (transcode, "New pad");
+
+ /* make sure we only have audio */
+ caps = gst_pad_get_caps (pad);
+ if (!caps)
+ return;
+
+ structure = gst_caps_get_structure (caps, 0);
+ if (structure) {
+ if (g_strrstr (gst_structure_get_name (structure), "audio")) {
+ GstPad *sink;
+ GstElement *queue;
+ GstPadLinkReturn res;
+
+ /* before linking pads (before any data reach grvolume), send tags */
+ brasero_transcode_send_volume_event (transcode);
+
+ /* This is necessary in case there is a video stream
+ * (see brasero-metadata.c). we need to queue to avoid
+ * a deadlock. */
+ queue = gst_element_factory_make ("queue", NULL);
+ gst_bin_add (GST_BIN (priv->pipeline), queue);
+ if (!gst_element_link (queue, priv->link)) {
+ brasero_transcode_error_on_pad_linking (transcode);
+ goto end;
+ }
+
+ sink = gst_element_get_pad (queue, "sink");
+ if (GST_PAD_IS_LINKED (sink)) {
+ brasero_transcode_error_on_pad_linking (transcode);
+ goto end;
+ }
+
+ res = gst_pad_link (pad, sink);
+ if (res == GST_PAD_LINK_OK)
+ gst_element_set_state (queue, GST_STATE_PLAYING);
+ else
+ brasero_transcode_error_on_pad_linking (transcode);
+
+ gst_object_unref (sink);
+ }
+ /* For video streams add a fakesink (see brasero-metadata.c) */
+ else if (g_strrstr (gst_structure_get_name (structure), "video")) {
+ GstPad *sink;
+ GstElement *fakesink;
+ GstPadLinkReturn res;
+
+ BRASERO_JOB_LOG (transcode, "Adding a fakesink for video stream");
+
+ fakesink = gst_element_factory_make ("fakesink", NULL);
+ if (!fakesink) {
+ brasero_transcode_error_on_pad_linking (transcode);
+ goto end;
+ }
+
+ sink = gst_element_get_static_pad (fakesink, "sink");
+ if (!sink) {
+ brasero_transcode_error_on_pad_linking (transcode);
+ gst_object_unref (fakesink);
+ goto end;
+ }
+
+ gst_bin_add (GST_BIN (priv->pipeline), fakesink);
+ res = gst_pad_link (pad, sink);
+
+ if (res == GST_PAD_LINK_OK)
+ gst_element_set_state (fakesink, GST_STATE_PLAYING);
+ else
+ brasero_transcode_error_on_pad_linking (transcode);
+
+ gst_object_unref (sink);
+ }
+ }
+
+end:
+ gst_caps_unref (caps);
+}
+
+static BraseroBurnResult
+brasero_transcode_clock_tick (BraseroJob *job)
+{
+ BraseroTranscodePrivate *priv;
+
+ priv = BRASERO_TRANSCODE_PRIVATE (job);
+
+ if (!priv->pipeline)
+ return BRASERO_BURN_ERR;
+
+ brasero_job_set_written_track (job, priv->pos);
+ return BRASERO_BURN_OK;
+}
+
+static void
+brasero_transcode_class_init (BraseroTranscodeClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ BraseroJobClass *job_class = BRASERO_JOB_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (BraseroTranscodePrivate));
+
+ parent_class = g_type_class_peek_parent (klass);
+ object_class->finalize = brasero_transcode_finalize;
+
+ job_class->start = brasero_transcode_start;
+ job_class->clock_tick = brasero_transcode_clock_tick;
+ job_class->stop = brasero_transcode_stop;
+}
+
+static void
+brasero_transcode_init (BraseroTranscode *obj)
+{ }
+
+static void
+brasero_transcode_finalize (GObject *object)
+{
+ BraseroTranscodePrivate *priv;
+
+ priv = BRASERO_TRANSCODE_PRIVATE (object);
+
+ if (priv->pad_id) {
+ g_source_remove (priv->pad_id);
+ priv->pad_id = 0;
+ }
+
+ brasero_transcode_stop_pipeline (BRASERO_TRANSCODE (object));
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static BraseroBurnResult
+brasero_transcode_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+ GSList *input;
+ GSList *output;
+
+ brasero_plugin_define (plugin,
+ "transcode",
+ _("Transcode converts song files into a format proper to burn them on CDs"),
+ "Philippe Rouquier",
+ 0);
+
+ output = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE|
+ BRASERO_PLUGIN_IO_ACCEPT_PIPE,
+ BRASERO_AUDIO_FORMAT_RAW|
+ BRASERO_AUDIO_FORMAT_44100|
+ BRASERO_METADATA_INFO);
+
+ input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_AUDIO_FORMAT_UNDEFINED|
+ BRASERO_METADATA_INFO);
+
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (output);
+ g_slist_free (input);
+
+ output = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE|
+ BRASERO_PLUGIN_IO_ACCEPT_PIPE,
+ BRASERO_AUDIO_FORMAT_RAW|
+ BRASERO_AUDIO_FORMAT_44100);
+
+ input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_AUDIO_FORMAT_UNDEFINED);
+
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (output);
+ g_slist_free (input);
+
+ return BRASERO_BURN_OK;
+}
diff --git a/plugins/transcode/burn-transcode.h b/plugins/transcode/burn-transcode.h
new file mode 100644
index 0000000..fb42802
--- /dev/null
+++ b/plugins/transcode/burn-transcode.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ * transcode.h
+ *
+ * ven jui 8 16:15:04 2005
+ * Copyright 2005 Philippe Rouquier
+ * Brasero-app wanadoo fr
+ ***************************************************************************/
+
+/*
+ * Brasero is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Brasero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef TRANSCODE_H
+#define TRANSCODE_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_TRANSCODE (brasero_transcode_get_type ())
+#define BRASERO_TRANSCODE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_TRANSCODE, BraseroTranscode))
+#define BRASERO_TRANSCODE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_TRANSCODE, BraseroTranscodeClass))
+#define BRASERO_IS_TRANSCODE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_TRANSCODE))
+#define BRASERO_IS_TRANSCODE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_TRANSCODE))
+#define BRASERO_TRANSCODE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_TRANSCODE, BraseroTranscodeClass))
+
+G_END_DECLS
+
+#endif /* TRANSCODE_H */
diff --git a/plugins/transcode/burn-vob.c b/plugins/transcode/burn-vob.c
new file mode 100644
index 0000000..94f300c
--- /dev/null
+++ b/plugins/transcode/burn-vob.c
@@ -0,0 +1,1269 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * brasero-vob.c
+ * Copyright (C) Rouquier Philippe 2008 <bonfire-app wanadoo fr>
+ *
+ * brasero-vob.c is free software.
+ *
+ * You may redistribute it and/or modify it under the terms of the
+ * GNU General Public License, as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * brasero-vob.c is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with brasero-vob.c. If not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+
+#include <gst/gst.h>
+
+#include "brasero-tags.h"
+#include "burn-job.h"
+#include "brasero-plugin-registration.h"
+#include "burn-vob.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroVob, brasero_vob, BRASERO_TYPE_JOB, BraseroJob);
+
+typedef struct _BraseroVobPrivate BraseroVobPrivate;
+struct _BraseroVobPrivate
+{
+ GstElement *pipeline;
+
+ GstElement *audio;
+ GstElement *video;
+
+ BraseroStreamFormat format;
+
+ guint svcd:1;
+ guint is_video_dvd:1;
+};
+
+#define BRASERO_VOB_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_VOB, BraseroVobPrivate))
+
+static GObjectClass *parent_class = NULL;
+
+
+static void
+brasero_vob_stop_pipeline (BraseroVob *vob)
+{
+ BraseroVobPrivate *priv;
+
+ priv = BRASERO_VOB_PRIVATE (vob);
+ if (!priv->pipeline)
+ return;
+
+ gst_element_set_state (priv->pipeline, GST_STATE_NULL);
+ gst_object_unref (GST_OBJECT (priv->pipeline));
+ priv->pipeline = NULL;
+}
+
+static BraseroBurnResult
+brasero_vob_stop (BraseroJob *job,
+ GError **error)
+{
+ BraseroVobPrivate *priv;
+
+ priv = BRASERO_VOB_PRIVATE (job);
+
+ brasero_vob_stop_pipeline (BRASERO_VOB (job));
+ return BRASERO_BURN_OK;
+}
+
+static void
+brasero_vob_finished (BraseroVob *vob)
+{
+ BraseroTrackType *type = NULL;
+ BraseroTrackStream *track;
+ BraseroVobPrivate *priv;
+ gchar *output = NULL;
+
+ priv = BRASERO_VOB_PRIVATE (vob);
+
+ type = brasero_track_type_new ();
+ brasero_job_get_output_type (BRASERO_JOB (vob), type);
+ brasero_job_get_audio_output (BRASERO_JOB (vob), &output);
+
+ track = brasero_track_stream_new ();
+ brasero_track_stream_set_source (track, output);
+ brasero_track_stream_set_format (track, brasero_track_type_get_stream_format (type));
+
+ brasero_job_add_track (BRASERO_JOB (vob), BRASERO_TRACK (track));
+ g_object_unref (track);
+
+ brasero_track_type_free (type);
+ g_free (output);
+
+ brasero_job_finished_track (BRASERO_JOB (vob));
+}
+
+static gboolean
+brasero_vob_bus_messages (GstBus *bus,
+ GstMessage *msg,
+ BraseroVob *vob)
+{
+ BraseroVobPrivate *priv;
+ GError *error = NULL;
+ gchar *debug;
+
+ priv = BRASERO_VOB_PRIVATE (vob);
+ switch (GST_MESSAGE_TYPE (msg)) {
+ case GST_MESSAGE_TAG:
+ return TRUE;
+
+ case GST_MESSAGE_ERROR:
+ gst_message_parse_error (msg, &error, &debug);
+ BRASERO_JOB_LOG (vob, debug);
+ g_free (debug);
+
+ brasero_job_error (BRASERO_JOB (vob), error);
+ return FALSE;
+
+ case GST_MESSAGE_EOS:
+ BRASERO_JOB_LOG (vob, "Transcoding finished");
+
+ /* add a new track and terminate */
+ brasero_vob_finished (vob);
+ return FALSE;
+
+ case GST_MESSAGE_STATE_CHANGED:
+ break;
+
+ default:
+ return TRUE;
+ }
+
+ return TRUE;
+}
+
+static void
+brasero_vob_new_decoded_pad_cb (GstElement *decode,
+ GstPad *pad,
+ gboolean arg2,
+ BraseroVob *vob)
+{
+ GstPad *sink;
+ GstCaps *caps;
+ GstStructure *structure;
+ BraseroVobPrivate *priv;
+
+ priv = BRASERO_VOB_PRIVATE (vob);
+
+ /* make sure we only have audio */
+ caps = gst_pad_get_caps (pad);
+ if (!caps)
+ return;
+
+ structure = gst_caps_get_structure (caps, 0);
+ if (structure) {
+ if (g_strrstr (gst_structure_get_name (structure), "video")) {
+ sink = gst_element_get_pad (priv->video, "sink");
+ gst_pad_link (pad, sink);
+ gst_object_unref (sink);
+
+ gst_element_set_state (priv->video, GST_STATE_PLAYING);
+ }
+
+ if (g_strrstr (gst_structure_get_name (structure), "audio")) {
+ sink = gst_element_get_pad (priv->audio, "sink");
+ gst_pad_link (pad, sink);
+ gst_object_unref (sink);
+
+ gst_element_set_state (priv->audio, GST_STATE_PLAYING);
+ }
+ }
+
+ gst_caps_unref (caps);
+}
+
+static gboolean
+brasero_vob_link_audio (BraseroVob *vob,
+ GstElement *start,
+ GstElement *end,
+ GstElement *tee,
+ GstElement *muxer)
+{
+ GstPad *srcpad;
+ GstPad *sinkpad;
+ GstPadLinkReturn res;
+
+ srcpad = gst_element_get_request_pad (tee, "src%d");
+ sinkpad = gst_element_get_static_pad (start, "sink");
+ res = gst_pad_link (srcpad, sinkpad);
+ gst_object_unref (sinkpad);
+ gst_object_unref (srcpad);
+
+ BRASERO_JOB_LOG (vob, "Linked audio bin to tee == %d", res);
+ if (res != GST_PAD_LINK_OK)
+ return FALSE;
+
+ sinkpad = gst_element_get_request_pad (muxer, "audio_%d");
+ srcpad = gst_element_get_static_pad (end, "src");
+ res = gst_pad_link (srcpad, sinkpad);
+ gst_object_unref (sinkpad);
+ gst_object_unref (srcpad);
+
+ BRASERO_JOB_LOG (vob, "Linked audio bin to muxer == %d", res);
+ if (res != GST_PAD_LINK_OK)
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+brasero_vob_build_audio_pcm (BraseroVob *vob,
+ GstElement *tee,
+ GstElement *muxer,
+ GError **error)
+{
+ GstElement *queue;
+ GstElement *queue1;
+ GstElement *filter;
+ GstElement *convert;
+ GstCaps *filtercaps;
+ GstElement *resample;
+ BraseroVobPrivate *priv;
+
+ priv = BRASERO_VOB_PRIVATE (vob);
+
+ /* NOTE: this can only be used for Video DVDs as PCM cannot be used for
+ * (S)VCDs. */
+
+ /* queue */
+ queue = gst_element_factory_make ("queue", NULL);
+ if (queue == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ /* Translators: %s is the name of the GstElement that
+ * could not be created */
+ _("%s element could not be created"),
+ "\"Queue\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (priv->pipeline), queue);
+
+ /* audioresample */
+ resample = gst_element_factory_make ("audioresample", NULL);
+ if (resample == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ /* Translators: %s is the name of the GstElement that
+ * could not be created */
+ _("%s element could not be created"),
+ "\"Audioresample\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (priv->pipeline), resample);
+
+ /* audioconvert */
+ convert = gst_element_factory_make ("audioconvert", NULL);
+ if (convert == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ /* Translators: %s is the name of the GstElement that
+ * element could not be created */
+ _("%s element could not be created"),
+ "\"Audioconvert\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (priv->pipeline), convert);
+
+ /* another queue */
+ queue1 = gst_element_factory_make ("queue", NULL);
+ if (queue1 == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Queue1\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (priv->pipeline), queue1);
+
+ /* create a filter */
+ filter = gst_element_factory_make ("capsfilter", NULL);
+ if (filter == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Filter\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (priv->pipeline), filter);
+
+ /* NOTE: what about the number of channels (up to 6) ? */
+ filtercaps = gst_caps_new_full (gst_structure_new ("audio/x-raw-int",
+ "width", G_TYPE_INT, 16,
+ "depth", G_TYPE_INT, 16,
+ "rate", G_TYPE_INT, 48000,
+ NULL),
+ NULL);
+
+ g_object_set (GST_OBJECT (filter), "caps", filtercaps, NULL);
+ gst_caps_unref (filtercaps);
+
+ gst_element_link_many (queue, resample, convert, filter, queue1, NULL);
+ brasero_vob_link_audio (vob, queue, queue1, tee, muxer);
+
+ return TRUE;
+
+error:
+
+ return FALSE;
+}
+
+static gboolean
+brasero_vob_build_audio_mp2 (BraseroVob *vob,
+ GstElement *tee,
+ GstElement *muxer,
+ GError **error)
+{
+ GstElement *queue;
+ GstElement *queue1;
+ GstElement *encode;
+ GstElement *filter;
+ GstElement *convert;
+ GstCaps *filtercaps;
+ GstElement *resample;
+ BraseroVobPrivate *priv;
+
+ priv = BRASERO_VOB_PRIVATE (vob);
+
+ /* queue */
+ queue = gst_element_factory_make ("queue", NULL);
+ if (queue == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Queue\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (priv->pipeline), queue);
+
+ /* audioconvert */
+ convert = gst_element_factory_make ("audioconvert", NULL);
+ if (convert == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Audioconvert\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (priv->pipeline), convert);
+
+ /* audioresample */
+ resample = gst_element_factory_make ("audioresample", NULL);
+ if (resample == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Audioresample\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (priv->pipeline), resample);
+
+ /* encoder */
+ encode = gst_element_factory_make ("ffenc_mp2", NULL);
+ if (encode == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"ffenc_mp2\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (priv->pipeline), encode);
+
+ /* another queue */
+ queue1 = gst_element_factory_make ("queue", NULL);
+ if (queue1 == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Queue1\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (priv->pipeline), queue1);
+
+ /* create a filter */
+ filter = gst_element_factory_make ("capsfilter", NULL);
+ if (filter == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Filter\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (priv->pipeline), filter);
+
+ if (priv->is_video_dvd) {
+ BRASERO_JOB_LOG (vob, "Setting mp2 bitrate to 448000, 48000 khz");
+ g_object_set (encode,
+ "bitrate", 448000, /* it could go up to 912k */
+ NULL);
+
+ /* NOTE: what about the number of channels (up to 7.1) ? */
+ filtercaps = gst_caps_new_full (gst_structure_new ("audio/x-raw-int",
+ "rate", G_TYPE_INT, 48000,
+ NULL),
+ NULL);
+ }
+ else if (!priv->svcd) {
+ /* VCD */
+ BRASERO_JOB_LOG (vob, "Setting mp2 bitrate to 224000, 44100 khz");
+ g_object_set (encode,
+ "bitrate", 224000,
+ NULL);
+
+ /* 2 channels tops */
+ filtercaps = gst_caps_new_full (gst_structure_new ("audio/x-raw-int",
+ "channels", G_TYPE_INT, 2,
+ "rate", G_TYPE_INT, 44100,
+ NULL),
+ NULL);
+ }
+ else {
+ /* SVCDs */
+ BRASERO_JOB_LOG (vob, "Setting mp2 bitrate to 384000, 44100 khz");
+ g_object_set (encode,
+ "bitrate", 384000,
+ NULL);
+
+ /* NOTE: channels up to 5.1 or dual */
+ filtercaps = gst_caps_new_full (gst_structure_new ("audio/x-raw-int",
+ "rate", G_TYPE_INT, 44100,
+ NULL),
+ NULL);
+ }
+
+ g_object_set (GST_OBJECT (filter), "caps", filtercaps, NULL);
+ gst_caps_unref (filtercaps);
+
+ gst_element_link_many (queue, convert, resample, filter, encode, queue1, NULL);
+
+ brasero_vob_link_audio (vob, queue, queue1, tee, muxer);
+ return TRUE;
+
+error:
+
+ return FALSE;
+}
+
+static gboolean
+brasero_vob_build_audio_ac3 (BraseroVob *vob,
+ GstElement *tee,
+ GstElement *muxer,
+ GError **error)
+{
+ GstElement *queue;
+ GstElement *queue1;
+ GstElement *filter;
+ GstElement *encode;
+ GstElement *convert;
+ GstCaps *filtercaps;
+ GstElement *resample;
+ BraseroVobPrivate *priv;
+
+ priv = BRASERO_VOB_PRIVATE (vob);
+
+ /* NOTE: This has to be a DVD since AC3 is not supported by (S)VCD */
+
+ /* queue */
+ queue = gst_element_factory_make ("queue", NULL);
+ if (queue == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Queue\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (priv->pipeline), queue);
+
+ /* audioconvert */
+ convert = gst_element_factory_make ("audioconvert", NULL);
+ if (convert == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Audioconvert\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (priv->pipeline), convert);
+
+ /* audioresample */
+ resample = gst_element_factory_make ("audioresample", NULL);
+ if (resample == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Audioresample\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (priv->pipeline), resample);
+
+ /* create a filter */
+ filter = gst_element_factory_make ("capsfilter", NULL);
+ if (filter == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Filter\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (priv->pipeline), filter);
+
+ BRASERO_JOB_LOG (vob, "Setting AC3 rate to 48000");
+ /* NOTE: we may want to limit the number of channels. */
+ filtercaps = gst_caps_new_full (gst_structure_new ("audio/x-raw-int",
+ "rate", G_TYPE_INT, 48000,
+ NULL),
+ NULL);
+
+ g_object_set (GST_OBJECT (filter), "caps", filtercaps, NULL);
+ gst_caps_unref (filtercaps);
+
+ /* encoder */
+ encode = gst_element_factory_make ("ffenc_ac3", NULL);
+ if (encode == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Ffenc_ac3\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (priv->pipeline), encode);
+
+ BRASERO_JOB_LOG (vob, "Setting AC3 bitrate to 448000");
+ g_object_set (encode,
+ "bitrate", 448000, /* Maximum allowed, is it useful ? */
+ NULL);
+
+ /* another queue */
+ queue1 = gst_element_factory_make ("queue", NULL);
+ if (queue1 == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Queue1\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (priv->pipeline), queue1);
+
+ gst_element_link_many (queue, convert, resample, filter, encode, queue1, NULL);
+ brasero_vob_link_audio (vob, queue, queue1, tee, muxer);
+
+ return TRUE;
+
+error:
+
+ return FALSE;
+}
+
+static GstElement *
+brasero_vob_build_audio_bins (BraseroVob *vob,
+ GstElement *muxer,
+ GError **error)
+{
+ GValue *value;
+ GstElement *tee;
+ BraseroVobPrivate *priv;
+
+ priv = BRASERO_VOB_PRIVATE (vob);
+
+ /* tee */
+ tee = gst_element_factory_make ("tee", NULL);
+ if (tee == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Tee\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (priv->pipeline), tee);
+
+ if (priv->is_video_dvd) {
+ /* Get output format */
+ value = NULL;
+ brasero_job_tag_lookup (BRASERO_JOB (vob),
+ BRASERO_DVD_STREAM_FORMAT,
+ &value);
+
+ if (value)
+ priv->format = g_value_get_int (value);
+
+ if (priv->format == BRASERO_AUDIO_FORMAT_NONE)
+ priv->format = BRASERO_AUDIO_FORMAT_RAW;
+
+ /* FIXME: for the moment even if we use tee, we can't actually
+ * encode and use more than one audio stream */
+ if (priv->format & BRASERO_AUDIO_FORMAT_RAW) {
+ /* PCM : on demand */
+ BRASERO_JOB_LOG (vob, "Adding PCM audio stream");
+ if (!brasero_vob_build_audio_pcm (vob, tee, muxer, error))
+ goto error;
+ }
+
+ if (priv->format & BRASERO_AUDIO_FORMAT_AC3) {
+ /* AC3 : on demand */
+ BRASERO_JOB_LOG (vob, "Adding AC3 audio stream");
+ if (!brasero_vob_build_audio_ac3 (vob, tee, muxer, error))
+ goto error;
+ }
+
+ if (priv->format & BRASERO_AUDIO_FORMAT_MP2) {
+ /* MP2 : on demand */
+ BRASERO_JOB_LOG (vob, "Adding MP2 audio stream");
+ if (!brasero_vob_build_audio_mp2 (vob, tee, muxer, error))
+ goto error;
+ }
+ }
+ else if (!brasero_vob_build_audio_mp2 (vob, tee, muxer, error))
+ goto error;
+
+ return tee;
+
+error:
+ return NULL;
+}
+
+static GstElement *
+brasero_vob_build_video_bin (BraseroVob *vob,
+ GstElement *muxer,
+ GError **error)
+{
+ GValue *value;
+ GstPad *srcpad;
+ GstPad *sinkpad;
+ GstElement *scale;
+ GstElement *queue;
+ GstElement *queue1;
+ GstElement *filter;
+ GstElement *encode;
+ GstPadLinkReturn res;
+ GstElement *framerate;
+ GstElement *colorspace;
+ BraseroVobPrivate *priv;
+ BraseroBurnResult result;
+
+ priv = BRASERO_VOB_PRIVATE (vob);
+
+ queue = gst_element_factory_make ("queue", NULL);
+ if (queue == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Queue\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (priv->pipeline), queue);
+
+ /* framerate and video type control */
+ framerate = gst_element_factory_make ("videorate", NULL);
+ if (framerate == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Framerate\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (priv->pipeline), framerate);
+ g_object_set (framerate,
+ "silent", TRUE,
+ NULL);
+
+ /* size scaling */
+ scale = gst_element_factory_make ("videoscale", NULL);
+ if (scale == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Videoscale\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (priv->pipeline), scale);
+
+ /* create a filter */
+ filter = gst_element_factory_make ("capsfilter", NULL);
+ if (filter == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Filter\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (priv->pipeline), filter);
+
+ colorspace = gst_element_factory_make ("ffmpegcolorspace", NULL);
+ if (colorspace == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Ffmepgcolorspace\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (priv->pipeline), colorspace);
+
+ encode = gst_element_factory_make ("mpeg2enc", NULL);
+ if (encode == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Mpeg2enc\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (priv->pipeline), encode);
+
+ if (priv->is_video_dvd)
+ g_object_set (encode,
+ "format", 8,
+ NULL);
+ else if (priv->svcd) {
+ /* Option to improve compatibility with vcdimager */
+ g_object_set (encode,
+ "dummy-svcd-sof", TRUE,
+ NULL);
+ g_object_set (encode,
+ "format", 4,
+ NULL);
+ }
+ else
+ g_object_set (encode,
+ "format", 1,
+ NULL);
+
+ /* settings */
+ value = NULL;
+ result = brasero_job_tag_lookup (BRASERO_JOB (vob),
+ BRASERO_VIDEO_OUTPUT_FRAMERATE,
+ &value);
+
+ if (result == BRASERO_BURN_OK && value) {
+ gint rate;
+ GstCaps *filtercaps = NULL;
+
+ rate = g_value_get_int (value);
+
+ if (rate == BRASERO_VIDEO_FRAMERATE_NTSC) {
+ g_object_set (encode,
+ "norm", 110,
+ "framerate", 4,
+ NULL);
+
+ if (priv->is_video_dvd)
+ filtercaps = gst_caps_new_full (gst_structure_new ("video/x-raw-yuv",
+ "framerate", GST_TYPE_FRACTION, 30000, 1001,
+ "width", G_TYPE_INT, 720,
+ "height", G_TYPE_INT, 480,
+ NULL),
+ gst_structure_new ("video/x-raw-rgb",
+ "framerate", GST_TYPE_FRACTION, 30000, 1001,
+ "width", G_TYPE_INT, 720,
+ "height", G_TYPE_INT, 480,
+ NULL),
+ NULL);
+ else if (priv->svcd)
+ filtercaps = gst_caps_new_full (gst_structure_new ("video/x-raw-yuv",
+ "framerate", GST_TYPE_FRACTION, 30000, 1001,
+ "width", G_TYPE_INT, 480,
+ "height", G_TYPE_INT, 480,
+ NULL),
+ gst_structure_new ("video/x-raw-rgb",
+ "framerate", GST_TYPE_FRACTION, 30000, 1001,
+ "width", G_TYPE_INT, 480,
+ "height", G_TYPE_INT, 480,
+ NULL),
+ NULL);
+ else
+ filtercaps = gst_caps_new_full (gst_structure_new ("video/x-raw-yuv",
+ "framerate", GST_TYPE_FRACTION, 30000, 1001,
+ "width", G_TYPE_INT, 352,
+ "height", G_TYPE_INT, 240,
+ NULL),
+ gst_structure_new ("video/x-raw-rgb",
+ "framerate", GST_TYPE_FRACTION, 30000, 1001,
+ "width", G_TYPE_INT, 352,
+ "height", G_TYPE_INT, 240,
+ NULL),
+ NULL);
+ }
+ else if (rate == BRASERO_VIDEO_FRAMERATE_PAL_SECAM) {
+ g_object_set (encode,
+ "norm", 112,
+ "framerate", 3,
+ NULL);
+
+ if (priv->is_video_dvd)
+ filtercaps = gst_caps_new_full (gst_structure_new ("video/x-raw-yuv",
+ "framerate", GST_TYPE_FRACTION, 25, 1,
+ "width", G_TYPE_INT, 720,
+ "height", G_TYPE_INT, 576,
+ NULL),
+ gst_structure_new ("video/x-raw-rgb",
+ "framerate", GST_TYPE_FRACTION, 25, 1,
+ "width", G_TYPE_INT, 720,
+ "height", G_TYPE_INT, 576,
+ NULL),
+ NULL);
+ else if (priv->svcd)
+ filtercaps = gst_caps_new_full (gst_structure_new ("video/x-raw-yuv",
+ "framerate", GST_TYPE_FRACTION, 25, 1,
+ "width", G_TYPE_INT, 480,
+ "height", G_TYPE_INT, 576,
+ NULL),
+ gst_structure_new ("video/x-raw-rgb",
+ "framerate", GST_TYPE_FRACTION, 25, 1,
+ "width", G_TYPE_INT, 480,
+ "height", G_TYPE_INT, 576,
+ NULL),
+ NULL);
+ else
+ filtercaps = gst_caps_new_full (gst_structure_new ("video/x-raw-yuv",
+ "framerate", GST_TYPE_FRACTION, 25, 1,
+ "width", G_TYPE_INT, 352,
+ "height", G_TYPE_INT, 288,
+ NULL),
+ gst_structure_new ("video/x-raw-rgb",
+ "framerate", GST_TYPE_FRACTION, 25, 1,
+ "width", G_TYPE_INT, 352,
+ "height", G_TYPE_INT, 288,
+ NULL),
+ NULL);
+ }
+
+ if (filtercaps) {
+ g_object_set (GST_OBJECT (filter), "caps", filtercaps, NULL);
+ gst_caps_unref (filtercaps);
+ }
+ }
+
+ if (priv->is_video_dvd || priv->svcd) {
+ value = NULL;
+ result = brasero_job_tag_lookup (BRASERO_JOB (vob),
+ BRASERO_VIDEO_OUTPUT_ASPECT,
+ &value);
+ if (result == BRASERO_BURN_OK && value) {
+ gint aspect;
+
+ aspect = g_value_get_int (value);
+ if (aspect == BRASERO_VIDEO_ASPECT_4_3) {
+ BRASERO_JOB_LOG (vob, "Setting ration 4:3");
+ g_object_set (encode,
+ "aspect", 2,
+ NULL);
+ }
+ else if (aspect == BRASERO_VIDEO_ASPECT_16_9) {
+ BRASERO_JOB_LOG (vob, "Setting ration 16:9");
+ g_object_set (encode,
+ "aspect", 3,
+ NULL);
+ }
+ }
+ }
+ else {
+ /* VCDs only support 4:3 */
+ BRASERO_JOB_LOG (vob, "Setting ration 4:3");
+ g_object_set (encode,
+ "aspect", 2,
+ NULL);
+ }
+
+ /* another queue */
+ queue1 = gst_element_factory_make ("queue", NULL);
+ if (queue1 == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Queue1\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (priv->pipeline), queue1);
+
+ gst_element_link_many (queue, framerate, scale, colorspace, filter, encode, queue1, NULL);
+
+ srcpad = gst_element_get_static_pad (queue1, "src");
+ sinkpad = gst_element_get_request_pad (muxer, "video_%d");
+ res = gst_pad_link (srcpad, sinkpad);
+ BRASERO_JOB_LOG (vob, "Linked video bin to muxer == %d", res)
+ gst_object_unref (sinkpad);
+ gst_object_unref (srcpad);
+
+ return queue;
+
+error:
+
+ return NULL;
+}
+
+static gboolean
+brasero_vob_build_pipeline (BraseroVob *vob,
+ GError **error)
+{
+ gchar *uri;
+ GstBus *bus;
+ gchar *output;
+ GstElement *sink;
+ GstElement *muxer;
+ GstElement *source;
+ GstElement *decode;
+ BraseroTrack *track;
+ GstElement *pipeline;
+ BraseroVobPrivate *priv;
+
+ priv = BRASERO_VOB_PRIVATE (vob);
+
+ BRASERO_JOB_LOG (vob, "Creating new pipeline");
+
+ pipeline = gst_pipeline_new (NULL);
+ priv->pipeline = pipeline;
+
+ /* source */
+ brasero_job_get_current_track (BRASERO_JOB (vob), &track);
+ uri = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (track), TRUE);
+ source = gst_element_make_from_uri (GST_URI_SRC, uri, NULL);
+ if (source == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Source\"");
+ return FALSE;
+ }
+ gst_bin_add (GST_BIN (pipeline), source);
+ g_object_set (source,
+ "typefind", FALSE,
+ NULL);
+
+ /* decode */
+ decode = gst_element_factory_make ("decodebin", NULL);
+ if (decode == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Decodebin\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (pipeline), decode);
+ gst_element_link_many (source, decode, NULL);
+
+ /* muxer: "mplex" */
+ muxer = gst_element_factory_make ("mplex", NULL);
+ if (muxer == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Mplex\"");
+ goto error;
+ }
+ gst_bin_add (GST_BIN (pipeline), muxer);
+
+ if (priv->is_video_dvd)
+ g_object_set (muxer,
+ "format", 8,
+ NULL);
+ else if (priv->svcd)
+ g_object_set (muxer,
+ "format", 4,
+ NULL);
+ else /* This should be 1 but it causes frame drops */
+ g_object_set (muxer,
+ "format", 4,
+ NULL);
+
+ /* create sink */
+ output = NULL;
+ brasero_job_get_audio_output (BRASERO_JOB (vob), &output);
+ sink = gst_element_factory_make ("filesink", NULL);
+ if (sink == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("%s element could not be created"),
+ "\"Sink\"");
+ return FALSE;
+ }
+ g_object_set (sink,
+ "location", output,
+ NULL);
+
+ gst_bin_add (GST_BIN (pipeline), sink);
+ gst_element_link (muxer, sink);
+
+ /* video encoding */
+ priv->video = brasero_vob_build_video_bin (vob, muxer, error);
+ if (!priv->video)
+ goto error;
+
+ /* audio encoding */
+ priv->audio = brasero_vob_build_audio_bins (vob, muxer, error);
+ if (!priv->audio)
+ goto error;
+
+ /* to be able to link everything */
+ g_signal_connect (G_OBJECT (decode),
+ "new-decoded-pad",
+ G_CALLBACK (brasero_vob_new_decoded_pad_cb),
+ vob);
+
+ /* connect to the bus */
+ bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
+ gst_bus_add_watch (bus,
+ (GstBusFunc) brasero_vob_bus_messages,
+ vob);
+ gst_object_unref (bus);
+
+ return TRUE;
+
+error:
+
+ if (error && (*error))
+ BRASERO_JOB_LOG (vob,
+ "can't create object : %s \n",
+ (*error)->message);
+
+ gst_object_unref (GST_OBJECT (pipeline));
+ return FALSE;
+}
+
+static BraseroBurnResult
+brasero_vob_start (BraseroJob *job,
+ GError **error)
+{
+ BraseroVobPrivate *priv;
+ BraseroJobAction action;
+ BraseroTrackType *output = NULL;
+
+ brasero_job_get_action (job, &action);
+ if (action != BRASERO_JOB_ACTION_IMAGE)
+ return BRASERO_BURN_NOT_SUPPORTED;
+
+ priv = BRASERO_VOB_PRIVATE (job);
+
+ /* get destination medium type */
+ output = brasero_track_type_new ();
+ brasero_job_get_output_type (job, output);
+
+ if (brasero_track_type_get_stream_format (output) & BRASERO_VIDEO_FORMAT_VCD) {
+ GValue *value = NULL;
+
+ priv->is_video_dvd = FALSE;
+ brasero_job_tag_lookup (job,
+ BRASERO_VCD_TYPE,
+ &value);
+ if (value)
+ priv->svcd = (g_value_get_int (value) == BRASERO_SVCD);
+ }
+ else
+ priv->is_video_dvd = TRUE;
+
+ BRASERO_JOB_LOG (job,
+ "Got output type (is DVD %i, is SVCD %i)",
+ priv->is_video_dvd,
+ priv->svcd);
+
+ brasero_track_type_free (output);
+
+ if (!brasero_vob_build_pipeline (BRASERO_VOB (job), error))
+ return BRASERO_BURN_ERR;
+
+ /* ready to go */
+ brasero_job_set_current_action (job,
+ BRASERO_BURN_ACTION_ANALYSING,
+ _("Converting video file to MPEG2"),
+ FALSE);
+ brasero_job_start_progress (job, FALSE);
+
+ gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_vob_clock_tick (BraseroJob *job)
+{
+ gint64 position = 0.0;
+ gint64 duration = 0.0;
+ BraseroVobPrivate *priv;
+ GstFormat format = GST_FORMAT_TIME;
+
+ priv = BRASERO_VOB_PRIVATE (job);
+
+ gst_element_query_duration (priv->pipeline, &format, &duration);
+ gst_element_query_position (priv->pipeline, &format, &position);
+
+ if (duration > 0.0) {
+ gdouble progress;
+
+ progress = (gdouble) position / (gdouble) duration;
+ brasero_job_set_progress (job, progress);
+ }
+
+ return BRASERO_BURN_OK;
+}
+
+static void
+brasero_vob_init (BraseroVob *object)
+{}
+
+static void
+brasero_vob_finalize (GObject *object)
+{
+ BraseroVobPrivate *priv;
+
+ priv = BRASERO_VOB_PRIVATE (object);
+
+ if (priv->pipeline) {
+ gst_object_unref (priv->pipeline);
+ priv->pipeline = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+brasero_vob_class_init (BraseroVobClass *klass)
+{
+ GObjectClass* object_class = G_OBJECT_CLASS (klass);
+ BraseroJobClass* job_class = BRASERO_JOB_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (BraseroVobPrivate));
+
+ object_class->finalize = brasero_vob_finalize;
+
+ job_class->start = brasero_vob_start;
+ job_class->clock_tick = brasero_vob_clock_tick;
+ job_class->stop = brasero_vob_stop;
+}
+
+static BraseroBurnResult
+brasero_vob_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+ GSList *input;
+ GSList *output;
+ GstElement *element;
+
+ /* Let's see if we've got the plugins we need */
+ element = gst_element_factory_make ("ffenc_mpeg2video", NULL);
+ if (!element) {
+ *error = g_strdup_printf (_("%s element could not be created"),
+ "\"ffenc_mpeg2video\"");
+ return BRASERO_BURN_ERR;
+ }
+ gst_object_unref (element);
+
+ element = gst_element_factory_make ("ffenc_ac3", NULL);
+ if (!element) {
+ *error = g_strdup_printf (_("%s element could not be created"),
+ "\"ffenc_ac3\"");
+ return BRASERO_BURN_ERR;
+ }
+ gst_object_unref (element);
+
+ element = gst_element_factory_make ("ffenc_mp2", NULL);
+ if (!element) {
+ *error = g_strdup_printf (_("%s element could not be created"),
+ "\"ffenc_mp2\"");
+ return BRASERO_BURN_ERR;
+ }
+ gst_object_unref (element);
+
+ element = gst_element_factory_make ("mplex", NULL);
+ if (!element) {
+ *error = g_strdup_printf (_("%s element could not be created"),
+ "\"mplex\"");
+ return BRASERO_BURN_ERR;
+ }
+ gst_object_unref (element);
+
+ brasero_plugin_define (plugin,
+ "transcode2vob",
+ _("Vob allows to transcode any video file to a format suitable for video DVDs"),
+ "Philippe Rouquier",
+ 0);
+
+ input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_AUDIO_FORMAT_UNDEFINED|
+ BRASERO_VIDEO_FORMAT_UNDEFINED|
+ BRASERO_METADATA_INFO);
+ output = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_AUDIO_FORMAT_MP2|
+ BRASERO_AUDIO_FORMAT_44100|
+ BRASERO_METADATA_INFO|
+ BRASERO_VIDEO_FORMAT_VCD);
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (output);
+
+ output = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_AUDIO_FORMAT_AC3|
+ BRASERO_AUDIO_FORMAT_MP2|
+ BRASERO_AUDIO_FORMAT_RAW|
+ BRASERO_AUDIO_FORMAT_44100|
+ BRASERO_AUDIO_FORMAT_48000|
+ BRASERO_METADATA_INFO|
+ BRASERO_VIDEO_FORMAT_VIDEO_DVD);
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (output);
+ g_slist_free (input);
+
+ input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_AUDIO_FORMAT_UNDEFINED|
+ BRASERO_VIDEO_FORMAT_UNDEFINED);
+ output = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_AUDIO_FORMAT_MP2|
+ BRASERO_AUDIO_FORMAT_44100|
+ BRASERO_VIDEO_FORMAT_VCD);
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (output);
+
+ output = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_AUDIO_FORMAT_AC3|
+ BRASERO_AUDIO_FORMAT_MP2|
+ BRASERO_AUDIO_FORMAT_RAW|
+ BRASERO_AUDIO_FORMAT_44100|
+ BRASERO_AUDIO_FORMAT_48000|
+ BRASERO_VIDEO_FORMAT_VIDEO_DVD);
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (output);
+ g_slist_free (input);
+ return BRASERO_BURN_OK;
+}
diff --git a/plugins/transcode/burn-vob.h b/plugins/transcode/burn-vob.h
new file mode 100644
index 0000000..5f3caf4
--- /dev/null
+++ b/plugins/transcode/burn-vob.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * brasero-vob.c
+ * Copyright (C) Rouquier Philippe 2008 <bonfire-app wanadoo fr>
+ *
+ * brasero-vob.c is free software.
+ *
+ * You may redistribute it and/or modify it under the terms of the
+ * GNU General Public License, as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * brasero-vob.c is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with brasero-vob.c. If not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _BRASERO_VOB_H_
+#define _BRASERO_VOB_H_
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_VOB (brasero_vob_get_type ())
+#define BRASERO_VOB(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BRASERO_TYPE_VOB, BraseroVob))
+#define BRASERO_VOB_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), BRASERO_TYPE_VOB, BraseroVobClass))
+#define BRASERO_IS_VOB(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BRASERO_TYPE_VOB))
+#define BRASERO_IS_VOB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), BRASERO_TYPE_VOB))
+#define BRASERO_VOB_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), BRASERO_TYPE_VOB, BraseroVobClass))
+
+G_END_DECLS
+
+#endif /* _BRASERO_VOB_H_ */
diff --git a/plugins/vcdimager/Makefile.am b/plugins/vcdimager/Makefile.am
new file mode 100644
index 0000000..465bfce
--- /dev/null
+++ b/plugins/vcdimager/Makefile.am
@@ -0,0 +1,23 @@
+
+INCLUDES = \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/libbrasero-media/ \
+ -I$(top_builddir)/libbrasero-media/ \
+ -I$(top_srcdir)/libbrasero-burn \
+ -I$(top_builddir)/libbrasero-burn/ \
+ -DBRASERO_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
+ -DBRASERO_PREFIX=\"$(prefix)\" \
+ -DBRASERO_SYSCONFDIR=\"$(sysconfdir)\" \
+ -DBRASERO_DATADIR=\"$(datadir)/brasero\" \
+ -DBRASERO_LIBDIR=\"$(libdir)\" \
+ $(DISABLE_DEPRECATED) \
+ $(BRASERO_GLIB_CFLAGS) \
+ $(BRASERO_LIBXML_CFLAGS)
+
+vcdimagerdir = $(libdir)/brasero/plugins
+vcdimager_LTLIBRARIES = libbrasero-vcdimager.la
+
+libbrasero_vcdimager_la_SOURCES = burn-vcdimager.c burn-vcdimager.h
+libbrasero_vcdimager_la_LIBADD = $(BRASERO_GLIB_LIBS) $(BRASERO_LIBXML_LIBS) ../../libbrasero-burn/libbrasero-burn.la
+libbrasero_vcdimager_la_LDFLAGS = -module -avoid-version
+
diff --git a/plugins/vcdimager/burn-vcdimager.c b/plugins/vcdimager/burn-vcdimager.c
new file mode 100644
index 0000000..c5384a1
--- /dev/null
+++ b/plugins/vcdimager/burn-vcdimager.c
@@ -0,0 +1,527 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * brasero
+ * Copyright (C) Philippe Rouquier 2005-2008 <bonfire-app wanadoo fr>
+ *
+ * brasero is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * brasero is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+#include <gmodule.h>
+
+#include <libxml/xmlerror.h>
+#include <libxml/xmlwriter.h>
+#include <libxml/parser.h>
+#include <libxml/xmlstring.h>
+#include <libxml/uri.h>
+
+#include "brasero-tags.h"
+#include "brasero-plugin-registration.h"
+#include "burn-job.h"
+#include "burn-process.h"
+#include "burn-vcdimager.h"
+#include "brasero-track-stream.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroVcdImager, brasero_vcd_imager, BRASERO_TYPE_PROCESS, BraseroProcess);
+
+typedef struct _BraseroVcdImagerPrivate BraseroVcdImagerPrivate;
+struct _BraseroVcdImagerPrivate
+{
+ guint num_tracks;
+
+ guint svcd:1;
+};
+
+#define BRASERO_VCD_IMAGER_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_VCD_IMAGER, BraseroVcdImagerPrivate))
+
+static BraseroProcessClass *parent_class = NULL;
+
+static BraseroBurnResult
+brasero_vcd_imager_read_stdout (BraseroProcess *process,
+ const gchar *line)
+{
+ gint percent = 0;
+ guint track_num = 0;
+ BraseroVcdImagerPrivate *priv;
+
+ priv = BRASERO_VCD_IMAGER_PRIVATE (process);
+
+ if (sscanf (line, "#scan[track-%d]: %*d/%*d (%d)", &track_num, &percent) == 2) {
+ brasero_job_start_progress (BRASERO_JOB (process), FALSE);
+ brasero_job_set_progress (BRASERO_JOB (process),
+ (gdouble) ((gdouble) percent) /
+ 100.0 /
+ (gdouble) (priv->num_tracks + 1) +
+ (gdouble) (track_num) /
+ (gdouble) (priv->num_tracks + 1));
+ }
+ else if (sscanf (line, "#write[%*d/%*d]: %*d/%*d (%d)", &percent) == 1) {
+ gdouble progress;
+
+ /* NOTE: percent can be over 100% ???? */
+ brasero_job_start_progress (BRASERO_JOB (process), FALSE);
+ progress = (gdouble) ((gdouble) percent) /
+ 100.0 /
+ (gdouble) (priv->num_tracks + 1) +
+ (gdouble) (priv->num_tracks) /
+ (gdouble) (priv->num_tracks + 1);
+
+ if (progress > 1.0)
+ progress = 1.0;
+
+ brasero_job_set_progress (BRASERO_JOB (process), progress);
+ }
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_vcd_imager_read_stderr (BraseroProcess *process,
+ const gchar *line)
+{
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_vcd_imager_generate_xml_file (BraseroProcess *process,
+ const gchar *path,
+ GError **error)
+{
+ BraseroVcdImagerPrivate *priv;
+ GSList *tracks = NULL;
+ xmlTextWriter *xml;
+ gchar buffer [64];
+ gint success;
+ GSList *iter;
+ gchar *name;
+ gint i;
+
+ BRASERO_JOB_LOG (process, "Creating (S)VCD layout xml file (%s)", path);
+
+ xml = xmlNewTextWriterFilename (path, 0);
+ if (!xml)
+ return BRASERO_BURN_ERR;
+
+ priv = BRASERO_VCD_IMAGER_PRIVATE (process);
+
+ xmlTextWriterSetIndent (xml, 1);
+ xmlTextWriterSetIndentString (xml, (xmlChar *) "\t");
+
+ success = xmlTextWriterStartDocument (xml,
+ NULL,
+ "UTF8",
+ NULL);
+ if (success < 0)
+ goto error;
+
+ success = xmlTextWriterWriteDTD (xml,
+ (xmlChar *) "videocd",
+ (xmlChar *) "-//GNU//DTD VideoCD//EN",
+ (xmlChar *) "http://www.gnu.org/software/vcdimager/videocd.dtd",
+ (xmlChar *) NULL);
+ if (success < 0)
+ goto error;
+
+ /* let's start */
+ success = xmlTextWriterStartElement (xml, (xmlChar *) "videocd");
+ if (success < 0)
+ goto error;
+
+ success = xmlTextWriterWriteAttribute (xml,
+ (xmlChar *) "xmlns",
+ (xmlChar *) "http://www.gnu.org/software/vcdimager/1.0/");
+ if (success < 0)
+ goto error;
+
+ if (priv->svcd)
+ success = xmlTextWriterWriteAttribute (xml,
+ (xmlChar *) "class",
+ (xmlChar *) "svcd");
+ else
+ success = xmlTextWriterWriteAttribute (xml,
+ (xmlChar *) "class",
+ (xmlChar *) "vcd");
+
+ if (success < 0)
+ goto error;
+
+ if (priv->svcd)
+ success = xmlTextWriterWriteAttribute (xml,
+ (xmlChar *) "version",
+ (xmlChar *) "1.0");
+ else
+ success = xmlTextWriterWriteAttribute (xml,
+ (xmlChar *) "version",
+ (xmlChar *) "2.0");
+ if (success < 0)
+ goto error;
+
+ /* info part */
+ success = xmlTextWriterStartElement (xml, (xmlChar *) "info");
+ if (success < 0)
+ goto error;
+
+ /* name of the volume */
+ name = NULL;
+ brasero_job_get_audio_title (BRASERO_JOB (process), &name);
+ success = xmlTextWriterWriteElement (xml,
+ (xmlChar *) "album-id",
+ (xmlChar *) name);
+ g_free (name);
+ if (success < 0)
+ goto error;
+
+ /* number of CDs */
+ success = xmlTextWriterWriteElement (xml,
+ (xmlChar *) "volume-count",
+ (xmlChar *) "1");
+ if (success < 0)
+ goto error;
+
+ /* CD number */
+ success = xmlTextWriterWriteElement (xml,
+ (xmlChar *) "volume-number",
+ (xmlChar *) "1");
+ if (success < 0)
+ goto error;
+
+ /* close info part */
+ success = xmlTextWriterEndElement (xml);
+ if (success < 0)
+ goto error;
+
+ /* Primary Volume descriptor */
+ success = xmlTextWriterStartElement (xml, (xmlChar *) "pvd");
+ if (success < 0)
+ goto error;
+
+ /* NOTE: no need to convert a possible non compliant name as this will
+ * be done by vcdimager. */
+ name = NULL;
+ brasero_job_get_audio_title (BRASERO_JOB (process), &name);
+ success = xmlTextWriterWriteElement (xml,
+ (xmlChar *) "volume-id",
+ (xmlChar *) name);
+ g_free (name);
+ if (success < 0)
+ goto error;
+
+ /* Makes it CD-i compatible */
+ success = xmlTextWriterWriteElement (xml,
+ (xmlChar *) "system-id",
+ (xmlChar *) "CD-RTOS CD-BRIDGE");
+ if (success < 0)
+ goto error;
+
+ /* Close Primary Volume descriptor */
+ success = xmlTextWriterEndElement (xml);
+ if (success < 0)
+ goto error;
+
+ /* the tracks */
+ success = xmlTextWriterStartElement (xml, (xmlChar *) "sequence-items");
+ if (success < 0)
+ goto error;
+
+ /* get all tracks */
+ brasero_job_get_tracks (BRASERO_JOB (process), &tracks);
+ priv->num_tracks = g_slist_length (tracks);
+ for (i = 0, iter = tracks; iter; iter = iter->next, i++) {
+ BraseroTrack *track;
+ gchar *video;
+
+ track = iter->data;
+ success = xmlTextWriterStartElement (xml, (xmlChar *) "sequence-item");
+ if (success < 0)
+ goto error;
+
+ video = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (track), FALSE);
+ success = xmlTextWriterWriteAttribute (xml,
+ (xmlChar *) "src",
+ (xmlChar *) video);
+ g_free (video);
+
+ if (success < 0)
+ goto error;
+
+ sprintf (buffer, "track-%i", i);
+ success = xmlTextWriterWriteAttribute (xml,
+ (xmlChar *) "id",
+ (xmlChar *) buffer);
+ if (success < 0)
+ goto error;
+
+ /* close sequence-item */
+ success = xmlTextWriterEndElement (xml);
+ if (success < 0)
+ goto error;
+ }
+
+ /* sequence-items */
+ success = xmlTextWriterEndElement (xml);
+ if (success < 0)
+ goto error;
+
+ /* the navigation */
+ success = xmlTextWriterStartElement (xml, (xmlChar *) "pbc");
+ if (success < 0)
+ goto error;
+
+ /* get all tracks */
+ brasero_job_get_tracks (BRASERO_JOB (process), &tracks);
+ for (i = 0, iter = tracks; iter; iter = iter->next, i++) {
+ BraseroTrack *track;
+
+ track = iter->data;
+
+ sprintf (buffer, "playlist-%i", i);
+ success = xmlTextWriterStartElement (xml, (xmlChar *) "playlist");
+ if (success < 0)
+ goto error;
+
+ success = xmlTextWriterWriteAttribute (xml,
+ (xmlChar *) "id",
+ (xmlChar *) buffer);
+ if (success < 0)
+ goto error;
+
+ success = xmlTextWriterWriteElement (xml,
+ (xmlChar *) "wait",
+ (xmlChar *) "0");
+ if (success < 0)
+ goto error;
+
+ success = xmlTextWriterStartElement (xml, (xmlChar *) "play-item");
+ if (success < 0)
+ goto error;
+
+ sprintf (buffer, "track-%i", i);
+ success = xmlTextWriterWriteAttribute (xml,
+ (xmlChar *) "ref",
+ (xmlChar *) buffer);
+ if (success < 0)
+ goto error;
+
+ /* play-item */
+ success = xmlTextWriterEndElement (xml);
+ if (success < 0)
+ goto error;
+
+ /* playlist */
+ success = xmlTextWriterEndElement (xml);
+ if (success < 0)
+ goto error;
+ }
+
+ /* pbc */
+ success = xmlTextWriterEndElement (xml);
+ if (success < 0)
+ goto error;
+
+ /* close videocd */
+ success = xmlTextWriterEndElement (xml);
+ if (success < 0)
+ goto error;
+
+ xmlTextWriterEndDocument (xml);
+ xmlFreeTextWriter (xml);
+
+ return BRASERO_BURN_OK;
+
+error:
+
+ BRASERO_JOB_LOG (process, "Error");
+
+ /* close everything */
+ xmlTextWriterEndDocument (xml);
+ xmlFreeTextWriter (xml);
+
+ /* FIXME: get the error */
+
+ return BRASERO_BURN_ERR;
+}
+
+static BraseroBurnResult
+brasero_vcd_imager_set_argv (BraseroProcess *process,
+ GPtrArray *argv,
+ GError **error)
+{
+ BraseroVcdImagerPrivate *priv;
+ BraseroBurnResult result;
+ BraseroJobAction action;
+ BraseroMedia medium;
+ gchar *output;
+ gchar *image;
+ gchar *toc;
+
+ priv = BRASERO_VCD_IMAGER_PRIVATE (process);
+
+ brasero_job_get_action (BRASERO_JOB (process), &action);
+ if (action != BRASERO_JOB_ACTION_IMAGE)
+ BRASERO_JOB_NOT_SUPPORTED (process);
+
+ g_ptr_array_add (argv, g_strdup ("vcdxbuild"));
+
+ g_ptr_array_add (argv, g_strdup ("--progress"));
+ g_ptr_array_add (argv, g_strdup ("-v"));
+
+ /* specifies output */
+ image = toc = NULL;
+ brasero_job_get_image_output (BRASERO_JOB (process),
+ &image,
+ &toc);
+
+ g_ptr_array_add (argv, g_strdup ("-c"));
+ g_ptr_array_add (argv, toc);
+ g_ptr_array_add (argv, g_strdup ("-b"));
+ g_ptr_array_add (argv, image);
+
+ /* get temporary file to write XML */
+ result = brasero_job_get_tmp_file (BRASERO_JOB (process),
+ NULL,
+ &output,
+ error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+
+ g_ptr_array_add (argv, output);
+
+ brasero_job_get_media (BRASERO_JOB (process), &medium);
+ if (medium & BRASERO_MEDIUM_CD) {
+ GValue *value = NULL;
+
+ brasero_job_tag_lookup (BRASERO_JOB (process),
+ BRASERO_VCD_TYPE,
+ &value);
+ if (value)
+ priv->svcd = (g_value_get_int (value) == BRASERO_SVCD);
+ }
+
+ result = brasero_vcd_imager_generate_xml_file (process, output, error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+
+ brasero_job_set_current_action (BRASERO_JOB (process),
+ BRASERO_BURN_ACTION_CREATING_IMAGE,
+ _("Creating file layout"),
+ FALSE);
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_vcd_imager_post (BraseroJob *job)
+{
+ BraseroVcdImagerPrivate *priv;
+
+ priv = BRASERO_VCD_IMAGER_PRIVATE (job);
+ return brasero_job_finished_session (job);
+}
+
+static void
+brasero_vcd_imager_init (BraseroVcdImager *object)
+{}
+
+static void
+brasero_vcd_imager_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+brasero_vcd_imager_class_init (BraseroVcdImagerClass *klass)
+{
+ GObjectClass* object_class = G_OBJECT_CLASS (klass);
+ BraseroProcessClass* process_class = BRASERO_PROCESS_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (BraseroVcdImagerPrivate));
+
+ object_class->finalize = brasero_vcd_imager_finalize;
+ process_class->stdout_func = brasero_vcd_imager_read_stdout;
+ process_class->stderr_func = brasero_vcd_imager_read_stderr;
+ process_class->set_argv = brasero_vcd_imager_set_argv;
+ process_class->post = brasero_vcd_imager_post;
+}
+
+static BraseroBurnResult
+brasero_vcd_imager_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+ BraseroBurnResult result;
+ GSList *output;
+ GSList *input;
+
+ /* NOTE: it seems that cdrecord can burn cue files on the fly */
+ brasero_plugin_define (plugin,
+ "vcdimager",
+ _("Use vcdimager to create SVCDs"),
+ "Philippe Rouquier",
+ 1);
+
+ /* First see if this plugin can be used */
+ result = brasero_process_check_path ("vcdimager", error);
+ if (result != BRASERO_BURN_OK)
+ return result;
+
+ input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_AUDIO_FORMAT_MP2|
+ BRASERO_AUDIO_FORMAT_44100|
+ BRASERO_VIDEO_FORMAT_VCD|
+ BRASERO_METADATA_INFO);
+
+ output = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_IMAGE_FORMAT_CUE);
+
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (input);
+
+ input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_AUDIO_FORMAT_MP2|
+ BRASERO_AUDIO_FORMAT_44100|
+ BRASERO_VIDEO_FORMAT_VCD);
+
+ brasero_plugin_link_caps (plugin, output, input);
+ g_slist_free (output);
+ g_slist_free (input);
+
+ /* we only support CDs they must be blank */
+ brasero_plugin_set_flags (plugin,
+ BRASERO_MEDIUM_CDRW|
+ BRASERO_MEDIUM_BLANK|
+ BRASERO_MEDIUM_CLOSED|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_HAS_DATA|
+ BRASERO_MEDIUM_HAS_AUDIO,
+ BRASERO_BURN_FLAG_NONE,
+ BRASERO_BURN_FLAG_NONE);
+
+ brasero_plugin_set_flags (plugin,
+ BRASERO_MEDIUM_FILE|
+ BRASERO_MEDIUM_CDR|
+ BRASERO_MEDIUM_BLANK|
+ BRASERO_MEDIUM_APPENDABLE|
+ BRASERO_MEDIUM_HAS_DATA|
+ BRASERO_MEDIUM_HAS_AUDIO,
+ BRASERO_BURN_FLAG_NONE,
+ BRASERO_BURN_FLAG_NONE);
+ return BRASERO_BURN_OK;
+}
+
diff --git a/plugins/vcdimager/burn-vcdimager.h b/plugins/vcdimager/burn-vcdimager.h
new file mode 100644
index 0000000..f50343c
--- /dev/null
+++ b/plugins/vcdimager/burn-vcdimager.h
@@ -0,0 +1,36 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * brasero
+ * Copyright (C) Philippe Rouquier 2005-2008 <bonfire-app wanadoo fr>
+ *
+ * brasero is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * brasero is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _BRASERO_VCD_IMAGER_H_
+#define _BRASERO_VCD_IMAGER_H_
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_VCD_IMAGER (brasero_vcd_imager_get_type ())
+#define BRASERO_VCD_IMAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BRASERO_TYPE_VCD_IMAGER, BraseroVcdImager))
+#define BRASERO_VCD_IMAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), BRASERO_TYPE_VCD_IMAGER, BraseroVcdImagerClass))
+#define BRASERO_IS_VCD_IMAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BRASERO_TYPE_VCD_IMAGER))
+#define BRASERO_IS_VCD_IMAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), BRASERO_TYPE_VCD_IMAGER))
+#define BRASERO_VCD_IMAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), BRASERO_TYPE_VCD_IMAGER, BraseroVcdImagerClass))
+
+G_END_DECLS
+
+#endif /* _BRASERO_VCD_IMAGER_H_ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]