File 0001-comics-Optionally-use-libgsf-for-reading-comics.patch of Package mingw64-evince

From 92ef94e923cbc4de5d3ea38beeaaec394ce1eba7 Mon Sep 17 00:00:00 2001
From: Hib Eris <hib@hiberis.nl>
Date: Wed, 21 Jul 2010 14:08:57 +0200
Subject: [PATCH] [comics] (Optionally) use libgsf for reading comics

---
 backend/comics/Makefile.am       |    4 +-
 backend/comics/comics-document.c |  405 +++++++++++++++++++++++++++++++++-----
 configure.ac                     |   14 ++
 3 files changed, 374 insertions(+), 49 deletions(-)

diff --git a/backend/comics/Makefile.am b/backend/comics/Makefile.am
index 3d56cd7..960342e 100644
--- a/backend/comics/Makefile.am
+++ b/backend/comics/Makefile.am
@@ -3,7 +3,7 @@ INCLUDES =                      		\
 	-I$(top_srcdir)/libdocument 		\
 	-DGNOMELOCALEDIR=\"$(datadir)/locale\"	\
 	-DEVINCE_COMPILATION			\
-	$(BACKEND_CFLAGS)			\
+	$(COMICS_CFLAGS)			\
 	$(LIB_CFLAGS)				\
 	$(WARN_CFLAGS)				\
 	$(DISABLE_DEPRECATED)
@@ -17,7 +17,7 @@ libcomicsdocument_la_SOURCES = \
 libcomicsdocument_la_LDFLAGS = $(BACKEND_LIBTOOL_FLAGS)
 libcomicsdocument_la_LIBADD =				\
 	$(top_builddir)/libdocument/libevdocument.la	\
-	$(BACKEND_LIBS)					\
+	$(COMICS_LIBS)					\
 	$(LIB_LIBS)
 
 backend_in_files = comicsdocument.evince-backend.in
diff --git a/backend/comics/comics-document.c b/backend/comics/comics-document.c
index 4d74385..fbd75b6 100644
--- a/backend/comics/comics-document.c
+++ b/backend/comics/comics-document.c
@@ -30,6 +30,14 @@
 #include <glib/gstdio.h>
 #include <gio/gio.h>
 
+#if WITH_LIBGSF
+#include <gsf/gsf.h>
+#include <gsf/gsf-input-gio.h>
+#include <gsf/gsf-infile.h>
+#include <gsf/gsf-infile-zip.h>
+#include <gsf/gsf-infile-tar.h>
+#endif
+
 #ifdef G_OS_WIN32
 # define WIFEXITED(x) ((x) != 3)
 # define WEXITSTATUS(x) (x)
@@ -54,6 +62,15 @@
 
 typedef enum
 {
+	TYPE_INVALID,
+	TYPE_ZIP,
+	TYPE_TAR,
+	TYPE_P7ZIP,
+	TYPE_RAR
+} ComicBookType;
+
+typedef enum
+{
 	RARLABS,
 	GNAUNRAR,
 	UNZIP,
@@ -72,8 +89,10 @@ struct _ComicsDocument
 {
 	EvDocument parent_instance;
 
+	ComicBookType type;
 	gchar    *archive, *dir;
 	GPtrArray *page_names;
+	GPtrArray *pages;
 	gchar    *selected_command, *alternative_command;
 	gchar    *extract_command, *list_command, *decompress_tmp;
 	gboolean regex_arg;
@@ -135,6 +154,54 @@ static void       render_pixbuf_size_prepared_cb (GdkPixbufLoader *loader,
 static char**     extract_argv                   (EvDocument *document,
 						  gint page);
 
+static ComicBookType
+comics_document_get_comics_type (const char *uri,
+				 GError    **error)
+{
+	ComicBookType type;
+
+	gchar *mime_type;
+	GError *err;
+
+	mime_type = ev_file_get_mime_type (uri, FALSE, &err);
+	if (!mime_type) {
+		if (err) {
+			g_propagate_error (error, err);
+		} else {
+			g_set_error_literal (error,
+					     EV_DOCUMENT_ERROR,
+					     EV_DOCUMENT_ERROR_INVALID,
+					     _("Unknown MIME Type"));
+		}
+		return TYPE_INVALID;
+	}
+	
+	/* FIXME, use proper cbr/cbz mime types once they're
+	 * included in shared-mime-info */
+	if (!strcmp (mime_type, "application/x-cbz") ||
+	    !strcmp (mime_type, "application/zip")) {
+		type = TYPE_ZIP;
+	} else if (!strcmp (mime_type, "application/x-cbt") ||
+		   !strcmp (mime_type, "application/x-tar")) {
+		type = TYPE_TAR;
+	} else if (!strcmp (mime_type, "application/x-cb7") ||
+		   !strcmp (mime_type, "application/x-7z-compressed")) {
+		type = TYPE_P7ZIP;
+	} else if (!strcmp (mime_type, "application/x-cbr") ||
+		   !strcmp (mime_type, "application/x-rar")) {
+		type = TYPE_RAR;
+	} else {
+		g_set_error (error,
+			     EV_DOCUMENT_ERROR,
+			     EV_DOCUMENT_ERROR_INVALID,
+			     _("Not a comic book MIME type: %s"),
+			     mime_type);
+		type = TYPE_INVALID;
+	}
+
+	g_free (mime_type);
+	return type;
+}
 
 EV_BACKEND_REGISTER_WITH_CODE (ComicsDocument, comics_document,
 	{
@@ -307,20 +374,18 @@ comics_generate_command_lines (ComicsDocument *comics_document,
 /* This function chooses an external command for decompressing a comic 
  * book based on its mime tipe. */
 static gboolean 
-comics_check_decompress_command	(gchar          *mime_type, 
-				 ComicsDocument *comics_document,
-				 GError         **error)
+comics_check_decompress_command (ComicsDocument *comics_document,
+				 ComicBookType   type,
+				 GError        **error)
 {
 	gboolean success;
 	gchar *std_out, *std_err;
 	gint retval;
 	GError *err = NULL;
 	
-	/* FIXME, use proper cbr/cbz mime types once they're
-	 * included in shared-mime-info */
-	
-	if (!strcmp (mime_type, "application/x-cbr") ||
-	    !strcmp (mime_type, "application/x-rar")) {
+	switch (type) {
+
+	case TYPE_RAR:
 	        /* The RARLAB provides a no-charge proprietary (freeware) 
 	        * decompress-only client for Linux called unrar. Another 
 		* option is a GPLv2-licensed command-line tool developed by 
@@ -368,9 +433,9 @@ comics_check_decompress_command	(gchar          *mime_type,
 			comics_document->command_usage = GNAUNRAR;
 			return TRUE;
 		}
+		break;
 
-	} else if (!strcmp (mime_type, "application/x-cbz") ||
-		   !strcmp (mime_type, "application/zip")) {
+	case TYPE_ZIP:
 		/* InfoZIP's unzip program */
 		comics_document->selected_command = 
 				g_find_program_in_path ("unzip");
@@ -381,9 +446,9 @@ comics_check_decompress_command	(gchar          *mime_type,
 			comics_document->command_usage = UNZIP;
 			return TRUE;
 		}
+		break;
 
-	} else if (!strcmp (mime_type, "application/x-cb7") ||
-		   !strcmp (mime_type, "application/x-7z-compressed")) {
+	case TYPE_P7ZIP:
 		/* 7zr, 7za and 7z are the commands from the p7zip project able 
 		 * to decompress .7z files */ 
 			comics_document->selected_command = 
@@ -404,8 +469,9 @@ comics_check_decompress_command	(gchar          *mime_type,
 				comics_document->command_usage = P7ZIP;
 				return TRUE;
 			}
-	} else if (!strcmp (mime_type, "application/x-cbt") ||
-		   !strcmp (mime_type, "application/x-tar")) {
+		break;
+
+	case TYPE_TAR:
 		/* tar utility (Tape ARchive) */
 		comics_document->selected_command =
 				g_find_program_in_path ("tar");
@@ -413,14 +479,13 @@ comics_check_decompress_command	(gchar          *mime_type,
 			comics_document->command_usage = TAR;
 			return TRUE;
 		}
-	} else {
-		g_set_error (error,
-			     EV_DOCUMENT_ERROR,
-			     EV_DOCUMENT_ERROR_INVALID,
-			     _("Not a comic book MIME type: %s"),
-			     mime_type);
-			     return FALSE;
+		break;
+
+	default:
+		g_warning (_("Invalid comic book type"));
+		break;
 	}
+
 	g_set_error_literal (error,
 			     EV_DOCUMENT_ERROR,
 			     EV_DOCUMENT_ERROR_INVALID,
@@ -436,49 +501,119 @@ sort_page_names (gconstpointer a,
   return strcmp (* (const char **) a, * (const char **) b);
 }
 
+#if WITH_LIBGSF
+static void
+get_pages_gsf (GsfInput   *source,
+	       GSList     *supported_extensions,
+	       GPtrArray **pages)
+{
+	GsfInfile *infile = GSF_IS_INFILE (source) ? GSF_INFILE (source) : NULL;
+	GsfInput *child;
+	int i, n;
+
+	n = infile ? gsf_infile_num_children (infile): 0;
+	if (n > 0) {
+		GPtrArray *page_names = g_ptr_array_sized_new (n);
+		for (i = 0; i < n; i++) {
+			child = gsf_infile_child_by_index (infile, i);
+                        g_ptr_array_add (page_names,
+					 g_strdup (gsf_input_name (child)));
+			g_object_unref (child);
+		}
+		g_ptr_array_sort (page_names, sort_page_names);
+
+		for (i = 0; i < page_names->len; i++) {
+			child = gsf_infile_child_by_name (infile,
+					(char const*) page_names->pdata[i]);
+			get_pages_gsf (child, supported_extensions, pages);
+			g_object_unref (child);
+		}
+		g_ptr_array_foreach (page_names, (GFunc) g_free, NULL);
+		g_ptr_array_free (page_names, TRUE);
+	} else {
+		gchar *suffix = g_strrstr (gsf_input_name (source), ".");
+		if (suffix) {
+			suffix = g_ascii_strdown (suffix + 1, -1);
+			if (g_slist_find_custom (supported_extensions, suffix,
+					 (GCompareFunc) strcmp) != NULL) {
+				g_object_ref (source);
+				g_ptr_array_add (*pages, source);
+			}
+			g_free (suffix);
+		}
+	}
+}
+
 static gboolean
-comics_document_load (EvDocument *document,
+comics_document_load_gsf (EvDocument *document,
+			  const char *uri,
+			  GError    **error)
+{
+	ComicsDocument *comics_document = COMICS_DOCUMENT (document);
+	GsfInput *source;
+	GsfInfile *infile;
+	GSList *supported_extensions;
+
+	source = gsf_input_gio_new_for_uri (uri, error);
+	if (!source)
+		return FALSE;
+
+	switch (comics_document->type) {
+	case TYPE_ZIP:
+		infile = gsf_infile_zip_new (source, error);
+		break;
+	case TYPE_TAR:
+		infile = gsf_infile_tar_new (source, error);
+		break;
+	default:
+		g_warning (_("Invalid comic book type"));
+		g_set_error_literal (error,
+			     EV_DOCUMENT_ERROR,
+			     EV_DOCUMENT_ERROR_INVALID,
+			     _("Can't find an appropriate command to "
+			     "decompress this type of comic book"));
+		g_object_unref (source);
+		return FALSE;
+	}
+	g_object_unref (source);
+	if (!infile)
+		return FALSE;
+
+	comics_document->pages = g_ptr_array_sized_new (64);
+
+	supported_extensions = get_supported_image_extensions ();
+	get_pages_gsf (GSF_INPUT (infile), supported_extensions, &(comics_document->pages));
+	g_slist_foreach (supported_extensions, (GFunc) g_free, NULL);
+	g_slist_free (supported_extensions);
+	g_object_unref (infile);
+
+	return TRUE;
+}
+#endif
+
+static gboolean
+comics_document_load_external (EvDocument *document,
 		      const char *uri,
 		      GError    **error)
 {
 	ComicsDocument *comics_document = COMICS_DOCUMENT (document);
 	GSList *supported_extensions;
 	gchar *std_out;
-	gchar *mime_type;
 	gchar **cb_files, *cb_file;
 	gboolean success;
 	int i, retval;
-	GError *err = NULL;
 
 	comics_document->archive = g_filename_from_uri (uri, NULL, error);
 	if (!comics_document->archive)
 		return FALSE;
 
-	mime_type = ev_file_get_mime_type (uri, FALSE, &err);
-	if (!mime_type) {
-		if (err) {
-			g_propagate_error (error, err);
-		} else {
-			g_set_error_literal (error,
-					     EV_DOCUMENT_ERROR,
-					     EV_DOCUMENT_ERROR_INVALID,
-					     _("Unknown MIME Type"));
-		}
-
-		return FALSE;
-	}
-	
-	if (!comics_check_decompress_command (mime_type, comics_document, 
-	error)) {	
-		g_free (mime_type);
+	if (!comics_check_decompress_command (comics_document,
+				comics_document->type, error)) {
 		return FALSE;
 	} else if (!comics_generate_command_lines (comics_document, error)) {
-		   g_free (mime_type);
 		return FALSE;
 	}
 
-	g_free (mime_type);
-
 	/* Get list of files in archive */
 	success = g_spawn_command_line_sync (comics_document->list_command,
 					     &std_out, NULL, &retval, error);
@@ -552,6 +687,31 @@ comics_document_load (EvDocument *document,
 	return TRUE;
 }
 
+static gboolean
+comics_document_load (EvDocument *document,
+		      const char *uri,
+		      GError    **error)
+{
+	ComicsDocument *comics_document = COMICS_DOCUMENT (document);
+
+	comics_document->type = comics_document_get_comics_type (uri, error);
+	if (comics_document->type == TYPE_INVALID)
+		return FALSE;
+
+#if WITH_LIBGSF
+	switch (comics_document->type) {
+
+	case TYPE_ZIP:
+	case TYPE_TAR:
+		return comics_document_load_gsf (document, uri, error);
+		break;
+	default:
+		;
+	}
+#endif
+
+	return comics_document_load_external (document, uri, error);
+}
 
 static gboolean
 comics_document_save (EvDocument *document,
@@ -568,14 +728,69 @@ comics_document_get_n_pages (EvDocument *document)
 {
 	ComicsDocument *comics_document = COMICS_DOCUMENT (document);
 
+#if WITH_LIBGSF
+	if (comics_document->pages != NULL)
+		return comics_document->pages->len;
+#endif
         if (comics_document->page_names == NULL)
                 return 0;
 
 	return comics_document->page_names->len;
 }
 
+#if WITH_LIBGSF
 static void
-comics_document_get_page_size (EvDocument *document,
+comics_document_get_page_size_gsf (EvDocument *document,
+			       EvPage     *page,
+			       double     *width,
+			       double     *height)
+{
+	ComicsDocument *comics_document = COMICS_DOCUMENT (document);
+	GdkPixbufLoader *loader;
+	guint8 const *data;
+	gsf_off_t len;
+	GdkPixbuf *pixbuf;
+	gboolean got_size = FALSE;
+
+	loader = gdk_pixbuf_loader_new ();
+	g_signal_connect (loader, "area-prepared",
+			  G_CALLBACK (get_page_size_area_prepared_cb),
+			  &got_size);
+
+	GsfInput *input = GSF_INPUT (
+		g_ptr_array_index(comics_document->pages, page->index));
+
+	gsf_input_seek(input, 0, G_SEEK_SET);
+
+	while ((len = gsf_input_remaining (input)) > 0) {
+
+		if (len > 1024)
+			len = 1024;
+
+		if ((data = gsf_input_read (input, len, NULL))) {
+			gdk_pixbuf_loader_write (loader, data, len, NULL);
+		}
+
+		if ((!data) || got_size) {
+			break;
+		}
+	}
+	gdk_pixbuf_loader_close (loader, NULL);
+
+	if (gdk_pixbuf_loader_get_pixbuf (loader)) {
+		pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
+		if (width)
+			*width = gdk_pixbuf_get_width (pixbuf);
+		if (height)
+			*height = gdk_pixbuf_get_height (pixbuf);
+	}
+
+	g_object_unref (loader);
+}
+#endif
+
+static void
+comics_document_get_page_size_external (EvDocument *document,
 			       EvPage     *page,
 			       double     *width,
 			       double     *height)
@@ -643,6 +858,27 @@ comics_document_get_page_size (EvDocument *document,
 }
 
 static void
+comics_document_get_page_size (EvDocument *document,
+			       EvPage     *page,
+			       double     *width,
+			       double     *height)
+{
+	ComicsDocument *comics_document = COMICS_DOCUMENT (document);
+	switch (comics_document->type) {
+#if WITH_LIBGSF
+	case TYPE_ZIP:
+	case TYPE_TAR:
+		comics_document_get_page_size_gsf (document,
+			page, width, height);
+		break;
+#endif
+	default:
+		comics_document_get_page_size_external (document,
+			page, width, height);
+	}
+}
+
+static void
 get_page_size_area_prepared_cb (GdkPixbufLoader *loader,
 				gpointer         data)
 {
@@ -650,9 +886,54 @@ get_page_size_area_prepared_cb (GdkPixbufLoader *loader,
 	*got_size = TRUE;
 }
 
+#if WITH_LIBGSF
 static GdkPixbuf *
-comics_document_render_pixbuf (EvDocument      *document,
-			       EvRenderContext *rc)
+comics_document_render_pixbuf_gsf (EvDocument      *document,
+				   EvRenderContext *rc)
+{
+	ComicsDocument *comics_document = COMICS_DOCUMENT (document);
+	GdkPixbufLoader *loader;
+	GdkPixbuf *rotated_pixbuf;
+	guint8 const *data;
+	gsf_off_t len;
+
+	loader = gdk_pixbuf_loader_new ();
+	g_signal_connect (loader, "size-prepared",
+			  G_CALLBACK (render_pixbuf_size_prepared_cb),
+			  &rc->scale);
+
+	GsfInput *input = GSF_INPUT (
+		g_ptr_array_index(comics_document->pages, rc->page->index));
+
+	gsf_input_seek(input, 0, G_SEEK_SET);
+	while ((len = gsf_input_remaining (input)) > 0) {
+
+		if (len > 1024)
+			len = 1024;
+
+		if ((data = gsf_input_read (input, len, NULL))) {
+			gdk_pixbuf_loader_write (loader, data, len, NULL);
+		}
+
+		if (!data) {
+			g_warning (_("Failed to read data"));
+			break;
+		}
+	}
+	gdk_pixbuf_loader_close (loader, NULL);
+
+	rotated_pixbuf = gdk_pixbuf_rotate_simple (
+				gdk_pixbuf_loader_get_pixbuf (loader),
+				360 - rc->rotation);
+	g_object_unref (loader);
+
+	return rotated_pixbuf;
+}
+#endif
+
+static GdkPixbuf *
+comics_document_render_pixbuf_external (EvDocument      *document,
+				        EvRenderContext *rc)
 {
 	GdkPixbufLoader *loader;
 	GdkPixbuf *rotated_pixbuf;
@@ -719,6 +1000,23 @@ comics_document_render_pixbuf (EvDocument      *document,
 	return rotated_pixbuf;
 }
 
+static GdkPixbuf *
+comics_document_render_pixbuf (EvDocument      *document,
+			       EvRenderContext *rc)
+{
+	ComicsDocument *comics_document = COMICS_DOCUMENT (document);
+	switch (comics_document->type) {
+#if WITH_LIBGSF
+	case TYPE_ZIP:
+	case TYPE_TAR:
+		return comics_document_render_pixbuf_gsf (document, rc);
+		break;
+#endif
+	default:
+		return comics_document_render_pixbuf_external (document, rc);
+	}
+}
+
 static cairo_surface_t *
 comics_document_render (EvDocument      *document,
 			EvRenderContext *rc)
@@ -790,6 +1088,13 @@ comics_document_finalize (GObject *object)
 		g_free (comics_document->dir);
 	}
 	
+#if WITH_LIBGSF
+	if (comics_document->pages) {
+                g_ptr_array_foreach (comics_document->pages, (GFunc) g_object_unref, NULL);
+                g_ptr_array_free (comics_document->pages, TRUE);
+	}
+#endif
+
 	if (comics_document->page_names) {
                 g_ptr_array_foreach (comics_document->page_names, (GFunc) g_free, NULL);
                 g_ptr_array_free (comics_document->page_names, TRUE);
@@ -823,8 +1128,14 @@ static void
 comics_document_init (ComicsDocument *comics_document)
 {
 	comics_document->archive = NULL;
+	comics_document->dir = NULL;
 	comics_document->page_names = NULL;
+	comics_document->pages = NULL;
+	comics_document->selected_command = NULL;
+	comics_document->alternative_command = NULL;
 	comics_document->extract_command = NULL;
+	comics_document->list_command = NULL;
+	comics_document->decompress_tmp = NULL;
 }
 
 /* Returns a list of file extensions supported by gdk-pixbuf */
diff --git a/configure.ac b/configure.ac
index d061c2e..13556b0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -672,6 +672,20 @@ AC_ARG_ENABLE(comics,
 	
 if test "x$enable_comics" = "xyes"; then
 	AC_DEFINE([ENABLE_COMICS], [1], [Enable support for comics.])
+	COMICS_PKGS="gtk+-$GTK_API_VERSION >= $GTK_REQUIRED"
+	AC_ARG_WITH(libgsf,
+		[AS_HELP_STRING([--with-libgsf],
+			[Use libgsf for comics support])],
+		[],
+		[case "$with_platform" in
+			win32) with_libgsf=yes ;;
+			*) with_libgsf=no ;;
+		esac])
+	if test "x$with_libgsf" = "xyes"; then
+		AC_DEFINE([WITH_LIBGSF], [1], [Use libgsf for comics support.])
+		COMICS_PKGS="$COMICS_PKGS libgsf-1"
+	fi
+	PKG_CHECK_MODULES(COMICS, [$COMICS_PKGS])
 fi
 AM_CONDITIONAL(ENABLE_COMICS, test x$enable_comics = xyes)
 
-- 
1.6.4.2

openSUSE Build Service is sponsored by