[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1061380: marked as done (bookworm-pu: package atril/1.26.0-2+deb12u2)



Your message dated Sat, 10 Feb 2024 13:11:21 +0000
with message-id <E1rYn8b-002ybg-Ka@coccia.debian.org>
and subject line Released with 12.5
has caused the Debian Bug report #1061380,
regarding bookworm-pu: package atril/1.26.0-2+deb12u2
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
1061380: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1061380
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
Tags: bookworm
User: release.debian.org@packages.debian.org
Usertags: pu
X-Debbugs-Cc: atril@packages.debian.org
Control: affects -1 + src:atril

Recently atril 1.26.0-2+deb12u1 has been accepted in bookworm for the
upcoming 12.5 point release. This upload brings a follow-up change (CVE
fix), also targetting the upcoming point release.

[ Reason ]
Fix CVE-2023-51698:
https://security-tracker.debian.org/tracker/CVE-2023-51698

[ Impact ]
CVE-2023-51698 stays unfixed and atril stays vulnerable to crafted .CBT
(Comic Book Tar) files 

[ Tests ]
I manually checked that common file formats such as PDF and ePub can
still be opened. Unfortunately, I don't own any comic book tarball files
and could not find any such files on the internet for free download. As the
patches have been cherry-picked from upstream, I assume that they are
well tested with actual .CBT files.

[ Risks ]
Comic book consumers who read their comic books with atril might be
affected if the patchset is not sane.

[ Checklist ]
  [x] *all* changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in (old)stable
  [x] the issue is verified as fixed in unstable

[ Changes ]

+atril (1.26.0-2+deb12u2) bookworm; urgency=medium
+
+  * debian/patches:
+    + Add 0005-Use-a-blank-line-at-most.patch and 0006-comics-Use-libarchive-
+      to-unpack-documents.patch. Use libarchive instead of external command for
+      extracing documents (CVE-2023-51698, closes: #1060751).
+
+ -- Mike Gabriel <sunweaver@debian.org>  Tue, 23 Jan 2024 10:08:40 +0100
+
+atril (1.26.0-2+deb12u1) bookworm; urgency=medium
+
+  * debian/patches:
+    + Add 1002-avoid-crash-on-certain-epub-files.patch. Avoid crashes when
+      opening certain epub files. (Closes: #972715).
+    + Add 0001-Accessibility-add-button-description.patch. Accessibility: add
+      'Hide sidebar' button description. (Cherry-picked from v1.26.1).
+    + Add 0003-epub-Fix-index-loading-for-certain-documents-look-fo.patch. Fix
+      index loading for certain epub documents. (Cherry-picked from v1.26.1).
+    + Add 0004-epub-add-fallback-for-malformed-epub-files-in-check_.patch. epub:
+      add fallback for malformed epub files in check_mime_type. (Cherry-picked from
+      v1.26.1).
+
+ -- Mike Gabriel <sunweaver@debian.org>  Sat, 06 Jan 2024 07:18:28 +0100

[ Other info ]
None.
diff -Nru atril-1.26.0/debian/changelog atril-1.26.0/debian/changelog
--- atril-1.26.0/debian/changelog	2022-10-27 11:00:10.000000000 +0200
+++ atril-1.26.0/debian/changelog	2024-01-23 10:08:40.000000000 +0100
@@ -1,3 +1,27 @@
+atril (1.26.0-2+deb12u2) bookworm; urgency=medium
+
+  * debian/patches:
+    + Add 0005-Use-a-blank-line-at-most.patch and 0006-comics-Use-libarchive-
+      to-unpack-documents.patch. Use libarchive instead of external command for
+      extracing documents (CVE-2023-51698, closes: #1060751).
+
+ -- Mike Gabriel <sunweaver@debian.org>  Tue, 23 Jan 2024 10:08:40 +0100
+
+atril (1.26.0-2+deb12u1) bookworm; urgency=medium
+
+  * debian/patches:
+    + Add 1002-avoid-crash-on-certain-epub-files.patch. Avoid crashes when
+      opening certain epub files. (Closes: #972715).
+    + Add 0001-Accessibility-add-button-description.patch. Accessibility: add
+      'Hide sidebar' button description. (Cherry-picked from v1.26.1).
+    + Add 0003-epub-Fix-index-loading-for-certain-documents-look-fo.patch. Fix
+      index loading for certain epub documents. (Cherry-picked from v1.26.1).
+    + Add 0004-epub-add-fallback-for-malformed-epub-files-in-check_.patch. epub:
+      add fallback for malformed epub files in check_mime_type. (Cherry-picked from
+      v1.26.1).
+
+ -- Mike Gabriel <sunweaver@debian.org>  Sat, 06 Jan 2024 07:18:28 +0100
+
 atril (1.26.0-2) unstable; urgency=medium
 
   [ Mike Gabriel ]
diff -Nru atril-1.26.0/debian/patches/0001-Accessibility-add-button-description.patch atril-1.26.0/debian/patches/0001-Accessibility-add-button-description.patch
--- atril-1.26.0/debian/patches/0001-Accessibility-add-button-description.patch	1970-01-01 01:00:00.000000000 +0100
+++ atril-1.26.0/debian/patches/0001-Accessibility-add-button-description.patch	2024-01-23 10:05:56.000000000 +0100
@@ -0,0 +1,47 @@
+From 9a981607b36488ea5d2ce8646540b1545e35ecd5 Mon Sep 17 00:00:00 2001
+From: Valentin Villenave <vvillenave@hypra.fr>
+Date: Tue, 26 Oct 2021 19:29:01 +0200
+Subject: [PATCH 01/10] Accessibility: add button description
+
+Signed-off-by: Mike Gabriel <mike.gabriel@das-netzwerkteam.de>
+---
+ po/POTFILES.in     | 1 +
+ shell/ev-sidebar.c | 3 +++
+ 2 files changed, 4 insertions(+)
+
+diff --git a/po/POTFILES.in b/po/POTFILES.in
+index 02b9435..08ab5ec 100644
+--- a/po/POTFILES.in
++++ b/po/POTFILES.in
+@@ -67,6 +67,7 @@ shell/ev-password-view.c
+ shell/ev-properties-dialog.c
+ shell/ev-properties-fonts.c
+ shell/ev-properties-license.c
++shell/ev-sidebar.c
+ shell/ev-sidebar-annotations.c
+ shell/ev-sidebar-attachments.c
+ shell/ev-sidebar-bookmarks.c
+diff --git a/shell/ev-sidebar.c b/shell/ev-sidebar.c
+index b9173cd..0cdb6be 100644
+--- a/shell/ev-sidebar.c
++++ b/shell/ev-sidebar.c
+@@ -26,6 +26,8 @@
+ 
+ #include <string.h>
+ 
++#include <glib.h>
++#include <glib/gi18n.h>
+ #include <gtk/gtk.h>
+ #include <gdk/gdkkeysyms.h>
+ 
+@@ -362,6 +364,7 @@ ev_sidebar_init (EvSidebar *ev_sidebar)
+ 	g_signal_connect (close_button, "clicked",
+ 			  G_CALLBACK (ev_sidebar_close_clicked_cb),
+ 			  ev_sidebar);
++	gtk_widget_set_tooltip_text (close_button, _("Hide sidebar"));
+ 
+ 	image = gtk_image_new_from_icon_name ("window-close",
+ 	                                      GTK_ICON_SIZE_MENU);
+-- 
+2.39.2
+
diff -Nru atril-1.26.0/debian/patches/0003-epub-Fix-index-loading-for-certain-documents-look-fo.patch atril-1.26.0/debian/patches/0003-epub-Fix-index-loading-for-certain-documents-look-fo.patch
--- atril-1.26.0/debian/patches/0003-epub-Fix-index-loading-for-certain-documents-look-fo.patch	1970-01-01 01:00:00.000000000 +0100
+++ atril-1.26.0/debian/patches/0003-epub-Fix-index-loading-for-certain-documents-look-fo.patch	2024-01-23 10:05:56.000000000 +0100
@@ -0,0 +1,38 @@
+From 9f5d7343f79f6ff8295884df3229bc6696b4386c Mon Sep 17 00:00:00 2001
+From: Michael Webster <miketwebster@gmail.com>
+Date: Mon, 18 Jul 2022 10:43:47 -0400
+Subject: [PATCH 03/10] epub: Fix index loading for certain documents - look
+ for epub:type instead of epub:id.
+
+Add a null check as well.
+
+ref:
+https://help.apple.com/itc/booksassetguide/en.lproj/itc0f175a5b9.html#apdd3c4c6d1c0904
+https://idpf.org/epub/301/spec/epub-contentdocs-20140626.html#sec-xhtml-nav
+Signed-off-by: Mike Gabriel <mike.gabriel@das-netzwerkteam.de>
+---
+ backend/epub/epub-document.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/backend/epub/epub-document.c b/backend/epub/epub-document.c
+index 52530f4..385d2fe 100644
+--- a/backend/epub/epub-document.c
++++ b/backend/epub/epub-document.c
+@@ -1201,7 +1201,13 @@ setup_index_from_navfile(gchar *tocpath)
+     GList *index = NULL;
+     open_xml_document(tocpath);
+     set_xml_root_node(NULL);
+-    xmlNodePtr nav = xml_get_pointer_to_node((xmlChar*)"nav",(xmlChar*)"id",(xmlChar*)"toc");
++    xmlNodePtr nav = xml_get_pointer_to_node((xmlChar*)"nav",(xmlChar*)"type",(xmlChar*)"toc");
++
++    if (nav == NULL) {
++        xml_free_doc();
++        return NULL;
++    }
++
+     xmlretval=NULL;
+     xml_parse_children_of_node(nav,(xmlChar*)"ol", NULL,NULL);
+     gchar *navdirend = g_strrstr(tocpath,"/");
+-- 
+2.39.2
+
diff -Nru atril-1.26.0/debian/patches/0004-epub-add-fallback-for-malformed-epub-files-in-check_.patch atril-1.26.0/debian/patches/0004-epub-add-fallback-for-malformed-epub-files-in-check_.patch
--- atril-1.26.0/debian/patches/0004-epub-add-fallback-for-malformed-epub-files-in-check_.patch	1970-01-01 01:00:00.000000000 +0100
+++ atril-1.26.0/debian/patches/0004-epub-add-fallback-for-malformed-epub-files-in-check_.patch	2024-01-23 10:05:56.000000000 +0100
@@ -0,0 +1,98 @@
+From c585b945d27e883908c437d12aa9c453db2143f4 Mon Sep 17 00:00:00 2001
+From: rbuj <robert.buj@gmail.com>
+Date: Sun, 7 Aug 2022 23:08:59 +0200
+Subject: [PATCH 04/10] epub: add fallback for malformed epub files in
+ check_mime_type
+
+Signed-off-by: Mike Gabriel <mike.gabriel@das-netzwerkteam.de>
+---
+ backend/epub/epub-document.c | 66 +++++++++++++++++++++---------------
+ 1 file changed, 38 insertions(+), 28 deletions(-)
+
+diff --git a/backend/epub/epub-document.c b/backend/epub/epub-document.c
+index 385d2fe..451c884 100644
+--- a/backend/epub/epub-document.c
++++ b/backend/epub/epub-document.c
+@@ -625,41 +625,51 @@ xml_get_data_from_node(xmlNodePtr node,
+ static gboolean
+ check_mime_type(const gchar* uri,GError** error)
+ {
+-    GError * err = NULL ;
+-    const gchar* mimeFromFile = ev_file_get_mime_type(uri,FALSE,&err);
++    GError * err = NULL;
++    const gchar* mimeFromFile;
+ 
+-    gchar* mimetypes[] = {"application/epub+zip","application/x-booki+zip"};
+-    int typecount = 2;
+-    if ( !mimeFromFile )
++    mimeFromFile = ev_file_get_mime_type(uri, FALSE, &err);
++    if (mimeFromFile)
+     {
+-        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;
+-    }
+-    else
+-    {
+-        int i=0;
+-        for (i=0; i < typecount ;i++) {
+-           if ( g_strcmp0(mimeFromFile, mimetypes[i]) == 0  ) {
++        const gchar* mimetypes[] = {"application/epub+zip", "application/x-booki+zip", NULL};
++        guint i;
++
++        for (i = 0; i < g_strv_length (mimetypes); i++) {
++           if (strcmp(mimeFromFile, mimetypes[i]) == 0)
+                 return TRUE;
+-           }
++	}
++
++        /* fallback for malformed epub files */
++        if (strcmp (mimeFromFile, "application/zip") == 0)
++        {
++            mimeFromFile = ev_file_get_mime_type (uri, TRUE, &err);
++            if (mimeFromFile)
++            {
++                for (i = 0; i < g_strv_length (mimetypes); i++) {
++                    if (g_strcmp0(mimeFromFile, mimetypes[i]) == 0)
++                        return TRUE;
++                }
++
++                /*We didn't find a match*/
++                g_set_error_literal (error,
++                                     EV_DOCUMENT_ERROR,
++                                     EV_DOCUMENT_ERROR_INVALID,
++                                     _("Not an ePub document"));
++
++                return FALSE;
++            }
+         }
++    }
+ 
+-        /*We didn't find a match*/
++    if (err)
++        g_propagate_error (error, err);
++    else
+         g_set_error_literal (error,
+-                     EV_DOCUMENT_ERROR,
+-                     EV_DOCUMENT_ERROR_INVALID,
+-                     _("Not an ePub document"));
++                             EV_DOCUMENT_ERROR,
++                             EV_DOCUMENT_ERROR_INVALID,
++                             _("Unknown MIME Type"));
+ 
+-        return FALSE;
+-    }
++    return FALSE;
+ }
+ 
+ static gboolean
+-- 
+2.39.2
+
diff -Nru atril-1.26.0/debian/patches/0005-Use-a-blank-line-at-most.patch atril-1.26.0/debian/patches/0005-Use-a-blank-line-at-most.patch
--- atril-1.26.0/debian/patches/0005-Use-a-blank-line-at-most.patch	1970-01-01 01:00:00.000000000 +0100
+++ atril-1.26.0/debian/patches/0005-Use-a-blank-line-at-most.patch	2024-01-23 10:08:40.000000000 +0100
@@ -0,0 +1,1866 @@
+From 658fab1f008bff7e1ec147d95baa04bc44c2fbcd Mon Sep 17 00:00:00 2001
+From: rbuj <robert.buj@gmail.com>
+Date: Wed, 27 Oct 2021 17:30:36 +0200
+Subject: [PATCH 1/2] Use a blank line at most
+
+Signed-off-by: Mike Gabriel <mike.gabriel@das-netzwerkteam.de>
+---
+ backend/comics/comics-document.c              |  3 --
+ backend/djvu/djvu-document.c                  |  3 --
+ backend/djvu/djvu-links.c                     |  2 -
+ backend/djvu/djvu-text-page.c                 |  3 --
+ backend/djvu/djvu-text-page.h                 |  1 -
+ backend/dvi/dvi-document.c                    |  2 -
+ backend/dvi/fonts.c                           |  1 -
+ backend/dvi/mdvi-lib/afmparse.c               | 18 --------
+ backend/dvi/mdvi-lib/bitmap.c                 |  2 -
+ backend/dvi/mdvi-lib/color.c                  |  1 -
+ backend/dvi/mdvi-lib/color.h                  |  1 -
+ backend/dvi/mdvi-lib/fontmap.c                |  1 -
+ backend/dvi/mdvi-lib/hash.c                   |  1 -
+ backend/dvi/mdvi-lib/hash.h                   |  2 -
+ backend/dvi/mdvi-lib/mdvi.h                   |  2 -
+ backend/dvi/mdvi-lib/paper.h                  |  1 -
+ backend/dvi/mdvi-lib/special.c                |  1 -
+ backend/dvi/mdvi-lib/tfmfile.c                |  1 -
+ backend/epub/epub-document.c                  |  6 ---
+ backend/epub/minizip/ioapi.c                  |  6 ---
+ backend/epub/minizip/ioapi.h                  |  7 ---
+ backend/epub/minizip/unzip.c                  | 45 -------------------
+ backend/epub/minizip/unzip.h                  | 11 -----
+ backend/pdf/ev-poppler.h                      |  1 -
+ backend/pixbuf/pixbuf-document.c              |  1 -
+ backend/tiff/tiff-document.c                  |  1 -
+ backend/tiff/tiff2ps.c                        |  2 -
+ backend/xps/xps-document.c                    |  2 -
+ .../toolbar-editor/egg-editable-toolbar.c     |  2 -
+ .../toolbar-editor/egg-toolbar-editor.c       |  1 -
+ .../toolbar-editor/egg-toolbar-editor.h       |  2 -
+ .../toolbar-editor/egg-toolbars-model.c       |  2 -
+ cut-n-paste/zoom-control/ephy-zoom.c          |  1 -
+ libdocument/ev-document-attachments.c         |  1 -
+ libdocument/ev-document-factory.c             |  1 -
+ libdocument/ev-document-fonts.h               |  1 -
+ libdocument/ev-document-misc.c                |  1 -
+ libdocument/ev-document-security.h            |  1 -
+ libdocument/ev-document-text.c                |  1 -
+ libdocument/ev-document.c                     |  1 -
+ libdocument/ev-file-helpers.h                 |  1 -
+ libdocument/ev-form-field.h                   |  1 -
+ libdocument/ev-image.h                        |  1 -
+ libdocument/ev-render-context.h               |  2 -
+ libdocument/ev-transition-effect.h            |  2 -
+ libmisc/ev-page-action-widget.c               |  3 --
+ libview/ev-page-accessible.c                  |  2 -
+ libview/ev-pixbuf-cache.c                     |  6 ---
+ libview/ev-pixbuf-cache.h                     |  2 -
+ libview/ev-timeline.c                         |  2 -
+ libview/ev-timeline.h                         |  2 -
+ libview/ev-transition-animation.c             |  2 -
+ libview/ev-transition-animation.h             |  2 -
+ libview/ev-view-presentation.c                |  1 -
+ libview/ev-view.c                             |  2 -
+ libview/ev-web-view.c                         |  2 -
+ libview/ev-web-view.h                         |  1 -
+ previewer/ev-previewer-window.c               |  1 -
+ shell/eggfindbar.c                            |  1 -
+ shell/eggfindbar.h                            |  1 -
+ shell/ev-application.c                        |  2 -
+ shell/ev-bookmarks.h                          |  2 -
+ shell/ev-daemon.c                             |  1 -
+ shell/ev-history.c                            |  1 -
+ shell/ev-loading-message.c                    |  1 -
+ shell/ev-media-player-keys.h                  |  1 -
+ shell/ev-navigation-action.c                  |  1 -
+ shell/ev-open-recent-action.c                 |  1 -
+ shell/ev-password-view.c                      |  2 -
+ shell/ev-sidebar-attachments.c                |  1 -
+ shell/ev-sidebar-bookmarks.c                  |  1 -
+ shell/ev-sidebar-layers.c                     |  1 -
+ shell/ev-sidebar-links.c                      |  3 --
+ shell/ev-sidebar-links.h                      |  1 -
+ shell/ev-sidebar-page.c                       |  1 -
+ shell/ev-sidebar-page.h                       |  1 -
+ shell/ev-sidebar-thumbnails.c                 |  1 -
+ shell/ev-sidebar-thumbnails.h                 |  1 -
+ shell/ev-sidebar.c                            |  1 -
+ shell/ev-sidebar.h                            |  1 -
+ shell/ev-window.c                             |  9 ----
+ shell/ev-window.h                             |  2 -
+ shell/main.c                                  |  4 --
+ 83 files changed, 220 deletions(-)
+
+--- a/backend/comics/comics-document.c
++++ b/backend/comics/comics-document.c
+@@ -126,7 +126,6 @@
+ static char**     extract_argv                   (EvDocument *document,
+ 						  gint page);
+ 
+-
+ EV_BACKEND_REGISTER_WITH_CODE (ComicsDocument, comics_document,
+ 	{
+ 		EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_THUMBNAILS,
+@@ -186,7 +185,6 @@
+ 	return g_string_free (dest, FALSE);
+ }
+ 
+-
+ /* This function manages the command for decompressing a comic book */
+ static gboolean
+ comics_decompress_temp_dir (const gchar *command_decompress_tmp,
+@@ -627,7 +625,6 @@
+ 	return TRUE;
+ }
+ 
+-
+ static gboolean
+ comics_document_save (EvDocument *document,
+ 		      const char *uri,
+--- a/backend/djvu/djvu-document.c
++++ b/backend/djvu/djvu-document.c
+@@ -66,7 +66,6 @@
+       EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_SELECTION, djvu_selection_iface_init);
+      });
+ 
+-
+ #define EV_DJVU_ERROR ev_djvu_error_quark ()
+ 
+ static GQuark
+@@ -256,7 +255,6 @@
+ 	return TRUE;
+ }
+ 
+-
+ static gboolean
+ djvu_document_save (EvDocument  *document,
+ 		    const char  *uri,
+@@ -676,7 +674,6 @@
+ 		r->y2 = height - tmp * SCALE_FACTOR;
+ 	}
+ 
+-
+ 	return matches;
+ }
+ 
+--- a/backend/djvu/djvu-links.c
++++ b/backend/djvu/djvu-links.c
+@@ -181,7 +181,6 @@
+ 		if (!string_from_miniexp (miniexp_car (iter), &title)) goto unknown_entry;
+ 		if (!string_from_miniexp (miniexp_cadr (iter), &link_dest)) goto unknown_entry;
+ 
+-
+ 		if (!g_utf8_validate (title, -1, NULL)) {
+ 			utf8_title = str_to_utf8 (title);
+ 			title_markup = g_markup_escape_text (utf8_title, -1);
+@@ -342,7 +341,6 @@
+ 	return NULL;
+ }
+ 
+-
+ gboolean
+ djvu_links_has_document_links (EvDocumentLinks *document_links)
+ {
+--- a/backend/djvu/djvu-text-page.c
++++ b/backend/djvu/djvu-text-page.c
+@@ -23,7 +23,6 @@
+ #include <libdjvu/miniexp.h>
+ #include "djvu-text-page.h"
+ 
+-
+ /**
+  * djvu_text_page_selection_process:
+  * @page: #DjvuTextPage instance
+@@ -117,7 +116,6 @@
+ 	}
+ }
+ 
+-
+ static void
+ djvu_text_page_limits (DjvuTextPage *page,
+ 			  miniexp_t     p,
+@@ -404,7 +402,6 @@
+ 	g_free (search_text);
+ }
+ 
+-
+ /**
+  * djvu_text_page_prepare_search:
+  * @page: #DjvuTextPage instance
+--- a/backend/djvu/djvu-text-page.h
++++ b/backend/djvu/djvu-text-page.h
+@@ -25,7 +25,6 @@
+ #include <glib.h>
+ #include <libdjvu/miniexp.h>
+ 
+-
+ typedef struct _DjvuTextPage DjvuTextPage;
+ typedef struct _DjvuTextLink DjvuTextLink;
+ 
+--- a/backend/dvi/dvi-document.c
++++ b/backend/dvi/dvi-document.c
+@@ -110,7 +110,6 @@
+ 
+ 	mdvi_cairo_device_init (&dvi_document->context->device);
+ 
+-
+ 	dvi_document->base_width = dvi_document->context->dvi_page_w * dvi_document->context->params.conv
+ 		+ 2 * unit2pix(dvi_document->params->dpi, MDVI_HMARGIN) / dvi_document->params->hshrink;
+ 
+@@ -123,7 +122,6 @@
+ 	return TRUE;
+ }
+ 
+-
+ static gboolean
+ dvi_document_save (EvDocument  *document,
+ 		      const char  *uri,
+--- a/backend/dvi/fonts.c
++++ b/backend/dvi/fonts.c
+@@ -54,4 +54,3 @@
+ 	return;
+ }
+ 
+-
+--- a/backend/dvi/mdvi-lib/afmparse.c
++++ b/backend/dvi/mdvi-lib/afmparse.c
+@@ -81,13 +81,10 @@
+ 
+ #define MATCH(A,B)		(strncmp((A),(B), MAX_NAME) == 0)
+ 
+-
+-
+ /*************************** GLOBALS ***********************/
+ 
+ static char *ident = NULL; /* storage buffer for keywords */
+ 
+-
+ /* "shorts" for fast case statement
+  * The values of each of these enumerated items correspond to an entry in the
+  * table of strings defined below. Therefore, if you add a new string as
+@@ -175,7 +172,6 @@
+ 
+ } /* token */
+ 
+-
+ /*************************** linetoken *************************/
+ 
+ /*  "linetoken" will get read all tokens until the EOL character from
+@@ -203,7 +199,6 @@
+ 
+ } /* linetoken */
+ 
+-
+ /*************************** recognize *************************/
+ 
+ /*  This function tries to match a string to a known list of
+@@ -234,7 +229,6 @@
+ 
+ } /* recognize */
+ 
+-
+ /************************* parseGlobals *****************************/
+ 
+ /*  This function is called by "parseFile". It will parse the AFM File
+@@ -401,8 +395,6 @@
+ 
+ } /* parseGlobals */
+ 
+-
+-
+ #if 0 /* this function does not seem to be used anywhere */
+ /************************* initializeArray ************************/
+ 
+@@ -584,7 +576,6 @@
+ 
+ } /* parseCharWidths */
+ 
+-
+ /************************* parseCharMetrics ************************/
+ 
+ /*  This function is called by parseFile if the caller of parseFile
+@@ -694,8 +685,6 @@
+ 
+ } /* parseCharMetrics */
+ 
+-
+-
+ /************************* parseTrackKernData ***********************/
+ 
+ /*  This function is called by "parseFile". It will parse the AFM File
+@@ -797,7 +786,6 @@
+ 
+ } /* parseTrackKernData */
+ 
+-
+ /************************* parsePairKernData ************************/
+ 
+ /*  This function is called by "parseFile". It will parse the AFM File
+@@ -918,7 +906,6 @@
+ 
+ } /* parsePairKernData */
+ 
+-
+ /************************* parseCompCharData **************************/
+ 
+ /*  This function is called by "parseFile". It will parse the AFM File
+@@ -1043,12 +1030,8 @@
+ 
+ } /* parseCompCharData */
+ 
+-
+-
+-
+ /*************************** 'PUBLIC' FUNCTION ********************/
+ 
+-
+ /*************************** parseFile *****************************/
+ 
+ /*  parseFile is the only 'public' procedure available. It is called
+@@ -1078,7 +1061,6 @@
+ 
+     register char *keyword; /* used to store a token */
+ 
+-
+     /* storage data for the global variable ident */
+     ident = (char *) calloc(MAX_NAME, sizeof(char));
+     if (ident == NULL) {error = storageProblem; return(error);}
+--- a/backend/dvi/mdvi-lib/bitmap.c
++++ b/backend/dvi/mdvi-lib/bitmap.c
+@@ -117,7 +117,6 @@
+ 	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
+ };
+ 
+-
+ /*
+  * next we have three bitmap functions to convert bitmaps in LSB bit order
+  * with 8, 16 and 32 bits per unit, to our internal format. The differences
+@@ -192,7 +191,6 @@
+ 	return bm;
+ }
+ 
+-
+ BITMAP	*bitmap_copy(BITMAP *bm)
+ {
+ 	BITMAP	*nb = bitmap_alloc(bm->width, bm->height);
+--- a/backend/dvi/mdvi-lib/color.c
++++ b/backend/dvi/mdvi-lib/color.c
+@@ -79,7 +79,6 @@
+ 
+ #define GAMMA_DIFF	0.005
+ 
+-
+ /* create a color table */
+ Ulong	*get_color_table(DviDevice *dev,
+ 			 int nlevels, Ulong fg, Ulong bg, double gamma, int density)
+--- a/backend/dvi/mdvi-lib/color.h
++++ b/backend/dvi/mdvi-lib/color.h
+@@ -16,7 +16,6 @@
+  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+  */
+ 
+-
+ #ifndef _COLOR_H_
+ #define _COLOR_H_
+ 
+--- a/backend/dvi/mdvi-lib/fontmap.c
++++ b/backend/dvi/mdvi-lib/fontmap.c
+@@ -834,7 +834,6 @@
+ 	return 0;
+ }
+ 
+-
+ void	mdvi_flush_encodings(void)
+ {
+ 	DviEncoding *enc;
+--- a/backend/dvi/mdvi-lib/hash.c
++++ b/backend/dvi/mdvi-lib/hash.c
+@@ -21,7 +21,6 @@
+ 
+ /* simple hash tables for MDVI */
+ 
+-
+ struct _DviHashBucket {
+ 	DviHashBucket *next;
+ 	DviHashKey	key;
+--- a/backend/dvi/mdvi-lib/hash.h
++++ b/backend/dvi/mdvi-lib/hash.h
+@@ -3,7 +3,6 @@
+ 
+ /* Hash tables */
+ 
+-
+ typedef struct _DviHashBucket DviHashBucket;
+ typedef struct _DviHashTable DviHashTable;
+ 
+@@ -18,7 +17,6 @@
+ typedef int	(*DviHashComp) __PROTO((DviHashKey key1, DviHashKey key2));
+ typedef void	(*DviHashFree) __PROTO((DviHashKey key, void *data));
+ 
+-
+ struct _DviHashTable {
+ 	DviHashBucket	**buckets;
+ 	int	nbucks;
+--- a/backend/dvi/mdvi-lib/mdvi.h
++++ b/backend/dvi/mdvi-lib/mdvi.h
+@@ -414,7 +414,6 @@
+ 	int	step;		/* step */
+ };
+ 
+-
+ typedef void (*DviSpecialHandler)
+ 	__PROTO((DviContext *dvi, const char *prefix, const char *arg));
+ 
+@@ -600,7 +599,6 @@
+ 
+ extern int mdvi_encode_font __PROTO((DviParams *, DviFont *));
+ 
+-
+ /* font lookup functions */
+ extern int mdvi_register_font_type __PROTO((DviFontInfo *, int));
+ extern char **mdvi_list_font_class __PROTO((int));
+--- a/backend/dvi/mdvi-lib/paper.h
++++ b/backend/dvi/mdvi-lib/paper.h
+@@ -24,7 +24,6 @@
+ 	const char *height;
+ };
+ 
+-
+ extern int 	mdvi_get_paper_size __PROTO((const char *, DviPaper *));
+ extern DviPaperSpec* mdvi_get_paper_specs __PROTO((DviPaperClass));
+ extern void	mdvi_free_paper_specs __PROTO((DviPaperSpec *));
+--- a/backend/dvi/mdvi-lib/special.c
++++ b/backend/dvi/mdvi-lib/special.c
+@@ -212,7 +212,6 @@
+ {
+ 	DviSpecial *sp, *list;
+ 
+-
+ 	for(list = (DviSpecial *)specials.head; (sp = list); ) {
+ 		list = sp->next;
+ 		if(sp->prefix) mdvi_free(sp->prefix);
+--- a/backend/dvi/mdvi-lib/tfmfile.c
++++ b/backend/dvi/mdvi-lib/tfmfile.c
+@@ -258,7 +258,6 @@
+ 	/* allocate characters */
+ 	info->chars = xnalloc(TFMChar, size);
+ 
+-
+ #ifdef WORD_LITTLE_ENDIAN
+ 	/* byte-swap the three arrays at once (they are consecutive in memory) */
+ 	swap_array((Uint32 *)widths, nw + nh + nd);
+--- a/backend/epub/epub-document.c
++++ b/backend/epub/epub-document.c
+@@ -224,7 +224,6 @@
+     return TRUE;
+ }
+ 
+-
+ typedef struct _LinksCBStruct {
+     GtkTreeModel *model;
+     GtkTreeIter  *parent;
+@@ -413,7 +412,6 @@
+     return (g_remove (path_name));
+ }
+ 
+-
+ static gboolean
+ check_mime_type             (const gchar* uri,
+                              GError** error);
+@@ -1562,7 +1560,6 @@
+ 
+         gchar *csspath = g_strdup_printf("%s/atrilnightstyle.css",epub_document->documentdir);
+ 
+-
+         GFile *styles = g_file_new_for_path (csspath);
+         GOutputStream *outstream = (GOutputStream*)g_file_create(styles,G_FILE_CREATE_PRIVATE,NULL,NULL);
+         if ( g_output_stream_write((GOutputStream*)outstream,style,strlen(style),NULL,NULL) == -1 )
+@@ -1636,7 +1633,6 @@
+     g_list_foreach(index,(GFunc)page_set_function,contentList);
+ }
+ 
+-
+ static void
+ add_mathjax_script_node_to_file(gchar *filename, gchar *data)
+ {
+@@ -1784,7 +1780,6 @@
+     epub_document->docTitle = NULL;
+ }
+ 
+-
+ static void
+ epub_document_finalize (GObject *object)
+ {
+@@ -1826,7 +1821,6 @@
+     G_OBJECT_CLASS (epub_document_parent_class)->finalize (object);
+ }
+ 
+-
+ static void
+ epub_document_class_init (EpubDocumentClass *klass)
+ {
+--- a/backend/epub/minizip/ioapi.c
++++ b/backend/epub/minizip/ioapi.c
+@@ -25,7 +25,6 @@
+ #define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin)
+ #endif
+ 
+-
+ #include "ioapi.h"
+ 
+ voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)
+@@ -82,8 +81,6 @@
+     p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file;
+ }
+ 
+-
+-
+ static voidpf  ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode));
+ static uLong   ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size));
+ static uLong   ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size));
+@@ -128,7 +125,6 @@
+     return file;
+ }
+ 
+-
+ static uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size)
+ {
+     uLong ret;
+@@ -150,7 +146,6 @@
+     return ret;
+ }
+ 
+-
+ static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream)
+ {
+     ZPOS64_T ret;
+@@ -206,7 +201,6 @@
+     return ret;
+ }
+ 
+-
+ static int ZCALLBACK fclose_file_func (voidpf opaque, voidpf stream)
+ {
+     int ret;
+--- a/backend/epub/minizip/ioapi.h
++++ b/backend/epub/minizip/ioapi.h
+@@ -110,7 +110,6 @@
+ extern "C" {
+ #endif
+ 
+-
+ #define ZLIB_FILEFUNC_SEEK_CUR (1)
+ #define ZLIB_FILEFUNC_SEEK_END (2)
+ #define ZLIB_FILEFUNC_SEEK_SET (0)
+@@ -122,7 +121,6 @@
+ #define ZLIB_FILEFUNC_MODE_EXISTING (4)
+ #define ZLIB_FILEFUNC_MODE_CREATE   (8)
+ 
+-
+ #ifndef ZCALLBACK
+  #if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK)
+    #define ZCALLBACK CALLBACK
+@@ -131,9 +129,6 @@
+  #endif
+ #endif
+ 
+-
+-
+-
+ typedef voidpf   (ZCALLBACK *open_file_func)      OF((voidpf opaque, const char* filename, int mode));
+ typedef uLong    (ZCALLBACK *read_file_func)      OF((voidpf opaque, voidpf stream, void* buf, uLong size));
+ typedef uLong    (ZCALLBACK *write_file_func)     OF((voidpf opaque, voidpf stream, const void* buf, uLong size));
+@@ -143,7 +138,6 @@
+ typedef long     (ZCALLBACK *tell_file_func)      OF((voidpf opaque, voidpf stream));
+ typedef long     (ZCALLBACK *seek_file_func)      OF((voidpf opaque, voidpf stream, uLong offset, int origin));
+ 
+-
+ /* here is the "old" 32 bits structure structure */
+ typedef struct zlib_filefunc_def_s
+ {
+@@ -185,7 +179,6 @@
+     seek_file_func      zseek32_file;
+ } zlib_filefunc64_32_def;
+ 
+-
+ #define ZREAD64(filefunc,filestream,buf,size)     ((*((filefunc).zfile_func64.zread_file))   ((filefunc).zfile_func64.opaque,filestream,buf,size))
+ #define ZWRITE64(filefunc,filestream,buf,size)    ((*((filefunc).zfile_func64.zwrite_file))  ((filefunc).zfile_func64.opaque,filestream,buf,size))
+ //#define ZTELL64(filefunc,filestream)            ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream))
+--- a/backend/epub/minizip/unzip.c
++++ b/backend/epub/minizip/unzip.c
+@@ -12,7 +12,6 @@
+ 
+          For more info read MiniZip_info.txt
+ 
+-
+   ------------------------------------------------------------------------------------
+   Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of
+   compatibility with older software. The following is from the original crypt.c.
+@@ -48,7 +47,6 @@
+ 
+         Copyright (C) 2007-2008 Even Rouault
+ 
+-
+         Oct-2009 - Mathias Svensson - Removed cpl_* from symbol names (Even Rouault added them but since this is now moved to a new project (minizip64) I renamed them again).
+   Oct-2009 - Mathias Svensson - Fixed problem if uncompressed size was > 4G and compressed size was <4G
+                                 should only read the compressed/uncompressed size from the Zip64 format if
+@@ -63,7 +61,6 @@
+ 
+ */
+ 
+-
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+@@ -86,20 +83,17 @@
+ #   include <errno.h>
+ #endif
+ 
+-
+ #ifndef local
+ #  define local static
+ #endif
+ /* compile with -Dlocal if your debugger can't find static symbols */
+ 
+-
+ #ifndef CASESENSITIVITYDEFAULT_NO
+ #  if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES)
+ #    define CASESENSITIVITYDEFAULT_NO
+ #  endif
+ #endif
+ 
+-
+ #ifndef UNZ_BUFSIZE
+ #define UNZ_BUFSIZE (16384)
+ #endif
+@@ -118,14 +112,12 @@
+ #define SIZECENTRALDIRITEM (0x2e)
+ #define SIZEZIPLOCALHEADER (0x1e)
+ 
+-
+ /* unz_file_info_interntal contain internal info about a file in zipfile*/
+ typedef struct unz_file_info64_internal_s
+ {
+     ZPOS64_T offset_curfile;/* relative offset of local header 8 bytes */
+ } unz_file_info64_internal;
+ 
+-
+ /* file_in_zip_read_info_s contain internal information about a file in zipfile,
+     when reading and decompress it */
+ typedef struct
+@@ -156,7 +148,6 @@
+     int   raw;
+ } file_in_zip64_read_info_s;
+ 
+-
+ /* unz64_s contain internal information about the zipfile
+ */
+ typedef struct
+@@ -189,7 +180,6 @@
+ #    endif
+ } unz64_s;
+ 
+-
+ #ifndef NOUNCRYPT
+ #include "crypt.h"
+ #endif
+@@ -200,7 +190,6 @@
+    IN assertion: the stream s has been successfully opened for reading.
+ */
+ 
+-
+ local int unz64local_getByte OF((
+     const zlib_filefunc64_32_def* pzlib_filefunc_def,
+     voidpf filestream,
+@@ -224,7 +213,6 @@
+     }
+ }
+ 
+-
+ /* ===========================================================================
+    Reads a long in LSB order from the given gz_stream. Sets
+ */
+@@ -295,7 +283,6 @@
+     voidpf filestream,
+     ZPOS64_T *pX));
+ 
+-
+ local int unz64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def,
+                             voidpf filestream,
+                             ZPOS64_T *pX)
+@@ -364,7 +351,6 @@
+     }
+ }
+ 
+-
+ #ifdef  CASESENSITIVITYDEFAULT_NO
+ #define CASESENSITIVITYDEFAULTVALUE 2
+ #else
+@@ -418,7 +404,6 @@
+     if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
+         return 0;
+ 
+-
+     uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);
+ 
+     if (uMaxBack>uSizeFile)
+@@ -463,7 +448,6 @@
+     return uPosFound;
+ }
+ 
+-
+ /*
+   Locate the Central directory 64 of a zipfile (at the end, just before
+     the global comment)
+@@ -486,7 +470,6 @@
+     if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
+         return 0;
+ 
+-
+     uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);
+ 
+     if (uMaxBack>uSizeFile)
+@@ -605,8 +588,6 @@
+         us.z_filefunc = *pzlib_filefunc64_32_def;
+     us.is64bitOpenFunction = is64bitOpenFunction;
+ 
+-
+-
+     us.filestream = ZOPEN64(us.z_filefunc,
+                                                  path,
+                                                  ZLIB_FILEFUNC_MODE_READ |
+@@ -745,7 +726,6 @@
+     us.pfile_in_zip_read = NULL;
+     us.encrypted = 0;
+ 
+-
+     s=(unz64_s*)ALLOC(sizeof(unz64_s));
+     if( s != NULL)
+     {
+@@ -755,7 +735,6 @@
+     return (unzFile)s;
+ }
+ 
+-
+ extern unzFile ZEXPORT unzOpen2 (const char *path,
+                                         zlib_filefunc_def* pzlib_filefunc32_def)
+ {
+@@ -814,7 +793,6 @@
+     return UNZ_OK;
+ }
+ 
+-
+ /*
+   Write info about the ZipFile in the *pglobal_info structure.
+   No preparation of the structure is needed
+@@ -897,7 +875,6 @@
+               ZLIB_FILEFUNC_SEEK_SET)!=0)
+         err=UNZ_ERRNO;
+ 
+-
+     /* we check the magic */
+     if (err==UNZ_OK)
+     {
+@@ -1002,7 +979,6 @@
+     else
+         lSeek += file_info.size_file_extra;
+ 
+-
+     if ((err==UNZ_OK) && (file_info.size_file_extra != 0))
+     {
+                                 uLong acc = 0;
+@@ -1096,7 +1072,6 @@
+     else
+         lSeek+=file_info.size_file_comment;
+ 
+-
+     if ((err==UNZ_OK) && (pfile_info!=NULL))
+         *pfile_info=file_info;
+ 
+@@ -1106,8 +1081,6 @@
+     return err;
+ }
+ 
+-
+-
+ /*
+   Write info about the ZipFile in the *pglobal_info structure.
+   No preparation of the structure is needed
+@@ -1156,7 +1129,6 @@
+ 
+         pfile_info->tmu_date = file_info64.tmu_date,
+ 
+-
+         pfile_info->compressed_size = (uLong)file_info64.compressed_size;
+         pfile_info->uncompressed_size = (uLong)file_info64.uncompressed_size;
+ 
+@@ -1212,7 +1184,6 @@
+     return err;
+ }
+ 
+-
+ /*
+   Try locate the file szFileName in the zipfile.
+   For the iCaseSensitivity signification, see unzStringFileNameCompare
+@@ -1234,7 +1205,6 @@
+     ZPOS64_T num_fileSaved;
+     ZPOS64_T pos_in_central_dirSaved;
+ 
+-
+     if (file==NULL)
+         return UNZ_PARAMERROR;
+ 
+@@ -1278,7 +1248,6 @@
+     return err;
+ }
+ 
+-
+ /*
+ ///////////////////////////////////////////
+ // Contributed by Ryan Haksi (mailto://cryogen@infoserve.net)
+@@ -1391,7 +1360,6 @@
+                                 s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0)
+         return UNZ_ERRNO;
+ 
+-
+     if (err==UNZ_OK)
+     {
+         if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK)
+@@ -1594,7 +1562,6 @@
+     pfile_in_zip_read_info->rest_read_uncompressed =
+             s->cur_file_info.uncompressed_size ;
+ 
+-
+     pfile_in_zip_read_info->pos_in_zipfile =
+             s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER +
+               iSizeVar;
+@@ -1626,7 +1593,6 @@
+     }
+ #    endif
+ 
+-
+     return UNZ_OK;
+ }
+ 
+@@ -1687,7 +1653,6 @@
+     if (pfile_in_zip_read_info==NULL)
+         return UNZ_PARAMERROR;
+ 
+-
+     if (pfile_in_zip_read_info->read_buffer == NULL)
+         return UNZ_END_OF_LIST_OF_FILE;
+     if (len==0)
+@@ -1731,7 +1696,6 @@
+                       uReadThis)!=uReadThis)
+                 return UNZ_ERRNO;
+ 
+-
+ #            ifndef NOUNCRYPT
+             if(s->encrypted)
+             {
+@@ -1743,7 +1707,6 @@
+             }
+ #            endif
+ 
+-
+             pfile_in_zip_read_info->pos_in_zipfile += uReadThis;
+ 
+             pfile_in_zip_read_info->rest_read_compressed-=uReadThis;
+@@ -1874,7 +1837,6 @@
+     return err;
+ }
+ 
+-
+ /*
+   Give the current position in uncompressed data
+ */
+@@ -1909,7 +1871,6 @@
+     return pfile_in_zip_read_info->total_out_64;
+ }
+ 
+-
+ /*
+   return 1 if the end of file was reached, 0 elsewhere
+ */
+@@ -1931,8 +1892,6 @@
+         return 0;
+ }
+ 
+-
+-
+ /*
+ Read extra field from the current file (opened by unzOpenCurrentFile)
+ This is the local-header version of the extra field (sometimes, there is
+@@ -2007,7 +1966,6 @@
+     if (pfile_in_zip_read_info==NULL)
+         return UNZ_PARAMERROR;
+ 
+-
+     if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) &&
+         (!pfile_in_zip_read_info->raw))
+     {
+@@ -2015,7 +1973,6 @@
+             err=UNZ_CRCERROR;
+     }
+ 
+-
+     TRYFREE(pfile_in_zip_read_info->read_buffer);
+     pfile_in_zip_read_info->read_buffer = NULL;
+     if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED)
+@@ -2025,7 +1982,6 @@
+         BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream);
+ #endif
+ 
+-
+     pfile_in_zip_read_info->stream_initialised = 0;
+     TRYFREE(pfile_in_zip_read_info);
+ 
+@@ -2034,7 +1990,6 @@
+     return err;
+ }
+ 
+-
+ /*
+   Get the global comment string of the ZipFile, in the szComment buffer.
+   uSizeBuf is the size of the szComment buffer.
+--- a/backend/epub/minizip/unzip.h
++++ b/backend/epub/minizip/unzip.h
+@@ -70,7 +70,6 @@
+ typedef voidp unzFile;
+ #endif
+ 
+-
+ #define UNZ_OK                          (0)
+ #define UNZ_END_OF_LIST_OF_FILE         (-100)
+ #define UNZ_ERRNO                       (Z_ERRNO)
+@@ -162,7 +161,6 @@
+     (like 1 on Unix, 2 on Windows)
+ */
+ 
+-
+ extern unzFile ZEXPORT unzOpen OF((const char *path));
+ extern unzFile ZEXPORT unzOpen64 OF((const void *path));
+ /*
+@@ -180,7 +178,6 @@
+        does not describe the reality
+ */
+ 
+-
+ extern unzFile ZEXPORT unzOpen2 OF((const char *path,
+                                     zlib_filefunc_def* pzlib_filefunc_def));
+ /*
+@@ -212,7 +209,6 @@
+   No preparation of the structure is needed
+   return UNZ_OK if there is no problem. */
+ 
+-
+ extern int ZEXPORT unzGetGlobalComment OF((unzFile file,
+                                            char *szComment,
+                                            uLong uSizeBuf));
+@@ -222,7 +218,6 @@
+   return the number of byte copied or an error code <0
+ */
+ 
+-
+ /***************************************************************************/
+ /* Unzip package allow you browse the directory of the zipfile */
+ 
+@@ -251,7 +246,6 @@
+   UNZ_END_OF_LIST_OF_FILE if the file is not found
+ */
+ 
+-
+ /* ****************************************** */
+ /* Ryan supplied functions */
+ /* unz_file_info contain information about a file in the zipfile */
+@@ -315,14 +309,12 @@
+             (commentBufferSize is the size of the buffer)
+ */
+ 
+-
+ /** Addition for GDAL : START */
+ 
+ extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file));
+ 
+ /** Addition for GDAL : END */
+ 
+-
+ /***************************************************************************/
+ /* for reading the content of the current zipfile, you can open it, read data
+    from it, and close it (you can close it before reading all the file)
+@@ -369,7 +361,6 @@
+          but you CANNOT set method parameter as NULL
+ */
+ 
+-
+ extern int ZEXPORT unzCloseCurrentFile OF((unzFile file));
+ /*
+   Close the file in zip opened with unzOpenCurrentFile
+@@ -428,8 +419,6 @@
+ extern int ZEXPORT unzSetOffset64 (unzFile file, ZPOS64_T pos);
+ extern int ZEXPORT unzSetOffset (unzFile file, uLong pos);
+ 
+-
+-
+ #ifdef __cplusplus
+ }
+ #endif
+--- a/backend/pdf/ev-poppler.h
++++ b/backend/pdf/ev-poppler.h
+@@ -34,7 +34,6 @@
+ 
+ G_MODULE_EXPORT GType register_atril_backend (GTypeModule *module);
+ 
+-
+ G_END_DECLS
+ 
+ #endif /* __PDF_DOCUMENT_H__ */
+--- a/backend/pixbuf/pixbuf-document.c
++++ b/backend/pixbuf/pixbuf-document.c
+@@ -201,7 +201,6 @@
+ 	iface->get_dimensions = pixbuf_document_thumbnails_get_dimensions;
+ }
+ 
+-
+ static void
+ pixbuf_document_init (PixbufDocument *pixbuf_document)
+ {
+--- a/backend/tiff/tiff-document.c
++++ b/backend/tiff/tiff-document.c
+@@ -361,7 +361,6 @@
+ 	if (width <= 0 || height <= 0)
+ 		return NULL;
+ 
+-
+ 	if (width >= INT_MAX / 4)
+ 		/* overflow */
+ 		return NULL;
+--- a/backend/tiff/tiff2ps.c
++++ b/backend/tiff/tiff2ps.c
+@@ -449,7 +449,6 @@
+ 	return splitpage;
+ }
+ 
+-
+ void
+ tiff2ps_process_page(TIFF2PSContext* ctx, TIFF* tif, double pw, double ph,
+ 		     double lm, double bm, gboolean cnt)
+@@ -592,7 +591,6 @@
+ 	}
+ }
+ 
+-
+ static char DuplexPreamble[] = "\
+ %%BeginFeature: *Duplex True\n\
+ systemdict begin\n\
+--- a/backend/xps/xps-document.c
++++ b/backend/xps/xps-document.c
+@@ -176,7 +176,6 @@
+ 		EV_DOCUMENT_INFO_N_PAGES |
+ 		EV_DOCUMENT_INFO_PAPER_SIZE;
+ 
+-
+ 	if (gxps_document_get_n_pages (xps->doc) > 0) {
+ 		ev_document_get_page_size (document, 0,
+ 					   &(info->paper_width),
+@@ -483,7 +482,6 @@
+ 	iface->find_link_page = xps_document_links_find_link_page;
+ }
+ 
+-
+ /* EvDocumentPrint */
+ static void
+ xps_document_print_print_page (EvDocumentPrint *document,
+--- a/cut-n-paste/toolbar-editor/egg-editable-toolbar.c
++++ b/cut-n-paste/toolbar-editor/egg-editable-toolbar.c
+@@ -541,7 +541,6 @@
+     }
+ }
+ 
+-
+ static void
+ configure_item_tooltip (GtkToolItem *item)
+ {
+@@ -557,7 +556,6 @@
+     }
+ }
+ 
+-
+ static void
+ connect_widget_signals (GtkWidget *proxy, EggEditableToolbar *etoolbar)
+ {
+--- a/cut-n-paste/toolbar-editor/egg-toolbar-editor.c
++++ b/cut-n-paste/toolbar-editor/egg-toolbar-editor.c
+@@ -36,7 +36,6 @@
+   {EGG_TOOLBAR_ITEM_TYPE, GTK_TARGET_SAME_APP, 0},
+ };
+ 
+-
+ static void egg_toolbar_editor_finalize         (GObject *object);
+ static void update_editor_sheet                 (EggToolbarEditor *editor);
+ 
+--- a/cut-n-paste/toolbar-editor/egg-toolbar-editor.h
++++ b/cut-n-paste/toolbar-editor/egg-toolbar-editor.h
+@@ -34,7 +34,6 @@
+ #define EGG_IS_TOOLBAR_EDITOR_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_TOOLBAR_EDITOR))
+ #define EGG_TOOLBAR_EDITOR_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_TOOLBAR_EDITOR, EggToolbarEditorClass))
+ 
+-
+ typedef struct EggToolbarEditor EggToolbarEditor;
+ typedef struct EggToolbarEditorPrivate EggToolbarEditorPrivate;
+ 
+@@ -51,7 +50,6 @@
+   GtkBoxClass parent_class;
+ };
+ 
+-
+ GType            egg_toolbar_editor_get_type     (void);
+ GtkWidget        *egg_toolbar_editor_new         (GtkUIManager *manager,
+                                                   EggToolbarsModel *model);
+--- a/cut-n-paste/toolbar-editor/egg-toolbars-model.c
++++ b/cut-n-paste/toolbar-editor/egg-toolbars-model.c
+@@ -213,7 +213,6 @@
+   EggToolbarsItem *idata2;
+   GNode *toolbar, *item;
+ 
+-
+   for(toolbar = g_node_first_child (model->priv->toolbars);
+       toolbar != NULL; toolbar = g_node_next_sibling (toolbar))
+     {
+@@ -330,7 +329,6 @@
+ 		 0, toolbar_position);
+ }
+ 
+-
+ char *
+ egg_toolbars_model_get_data (EggToolbarsModel *model,
+                              GdkAtom           type,
+--- a/cut-n-paste/zoom-control/ephy-zoom.c
++++ b/cut-n-paste/zoom-control/ephy-zoom.c
+@@ -54,7 +54,6 @@
+ 	return n_zoom_levels - 1;
+ }
+ 
+-
+ float
+ ephy_zoom_get_changed_zoom_level (float level, gint steps)
+ {
+--- a/libdocument/ev-document-attachments.c
++++ b/libdocument/ev-document-attachments.c
+@@ -52,4 +52,3 @@
+ 	return iface->get_attachments (document_attachments);
+ }
+ 
+-
+--- a/libdocument/ev-document-factory.c
++++ b/libdocument/ev-document-factory.c
+@@ -106,7 +106,6 @@
+ 	return EV_COMPRESSION_NONE;
+ }
+ 
+-
+ /*
+  * get_document_from_uri:
+  * @uri: the document URI
+--- a/libdocument/ev-document-fonts.h
++++ b/libdocument/ev-document-fonts.h
+@@ -37,7 +37,6 @@
+ 
+ G_BEGIN_DECLS
+ 
+-
+ #define EV_TYPE_DOCUMENT_FONTS		  (ev_document_fonts_get_type ())
+ #define EV_DOCUMENT_FONTS(o)		  (G_TYPE_CHECK_INSTANCE_CAST ((o), EV_TYPE_DOCUMENT_FONTS, EvDocumentFonts))
+ #define EV_DOCUMENT_FONTS_IFACE(k)	  (G_TYPE_CHECK_CLASS_CAST((k), EV_TYPE_DOCUMENT_FONTS, EvDocumentFontsInterface))
+--- a/libdocument/ev-document-misc.c
++++ b/libdocument/ev-document-misc.c
+@@ -149,7 +149,6 @@
+ 	}
+ }
+ 
+-
+ void
+ ev_document_misc_paint_one_page (cairo_t      *cr,
+ 				 GtkWidget    *widget,
+--- a/libdocument/ev-document-security.h
++++ b/libdocument/ev-document-security.h
+@@ -35,7 +35,6 @@
+ 
+ G_BEGIN_DECLS
+ 
+-
+ #define EV_TYPE_DOCUMENT_SECURITY		  (ev_document_security_get_type ())
+ #define EV_DOCUMENT_SECURITY(o)			  (G_TYPE_CHECK_INSTANCE_CAST ((o), EV_TYPE_DOCUMENT_SECURITY, EvDocumentSecurity))
+ #define EV_DOCUMENT_SECURITY_IFACE(k)	  	  (G_TYPE_CHECK_CLASS_CAST((k), EV_TYPE_DOCUMENT_SECURITY, EvDocumentSecurityInterface))
+--- a/libdocument/ev-document-text.c
++++ b/libdocument/ev-document-text.c
+@@ -42,7 +42,6 @@
+ 	return iface->get_text (document_text, page);
+ }
+ 
+-
+ gboolean
+ ev_document_text_get_text_layout (EvDocumentText   *document_text,
+ 				  EvPage           *page,
+--- a/libdocument/ev-document.c
++++ b/libdocument/ev-document.c
+@@ -388,7 +388,6 @@
+ 	return klass->get_page (document, index);
+ }
+ 
+-
+ #ifdef ENABLE_SYNCTEX
+ static gboolean
+ _ev_document_support_synctex (EvDocument *document)
+--- a/libdocument/ev-file-helpers.h
++++ b/libdocument/ev-file-helpers.h
+@@ -66,7 +66,6 @@
+ 				       EvCompressionType  type,
+ 				       GError           **error);
+ 
+-
+ G_END_DECLS
+ 
+ #endif /* EV_FILE_HELPERS_H */
+--- a/libdocument/ev-form-field.h
++++ b/libdocument/ev-form-field.h
+@@ -209,7 +209,6 @@
+ GType        ev_form_field_signature_get_type (void) G_GNUC_CONST;
+ EvFormField *ev_form_field_signature_new      (gint                  id);
+ 
+-
+ G_END_DECLS
+ 
+ #endif /* !EV_FORM_FIELD_H */
+--- a/libdocument/ev-image.h
++++ b/libdocument/ev-image.h
+@@ -62,7 +62,6 @@
+ 					GdkPixbuf       *pixbuf);
+ const gchar *ev_image_get_tmp_uri      (EvImage         *image);
+ 
+-
+ G_END_DECLS
+ 
+ #endif /* __EV_IMAGE_H__ */
+--- a/libdocument/ev-render-context.h
++++ b/libdocument/ev-render-context.h
+@@ -52,7 +52,6 @@
+ 	gdouble scale;
+ };
+ 
+-
+ GType            ev_render_context_get_type        (void) G_GNUC_CONST;
+ EvRenderContext *ev_render_context_new             (EvPage          *page,
+ 						    gint             rotation,
+@@ -64,7 +63,6 @@
+ void             ev_render_context_set_scale       (EvRenderContext *rc,
+ 						    gdouble          scale);
+ 
+-
+ G_END_DECLS
+ 
+ #endif /* !EV_RENDER_CONTEXT */
+--- a/libdocument/ev-transition-effect.h
++++ b/libdocument/ev-transition-effect.h
+@@ -61,7 +61,6 @@
+ 	EV_TRANSITION_DIRECTION_OUTWARD
+ } EvTransitionEffectDirection;
+ 
+-
+ typedef struct EvTransitionEffect      EvTransitionEffect;
+ typedef struct EvTransitionEffectClass EvTransitionEffectClass;
+ 
+@@ -75,7 +74,6 @@
+ 	GObjectClass parent_class;
+ };
+ 
+-
+ GType                 ev_transition_effect_get_type           (void) G_GNUC_CONST;
+ 
+ EvTransitionEffect   *ev_transition_effect_new                (EvTransitionEffectType  type,
+--- a/libmisc/ev-page-action-widget.c
++++ b/libmisc/ev-page-action-widget.c
+@@ -305,7 +305,6 @@
+ 	return TRUE;
+ }
+ 
+-
+ static void
+ display_completion_text (GtkCellLayout      *cell_layout,
+ 			 GtkCellRenderer    *renderer,
+@@ -349,7 +348,6 @@
+ 			    EV_DOCUMENT_LINKS_COLUMN_LINK, &link,
+ 			    -1);
+ 
+-
+ 	if (link) {
+ 		text = ev_link_get_title (link);
+ 		g_object_unref (link);
+@@ -445,7 +443,6 @@
+ 	return filter_model;
+ }
+ 
+-
+ void
+ ev_page_action_widget_update_links_model (EvPageActionWidget *proxy, GtkTreeModel *model)
+ {
+--- a/libview/ev-page-accessible.c
++++ b/libview/ev-page-accessible.c
+@@ -37,7 +37,6 @@
+ 	gboolean          children_initialized;
+ };
+ 
+-
+ enum {
+ 	PROP_0,
+ 	PROP_VIEW_ACCESSIBLE,
+@@ -412,7 +411,6 @@
+ 	EvRectangle *next_word_end;
+ 	gint prev_offset, next_offset;
+ 
+-
+ 	if (!log_attrs[offset].is_white)
+ 		return FALSE;
+ 
+--- a/libview/ev-pixbuf-cache.c
++++ b/libview/ev-pixbuf-cache.c
+@@ -72,7 +72,6 @@
+ 	void (* job_finished) (EvPixbufCache *pixbuf_cache);
+ };
+ 
+-
+ enum
+ {
+ 	JOB_FINISHED,
+@@ -92,7 +91,6 @@
+ 						  gint                page,
+ 						  gfloat              scale);
+ 
+-
+ /* These are used for iterating through the prev and next arrays */
+ #define FIRST_VISIBLE_PREV(pixbuf_cache) \
+ 	(MAX (0, pixbuf_cache->preload_cache_size - pixbuf_cache->start_page))
+@@ -223,7 +221,6 @@
+ 	G_OBJECT_CLASS (ev_pixbuf_cache_parent_class)->dispose (object);
+ }
+ 
+-
+ EvPixbufCache *
+ ev_pixbuf_cache_new (GtkWidget       *view,
+ 		     EvDocumentModel *model,
+@@ -985,7 +982,6 @@
+ 	}
+ }
+ 
+-
+ void
+ ev_pixbuf_cache_style_changed (EvPixbufCache *pixbuf_cache)
+ {
+@@ -1265,7 +1261,6 @@
+ 	}
+ }
+ 
+-
+ /* Returns what the pixbuf cache thinks is */
+ 
+ GList *
+@@ -1356,4 +1351,3 @@
+ 		 EV_JOB_PRIORITY_URGENT);
+ }
+ 
+-
+--- a/libview/ev-pixbuf-cache.h
++++ b/libview/ev-pixbuf-cache.h
+@@ -39,8 +39,6 @@
+ #define EV_PIXBUF_CACHE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_PIXBUF_CACHE, EvPixbufCache))
+ #define EV_IS_PIXBUF_CACHE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EV_TYPE_PIXBUF_CACHE))
+ 
+-
+-
+ /* The coordinates in the rect here are at scale == 1.0, so that we can ignore
+  * resizings.  There is one per page, maximum.
+  */
+--- a/libview/ev-timeline.c
++++ b/libview/ev-timeline.c
+@@ -56,10 +56,8 @@
+ 
+ static guint signals [LAST_SIGNAL] = { 0, };
+ 
+-
+ G_DEFINE_TYPE_WITH_PRIVATE (EvTimeline, ev_timeline, G_TYPE_OBJECT)
+ 
+-
+ static void
+ ev_timeline_init (EvTimeline *timeline)
+ {
+--- a/libview/ev-timeline.h
++++ b/libview/ev-timeline.h
+@@ -59,7 +59,6 @@
+ 				    gdouble     progress);
+ };
+ 
+-
+ GType                 ev_timeline_get_type           (void) G_GNUC_CONST;
+ 
+ EvTimeline           *ev_timeline_new                (guint                    duration);
+@@ -84,7 +83,6 @@
+ 
+ gdouble               ev_timeline_get_progress       (EvTimeline             *timeline);
+ 
+-
+ G_END_DECLS
+ 
+ #endif /* __EV_TIMELINE_H__ */
+--- a/libview/ev-transition-animation.c
++++ b/libview/ev-transition-animation.c
+@@ -41,10 +41,8 @@
+ 	PROP_DEST_SURFACE
+ };
+ 
+-
+ G_DEFINE_TYPE_WITH_PRIVATE (EvTransitionAnimation, ev_transition_animation, EV_TYPE_TIMELINE)
+ 
+-
+ static void
+ ev_transition_animation_init (EvTransitionAnimation *animation)
+ {
+--- a/libview/ev-transition-animation.h
++++ b/libview/ev-transition-animation.h
+@@ -50,7 +50,6 @@
+ 	EvTimelineClass parent_class;
+ };
+ 
+-
+ GType                   ev_transition_animation_get_type           (void) G_GNUC_CONST;
+ 
+ EvTransitionAnimation * ev_transition_animation_new                (EvTransitionEffect    *effect);
+@@ -67,7 +66,6 @@
+ 								    GdkRectangle           page_area);
+ gboolean                ev_transition_animation_ready              (EvTransitionAnimation *animation);
+ 
+-
+ G_END_DECLS
+ 
+ #endif /* __EV_TRANSITION_ANIMATION_H__ */
+--- a/libview/ev-view-presentation.c
++++ b/libview/ev-view-presentation.c
+@@ -1385,7 +1385,6 @@
+ 	return TRUE;
+ }
+ 
+-
+ static void
+ add_change_page_binding_keypad (GtkBindingSet  *binding_set,
+ 				guint           keyval,
+--- a/libview/ev-view.c
++++ b/libview/ev-view.c
+@@ -5621,7 +5621,6 @@
+ 
+ /*** Drawing ***/
+ 
+-
+ static void
+ draw_rubberband (EvView             *view,
+ 		 cairo_t            *cr,
+@@ -5652,7 +5651,6 @@
+ 	cairo_restore (cr);
+ }
+ 
+-
+ static void
+ highlight_find_results (EvView *view, cairo_t *cr, int page)
+ {
+--- a/libview/ev-web-view.c
++++ b/libview/ev-web-view.c
+@@ -31,7 +31,6 @@
+ #include "ev-document-model.h"
+ #include "ev-jobs.h"
+ 
+-
+  typedef enum {
+  	EV_WEB_VIEW_FIND_NEXT,
+  	EV_WEB_VIEW_FIND_PREV
+@@ -322,7 +321,6 @@
+ 	web_view_update_range_and_current_page (webview);
+ }
+ 
+-
+ gboolean
+ ev_web_view_next_page (EvWebView *webview)
+ {
+--- a/libview/ev-web-view.h
++++ b/libview/ev-web-view.h
+@@ -35,7 +35,6 @@
+ #include <glib-object.h>
+ G_BEGIN_DECLS
+ 
+-
+ typedef struct _EvWebView       EvWebView;
+ typedef struct _EvWebViewClass  EvWebViewClass;
+ 
+--- a/previewer/ev-previewer-window.c
++++ b/previewer/ev-previewer-window.c
+@@ -621,7 +621,6 @@
+ 	return object;
+ }
+ 
+-
+ static void
+ ev_previewer_window_class_init (EvPreviewerWindowClass *klass)
+ {
+--- a/shell/eggfindbar.c
++++ b/shell/eggfindbar.c
+@@ -573,7 +573,6 @@
+   g_object_thaw_notify (G_OBJECT (find_bar));
+ }
+ 
+-
+ /**
+  * egg_find_bar_get_search_string:
+  *
+--- a/shell/eggfindbar.h
++++ b/shell/eggfindbar.h
+@@ -77,4 +77,3 @@
+ 
+ #endif /* __EGG_FIND_BAR_H__ */
+ 
+-
+--- a/shell/ev-application.c
++++ b/shell/ev-application.c
+@@ -21,7 +21,6 @@
+  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+  */
+ 
+-
+ #include <config.h>
+ #include <stdlib.h>
+ #include <string.h>
+@@ -311,7 +310,6 @@
+ 	return empty_window;
+ }
+ 
+-
+ #ifdef ENABLE_DBUS
+ typedef struct {
+ 	gchar          *uri;
+--- a/shell/ev-bookmarks.h
++++ b/shell/ev-bookmarks.h
+@@ -50,8 +50,6 @@
+ void         ev_bookmarks_update        (EvBookmarks *bookmarks,
+                                          EvBookmark  *bookmark);
+ 
+-
+-
+ G_END_DECLS
+ 
+ #endif /* EV_BOOKMARKS_H */
+--- a/shell/ev-daemon.c
++++ b/shell/ev-daemon.c
+@@ -43,7 +43,6 @@
+ 
+ #define LOG g_debug
+ 
+-
+ #define EV_TYPE_DAEMON_APPLICATION              (ev_daemon_application_get_type ())
+ #define EV_DAEMON_APPLICATION(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), EV_TYPE_DAEMON_APPLICATION, EvDaemonApplication))
+ 
+--- a/shell/ev-history.c
++++ b/shell/ev-history.c
+@@ -24,7 +24,6 @@
+ 
+ #include "ev-history.h"
+ 
+-
+ enum
+ {
+ 	HISTORY_CHANGED,
+--- a/shell/ev-loading-message.c
++++ b/shell/ev-loading-message.c
+@@ -174,4 +174,3 @@
+         return message;
+ }
+ 
+-
+--- a/shell/ev-media-player-keys.h
++++ b/shell/ev-media-player-keys.h
+@@ -37,7 +37,6 @@
+ typedef struct _EvMediaPlayerKeys EvMediaPlayerKeys;
+ typedef struct _EvMediaPlayerKeysClass EvMediaPlayerKeysClass;
+ 
+-
+ GType	           ev_media_player_keys_get_type  (void) G_GNUC_CONST;
+ 
+ EvMediaPlayerKeys *ev_media_player_keys_new	  (void);
+--- a/shell/ev-navigation-action.c
++++ b/shell/ev-navigation-action.c
+@@ -26,7 +26,6 @@
+ #include "ev-navigation-action.h"
+ #include "ev-navigation-action-widget.h"
+ 
+-
+ enum
+ {
+ 	WIDGET_ACTIVATE_LINK,
+--- a/shell/ev-open-recent-action.c
++++ b/shell/ev-open-recent-action.c
+@@ -24,7 +24,6 @@
+ 
+ #include "ev-open-recent-action.h"
+ 
+-
+ enum {
+ 	ITEM_ACTIVATED,
+ 	N_SIGNALS
+--- a/shell/ev-password-view.c
++++ b/shell/ev-password-view.c
+@@ -18,7 +18,6 @@
+  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+  */
+ 
+-
+ #ifdef HAVE_CONFIG_H
+ #include "config.h"
+ #endif
+@@ -47,7 +46,6 @@
+ 
+ static guint password_view_signals [LAST_SIGNAL] = { 0 };
+ 
+-
+ G_DEFINE_TYPE_WITH_PRIVATE (EvPasswordView, ev_password_view, GTK_TYPE_VIEWPORT)
+ 
+ static void
+--- a/shell/ev-sidebar-attachments.c
++++ b/shell/ev-sidebar-attachments.c
+@@ -631,7 +631,6 @@
+ 	g_object_unref (job);
+ }
+ 
+-
+ static void
+ ev_sidebar_attachments_document_changed_cb (EvDocumentModel      *model,
+ 					    GParamSpec           *pspec,
+--- a/shell/ev-sidebar-bookmarks.c
++++ b/shell/ev-sidebar-bookmarks.c
+@@ -122,7 +122,6 @@
+         GtkTreeModel              *model;
+         GtkTreeIter                iter;
+ 
+-
+         selection = gtk_tree_view_get_selection (tree_view);
+         if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
+                 GtkTreePath *path;
+--- a/shell/ev-sidebar-layers.c
++++ b/shell/ev-sidebar-layers.c
+@@ -239,7 +239,6 @@
+ 	gtk_tree_selection_set_mode (gtk_tree_view_get_selection (tree_view),
+ 				     GTK_SELECTION_NONE);
+ 
+-
+ 	column = gtk_tree_view_column_new ();
+ 
+ 	renderer = gtk_cell_renderer_toggle_new ();
+--- a/shell/ev-sidebar-links.c
++++ b/shell/ev-sidebar-links.c
+@@ -379,7 +379,6 @@
+ 	return FALSE;
+ }
+ 
+-
+ static void
+ ev_sidebar_links_construct (EvSidebarLinks *ev_sidebar_links)
+ {
+@@ -425,7 +424,6 @@
+ 					     "markup", EV_DOCUMENT_LINKS_COLUMN_MARKUP,
+ 					     NULL);
+ 
+-
+ 	renderer = gtk_cell_renderer_text_new ();
+ 	gtk_tree_view_column_pack_end (GTK_TREE_VIEW_COLUMN (column), renderer, FALSE);
+ 	gtk_tree_view_column_set_attributes (GTK_TREE_VIEW_COLUMN (column), renderer,
+@@ -566,7 +564,6 @@
+ 	}
+ }
+ 
+-
+ static gint
+ page_link_tree_sort (gconstpointer a, gconstpointer b, void *data)
+ {
+--- a/shell/ev-sidebar-links.h
++++ b/shell/ev-sidebar-links.h
+@@ -63,4 +63,3 @@
+ 
+ #endif /* __EV_SIDEBAR_LINKS_H__ */
+ 
+-
+--- a/shell/ev-sidebar-page.c
++++ b/shell/ev-sidebar-page.c
+@@ -74,7 +74,6 @@
+ 	return iface->get_label (sidebar_page);
+ }
+ 
+-
+ static void
+ ev_sidebar_page_default_init (EvSidebarPageInterface *iface)
+ {
+--- a/shell/ev-sidebar-page.h
++++ b/shell/ev-sidebar-page.h
+@@ -58,7 +58,6 @@
+ 				                 EvDocumentModel *model);
+ const gchar*  ev_sidebar_page_get_label         (EvSidebarPage *page);
+ 
+-
+ G_END_DECLS
+ 
+ #endif /* EV_SIDEBAR_PAGE */
+--- a/shell/ev-sidebar-thumbnails.c
++++ b/shell/ev-sidebar-thumbnails.c
+@@ -245,7 +245,6 @@
+ 	return cache;
+ }
+ 
+-
+ static void
+ ev_sidebar_thumbnails_dispose (GObject *object)
+ {
+--- a/shell/ev-sidebar-thumbnails.h
++++ b/shell/ev-sidebar-thumbnails.h
+@@ -56,4 +56,3 @@
+ 
+ #endif /* __EV_SIDEBAR_THUMBNAILS_H__ */
+ 
+-
+--- a/shell/ev-sidebar.c
++++ b/shell/ev-sidebar.c
+@@ -446,7 +446,6 @@
+ 	gtk_list_store_move_before(GTK_LIST_STORE(ev_sidebar->priv->page_model),
+ 					   &iter, NULL);
+ 
+-
+ 	/* Set the first item added as active */
+ 	gtk_tree_model_get_iter_first (ev_sidebar->priv->page_model, &iter);
+ 	gtk_tree_model_get (ev_sidebar->priv->page_model,
+--- a/shell/ev-sidebar.h
++++ b/shell/ev-sidebar.h
+@@ -64,4 +64,3 @@
+ 
+ #endif /* __EV_SIDEBAR_H__ */
+ 
+-
+--- a/shell/ev-window.c
++++ b/shell/ev-window.c
+@@ -418,7 +418,6 @@
+ 	G_GNUC_END_IGNORE_DEPRECATIONS;
+ }
+ 
+-
+ static void
+ ev_window_setup_action_sensitivity (EvWindow *ev_window)
+ {
+@@ -1555,7 +1554,6 @@
+ 		ev_document_model_set_scale (model, g_settings_get_double (settings, "zoom"));
+ }
+ 
+-
+ static void
+ ev_window_clear_thumbnail_job (EvWindow *ev_window)
+ {
+@@ -3636,7 +3634,6 @@
+ 		GtkWidget *dialog;
+ 		GError    *error = NULL;
+ 
+-
+ 		ev_print_operation_get_error (op, &error);
+ 
+ 		/* The message area is already used by
+@@ -3891,7 +3888,6 @@
+ 		return FALSE;
+ 	}
+ 
+-
+ 	text = g_markup_printf_escaped (_("Save a copy of document “%s” before closing?"),
+ 					gtk_window_get_title (GTK_WINDOW (ev_window)));
+ 
+@@ -4414,7 +4410,6 @@
+                                          _("Running in presentation mode"));
+ }
+ 
+-
+ static void
+ ev_window_uninhibit_screensaver (EvWindow *window)
+ {
+@@ -4727,7 +4722,6 @@
+ 	ev_window_update_actions (window);
+ }
+ 
+-
+ static void
+ ev_window_cmd_edit_rotate_left (GtkAction *action, EvWindow *ev_window)
+ {
+@@ -5977,7 +5971,6 @@
+ 		 * the new expanded window size.
+ 		 */
+ 
+-
+ 		if (ev_window->priv->chrome & EV_CHROME_SIDEBAR)
+ 		{
+ 			GtkAllocation alloc;
+@@ -6491,7 +6484,6 @@
+ 	{ "EditSaveSettings", NULL, N_("Save Current Settings as _Default"), "<control>T", NULL,
+ 	  G_CALLBACK (ev_window_cmd_edit_save_settings) },
+ 
+-
+         /* View menu */
+         { "ViewZoomIn", "zoom-in", N_("Zoom _In"), "<control>plus",
+           N_("Enlarge the document"),
+@@ -7746,7 +7738,6 @@
+         ev_atril_window_emit_document_loaded (window->priv->skeleton, window->priv->uri);
+ }
+ 
+-
+ #ifdef ENABLE_SYNCTEX
+ static gboolean
+ handle_sync_view_cb (EvAtrilWindow        *object,
+--- a/shell/ev-window.h
++++ b/shell/ev-window.h
+@@ -58,7 +58,6 @@
+ #define EV_IS_WINDOW_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE((klass), EV_TYPE_WINDOW))
+ #define EV_WINDOW_GET_CLASS(object)	(G_TYPE_INSTANCE_GET_CLASS((object), EV_TYPE_WINDOW, EvWindowClass))
+ 
+-
+ struct _EvWindow {
+ 	GtkApplicationWindow base_instance;
+ 	EvWindowPrivate     *priv;
+@@ -87,7 +86,6 @@
+ 					 int		 last_page);
+ const gchar *	ev_window_get_dbus_object_path (EvWindow *ev_window);
+ 
+-
+ G_END_DECLS
+ 
+ #endif /* !EV_WINDOW_H */
+--- a/shell/main.c
++++ b/shell/main.c
+@@ -36,7 +36,6 @@
+ #include "eggsmclient.h"
+ #include "eggdesktopfile.h"
+ 
+-
+ static gchar   *ev_page_label;
+ static gchar   *ev_find_string;
+ static gint     ev_page_index = 0;
+@@ -48,7 +47,6 @@
+ static gchar   *print_settings;
+ static const char **file_arguments = NULL;
+ 
+-
+ static gboolean
+ option_version_cb (const gchar *option_name,
+                    const gchar *value,
+@@ -206,8 +204,6 @@
+ 			continue;
+ 		}
+ 
+-
+-
+ 		ev_application_open_uri_at_dest (EV_APP, uri, screen, dest,
+ 						 mode, ev_find_string,
+ 						 GDK_CURRENT_TIME);
diff -Nru atril-1.26.0/debian/patches/0006-comics-Use-libarchive-to-unpack-documents.patch atril-1.26.0/debian/patches/0006-comics-Use-libarchive-to-unpack-documents.patch
--- atril-1.26.0/debian/patches/0006-comics-Use-libarchive-to-unpack-documents.patch	1970-01-01 01:00:00.000000000 +0100
+++ atril-1.26.0/debian/patches/0006-comics-Use-libarchive-to-unpack-documents.patch	2024-01-23 10:06:08.000000000 +0100
@@ -0,0 +1,1814 @@
+From aa8e9dad472cbadc96719a8f521768aeeb0913f0 Mon Sep 17 00:00:00 2001
+From: lukefromdc <lukefromdc@hushmail.com>
+Date: Mon, 25 Dec 2023 15:11:04 -0500
+Subject: [PATCH 2/2] comics: Use libarchive to unpack documents
+
+This commit eliminates the use of external commands for opening
+comic documents, and uses libarchive instead.
+
+Signed-off-by: Mike Gabriel <mike.gabriel@das-netzwerkteam.de>
+---
+ backend/comics/Makefile.am       |    5 +-
+ backend/comics/comics-document.c | 1143 +++++++++++-------------------
+ backend/comics/comics-document.h |    7 +-
+ backend/comics/ev-archive.c      |  323 +++++++++
+ backend/comics/ev-archive.h      |   56 ++
+ configure.ac                     |    3 +
+ libdocument/ev-document.h        |    1 +
+ 7 files changed, 799 insertions(+), 739 deletions(-)
+ create mode 100644 backend/comics/ev-archive.c
+ create mode 100644 backend/comics/ev-archive.h
+
+diff --git a/backend/comics/Makefile.am b/backend/comics/Makefile.am
+index b27f9b85..77f3dedb 100644
+--- a/backend/comics/Makefile.am
++++ b/backend/comics/Makefile.am
+@@ -12,12 +12,15 @@ backend_LTLIBRARIES = libcomicsdocument.la
+ 
+ libcomicsdocument_la_SOURCES = \
+ 	comics-document.c      \
+-	comics-document.h
++	comics-document.h      \
++	ev-archive.c     \
++	ev-archive.h
+ 
+ libcomicsdocument_la_LDFLAGS = $(BACKEND_LIBTOOL_FLAGS)
+ libcomicsdocument_la_LIBADD =				\
+ 	$(top_builddir)/libdocument/libatrildocument.la	\
+ 	$(BACKEND_LIBS)					\
++	$(COMICS_LIBS)					\
+ 	$(LIB_LIBS)
+ 
+ backend_in_files = comicsdocument.atril-backend.desktop.in
+diff --git a/backend/comics/comics-document.c b/backend/comics/comics-document.c
+index ed02a35c..1da1eee2 100644
+--- a/backend/comics/comics-document.c
++++ b/backend/comics/comics-document.c
+@@ -30,24 +30,17 @@
+ #include <glib/gstdio.h>
+ #include <gio/gio.h>
+ 
+-#include <sys/wait.h>
+-
+ #include "comics-document.h"
+ #include "ev-document-misc.h"
+ #include "ev-document-thumbnails.h"
+ #include "ev-file-helpers.h"
++#include "ev-archive.h"
++#include <archive.h>
++#include <archive_entry.h>
+ 
+ #define EV_EOL "\n"
+ 
+-typedef enum
+-{
+-	RARLABS,
+-	GNAUNRAR,
+-	UNZIP,
+-	P7ZIP,
+-	TAR,
+-	UNARCHIVER
+-} ComicBookDecompressType;
++#define BLOCK_SIZE 10240
+ 
+ typedef struct _ComicsDocumentClass ComicsDocumentClass;
+ 
+@@ -58,398 +51,269 @@ struct _ComicsDocumentClass
+ 
+ struct _ComicsDocument
+ {
+-	EvDocument parent_instance;
+-
+-	gchar    *archive, *dir;
+-	GPtrArray *page_names;
+-	gchar    *selected_command, *alternative_command;
+-	gchar    *extract_command, *list_command, *decompress_tmp;
+-	gboolean regex_arg;
+-	gint     offset;
+-	ComicBookDecompressType command_usage;
++	EvDocument     parent_instance;
++	EvArchive     *archive;
++	gchar         *archive_path;
++	gchar         *archive_uri;
++	GPtrArray     *page_names; /* elem: char * */
++	GHashTable    *page_positions; /* key: char *, value: uint + 1 */
++
+ };
+ 
+-#define OFFSET_7Z 53
+-#define OFFSET_ZIP 2
+-#define NO_OFFSET 0
+-
+-/* For perfomance reasons of 7z* we've choosen to decompress on the temporary
+- * directory instead of decompressing on the stdout */
+-
+-/**
+- * @extract: command line arguments to pass to extract a file from the archive
+- *   to stdout.
+- * @list: command line arguments to list the archive contents
+- * @decompress_tmp: command line arguments to pass to extract the archive
+- *   into a directory.
+- * @regex_arg: whether the command can accept regex expressions
+- * @offset: the position offset of the filename on each line in the output of
+- *   running the @list command
+- */
+-typedef struct {
+-        char *extract;
+-        char *list;
+-        char *decompress_tmp;
+-        gboolean regex_arg;
+-        gint offset;
+-} ComicBookDecompressCommand;
++static void       
++comics_document_document_thumbnails_iface_init (EvDocumentThumbnailsInterface *iface);
++EV_BACKEND_REGISTER_WITH_CODE (ComicsDocument, comics_document,
++    {
++        EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_THUMBNAILS,
++                        comics_document_document_thumbnails_iface_init);
++    } );
++
++#define FORMAT_UNKNOWN     0
++#define FORMAT_SUPPORTED   1
++#define FORMAT_UNSUPPORTED 2
++
++/* Returns a GHashTable of:
++ * <key>: file extensions
++ * <value>: degree of support in gdk-pixbuf */
++static GHashTable *
++get_image_extensions(void)
++{
++	GHashTable *extensions;
++	GSList *formats = gdk_pixbuf_get_formats ();
++	GSList *l;
++	guint i;
++	const char *known_image_formats[] = {
++		"png",
++		"jpg",
++		"jpeg",
++		"webp"
++	};
++
++	extensions = g_hash_table_new_full (g_str_hash, g_str_equal,
++					    g_free, NULL);
++	for (l = formats; l != NULL; l = l->next) {
++		int i;
++		gchar **ext = gdk_pixbuf_format_get_extensions (l->data);
++
++		for (i = 0; ext[i] != NULL; i++) {
++			g_hash_table_insert (extensions,
++					     g_strdup (ext[i]),
++					     GINT_TO_POINTER (FORMAT_SUPPORTED));
++		}
+ 
+-static const ComicBookDecompressCommand command_usage_def[] = {
+-        /* RARLABS unrar */
+-	{"%s p -c- -ierr --", "%s vb -c- -- %s", NULL             , FALSE, NO_OFFSET},
++		g_strfreev (ext);
++	}
++	g_slist_free (formats);
+ 
+-        /* GNA! unrar */
+-	{NULL               , "%s t %s"        , "%s -xf %s %s"   , FALSE, NO_OFFSET},
++	/* Add known image formats that aren't supported by gdk-pixbuf */
++	for (i = 0; i < G_N_ELEMENTS (known_image_formats); i++) {
++		if (!g_hash_table_lookup (extensions, known_image_formats[i])) {
++			g_hash_table_insert (extensions,
++					     g_strdup (known_image_formats[i]),
++					     GINT_TO_POINTER (FORMAT_UNSUPPORTED));
++		}
++	}
+ 
+-        /* unzip */
+-	{"%s -p -C --"      , "%s %s"          , NULL             , TRUE , OFFSET_ZIP},
++	return extensions;
++}
+ 
+-        /* 7zip */
+-	{NULL               , "%s l -- %s"     , "%s x -y %s -o%s", FALSE, OFFSET_7Z},
++static int
++has_supported_extension (const char *name,
++			 GHashTable *supported_extensions)
++{
++	gboolean ret = FALSE;
++	gchar *suffix;
++	suffix = g_strrstr (name, ".");
++	if (!suffix)
++		return ret;
+ 
+-        /* tar */
+-	{"%s -xOf"          , "%s -tf %s"      , NULL             , FALSE, NO_OFFSET},
++	suffix = g_ascii_strdown (suffix + 1, -1);
++	ret = GPOINTER_TO_INT (g_hash_table_lookup (supported_extensions, suffix));
++	g_free (suffix);
+ 
+-	/* UNARCHIVER */
+-	{"unar -o -"	    , "%s %s"	       , NULL		  , FALSE, NO_OFFSET}
+-};
++	return ret;
++}
+ 
+-static void       comics_document_document_thumbnails_iface_init (EvDocumentThumbnailsInterface *iface);
++#define APPLE_DOUBLE_PREFIX "._"
++static gboolean
++is_apple_double (const char *name)
++{
++char *basename;
++	gboolean ret = FALSE;
+ 
+-static GSList*    get_supported_image_extensions (void);
+-static void       get_page_size_area_prepared_cb (GdkPixbufLoader *loader,
+-						  gpointer data);
+-static void       render_pixbuf_size_prepared_cb (GdkPixbufLoader *loader,
+-						  gint width,
+-						  gint height,
+-						  gpointer data);
+-static char**     extract_argv                   (EvDocument *document,
+-						  gint page);
++	basename = g_path_get_basename (name);
++	if (basename == NULL) {
++		g_debug ("Filename '%s' doesn't have a basename?", name);
++		return ret;
++	}
++	ret = g_str_has_prefix (basename, APPLE_DOUBLE_PREFIX);
++	g_free (basename);
+ 
+-EV_BACKEND_REGISTER_WITH_CODE (ComicsDocument, comics_document,
+-	{
+-		EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_THUMBNAILS,
+-						comics_document_document_thumbnails_iface_init);
+-	} );
+-
+-/**
+- * comics_regex_quote:
+- * @unquoted_string: a literal string
+- *
+- * Quotes a string so unzip will not interpret the regex expressions of
+- * @unquoted_string. Basically, this functions uses [] to disable regex
+- * expressions. The return value must be freed with * g_free()
+- *
+- * Return value: quoted and disabled-regex string
+- **/
+-static gchar *
+-comics_regex_quote (const gchar *unquoted_string)
++	return ret;
++}
++
++static gboolean
++archive_reopen_if_needed (ComicsDocument  *comics_document,
++			  const char      *page_wanted,
++			  GError         **error)
+ {
+-	const gchar *p;
+-	GString *dest;
+-
+-	dest = g_string_new ("'");
+-
+-	p = unquoted_string;
+-
+-	while (*p) {
+-		switch (*p) {
+-			/* * matches a sequence of 0 or more characters */
+-			case ('*'):
+-			/* ? matches exactly 1 charactere */
+-			case ('?'):
+-			/* [...]  matches any single character found inside
+-			 * the brackets. Disabling the first bracket is enough.
+-			 */
+-			case ('['):
+-				g_string_append (dest, "[");
+-				g_string_append_c (dest, *p);
+-				g_string_append (dest, "]");
+-				break;
+-			/* Because \ escapes regex expressions that we are
+-			 * disabling for unzip, we need to disable \ too */
+-			case ('\\'):
+-				g_string_append (dest, "[\\\\]");
+-				break;
+-			/* Escape single quote inside the string */
+-			case ('\''):
+-				g_string_append (dest, "'\\''");
+-				break;
+-			default:
+-				g_string_append_c (dest, *p);
+-				break;
++	const char *current_page;
++	guint current_page_idx, page_wanted_idx;
++
++	if (ev_archive_at_entry (comics_document->archive)) {
++		current_page = ev_archive_get_entry_pathname (comics_document->archive);
++		if (current_page) {
++			current_page_idx = GPOINTER_TO_UINT (g_hash_table_lookup (comics_document->page_positions, current_page));
++			page_wanted_idx = GPOINTER_TO_UINT (g_hash_table_lookup (comics_document->page_positions, page_wanted));
++
++			if (current_page_idx != 0 &&
++			    page_wanted_idx != 0 &&
++			    page_wanted_idx > current_page_idx)
++				return TRUE;
+ 		}
+-		++p;
++
++		ev_archive_reset (comics_document->archive);
+ 	}
+-	g_string_append_c (dest, '\'');
+-	return g_string_free (dest, FALSE);
++return ev_archive_open_filename (comics_document->archive, comics_document->archive_path, error);
+ }
+ 
+-/* This function manages the command for decompressing a comic book */
+-static gboolean
+-comics_decompress_temp_dir (const gchar *command_decompress_tmp,
+-			    const gchar *command,
+-			    GError      **error)
++static GPtrArray *
++comics_document_list (ComicsDocument  *comics_document,
++		      GError         **error)
+ {
+-	gboolean success;
+-	gchar *std_out, *basename;
+-	GError *err = NULL;
+-	gint retval;
+-
+-	success = g_spawn_command_line_sync (command_decompress_tmp, &std_out,
+-					     NULL, &retval, &err);
+-	basename = g_path_get_basename (command);
+-	if (!success) {
+-		g_set_error (error,
+-			     EV_DOCUMENT_ERROR,
+-			     EV_DOCUMENT_ERROR_INVALID,
+-			     _("Error launching the command “%s” in order to "
+-			     "decompress the comic book: %s"),
+-			     basename,
+-			     err->message);
+-		g_error_free (err);
+-	} else if (WIFEXITED (retval)) {
+-		if (WEXITSTATUS (retval) == EXIT_SUCCESS) {
+-			g_free (std_out);
+-			g_free (basename);
+-			return TRUE;
+-		} else {
+-			g_set_error (error,
++GPtrArray *array = NULL;
++	gboolean has_encrypted_files, has_unsupported_images, has_archive_errors;
++	GHashTable *supported_extensions = NULL;
++
++	if (!ev_archive_open_filename (comics_document->archive, comics_document->archive_path, error)) {
++		if (*error != NULL) {
++			g_warning ("Fatal error handling archive (%s): %s", G_STRFUNC, (*error)->message);
++			g_clear_error (error);
++		}
++
++		g_set_error_literal (error,
+ 				     EV_DOCUMENT_ERROR,
+ 				     EV_DOCUMENT_ERROR_INVALID,
+-				     _("The command “%s” failed at "
+-				     "decompressing the comic book."),
+-				     basename);
+-			g_free (std_out);
++			     _("File is corrupted"));
++		goto out;
++	}
++
++	supported_extensions = get_image_extensions ();
++
++	has_encrypted_files = FALSE;
++	has_unsupported_images = FALSE;
++	has_archive_errors = FALSE;
++	array = g_ptr_array_sized_new (64);
++
++	while (1) {
++		const char *name;
++		int supported;
++
++		if (!ev_archive_read_next_header (comics_document->archive, error)) {
++			if (*error != NULL) {
++				g_debug ("Fatal error handling archive (%s): %s", G_STRFUNC, (*error)->message);
++				g_clear_error (error);
++				has_archive_errors = TRUE;
++				goto out;
++			}
++			break;
+ 		}
+-	} else {
+-		g_set_error (error,
+-			     EV_DOCUMENT_ERROR,
+-			     EV_DOCUMENT_ERROR_INVALID,
+-			     _("The command “%s” did not end normally."),
+-			     basename);
+-		g_free (std_out);
++
++		name = ev_archive_get_entry_pathname (comics_document->archive);
++		/* Ignore https://en.wikipedia.org/wiki/AppleSingle_and_AppleDouble_formats */
++		if (is_apple_double (name)) {
++			g_debug ("Not adding AppleDouble file '%s' to the list of files in the comics", name);
++			continue;
++		}
++
++		supported = has_supported_extension (name, supported_extensions);
++		if (supported == FORMAT_UNKNOWN) {
++			g_debug ("Not adding unsupported file '%s' to the list of files in the comics", name);
++			continue;
++		} else if (supported == FORMAT_UNSUPPORTED) {
++			g_debug ("Not adding unsupported image '%s' to the list of files in the comics", name);
++			has_unsupported_images = TRUE;
++			continue;
++		}
++
++		if (ev_archive_get_entry_is_encrypted (comics_document->archive)) {
++			g_debug ("Not adding encrypted file '%s' to the list of files in the comics", name);
++			has_encrypted_files = TRUE;
++			continue;
++		}
++
++		g_debug ("Adding '%s' to the list of files in the comics", name);
++		g_ptr_array_add (array, g_strdup (name));
+ 	}
+-	g_free (basename);
+-	return FALSE;
++out:
++	if (array->len == 0) {
++		g_ptr_array_free (array, TRUE);
++		array = NULL;
++
++		if (has_encrypted_files) {
++			g_set_error_literal (error,
++					     EV_DOCUMENT_ERROR,
++					     EV_DOCUMENT_ERROR_ENCRYPTED,
++					     _("Archive is encrypted"));
++		} else if (has_unsupported_images) {
++			g_set_error_literal (error,
++					     EV_DOCUMENT_ERROR,
++					     EV_DOCUMENT_ERROR_UNSUPPORTED_CONTENT,
++					     _("No supported images in archive"));
++		} else if (has_archive_errors) {
++			g_set_error_literal (error,
++					     EV_DOCUMENT_ERROR,
++					     EV_DOCUMENT_ERROR_INVALID,
++					     _("File is corrupted"));
++		} else {
++			g_set_error_literal (error,
++					     EV_DOCUMENT_ERROR,
++					     EV_DOCUMENT_ERROR_INVALID,
++					     _("No files in archive"));
++		}
++	}
++
++	if (supported_extensions)
++		g_hash_table_destroy (supported_extensions);
++	ev_archive_reset (comics_document->archive);
++	return array;
+ }
+ 
+-/* This function shows how to use the choosen command for decompressing a
+- * comic book file. It modifies fields of the ComicsDocument struct with
+- * this information */
+-static gboolean
+-comics_generate_command_lines (ComicsDocument *comics_document,
+-			       GError         **error)
++static GHashTable *
++save_positions (GPtrArray *page_names)
+ {
+-	gchar *quoted_file, *quoted_file_aux;
+-	gchar *quoted_command;
+-	ComicBookDecompressType type;
+-
+-	type = comics_document->command_usage;
+-	comics_document->regex_arg = command_usage_def[type].regex_arg;
+-	quoted_command = g_shell_quote (comics_document->selected_command);
+-	if (comics_document->regex_arg) {
+-		quoted_file = comics_regex_quote (comics_document->archive);
+-		quoted_file_aux = g_shell_quote (comics_document->archive);
+-		comics_document->list_command =
+-			   g_strdup_printf (command_usage_def[type].list,
+-			                    comics_document->alternative_command,
+-			                    quoted_file_aux);
+-		g_free (quoted_file_aux);
+-	} else {
+-		quoted_file = g_shell_quote (comics_document->archive);
+-		comics_document->list_command =
+-				g_strdup_printf (command_usage_def[type].list,
+-				                 quoted_command, quoted_file);
+-	}
+-	comics_document->extract_command =
+-			    g_strdup_printf (command_usage_def[type].extract,
+-				             quoted_command);
+-	comics_document->offset = command_usage_def[type].offset;
+-	if (command_usage_def[type].decompress_tmp) {
+-		comics_document->dir = ev_mkdtemp ("atril-comics-XXXXXX", error);
+-                if (comics_document->dir == NULL)
+-                        return FALSE;
+-
+-		/* unrar-free can't create directories, but ev_mkdtemp already created the dir */
+-
+-		comics_document->decompress_tmp =
+-			g_strdup_printf (command_usage_def[type].decompress_tmp,
+-					 quoted_command, quoted_file,
+-					 comics_document->dir);
+-		g_free (quoted_file);
+-		g_free (quoted_command);
+-
+-		if (!comics_decompress_temp_dir (comics_document->decompress_tmp,
+-		    comics_document->selected_command, error))
+-			return FALSE;
+-		else
+-			return TRUE;
+-	} else {
+-		g_free (quoted_file);
+-		g_free (quoted_command);
+-		return TRUE;
+-	}
++	guint i;
++	GHashTable *ht;
+ 
++	ht = g_hash_table_new (g_str_hash, g_str_equal);
++	for (i = 0; i < page_names->len; i++)
++		g_hash_table_insert (ht, page_names->pdata[i], GUINT_TO_POINTER(i + 1));
++	return ht;
+ }
+ 
+-/* This function chooses an external command for decompressing a comic
+- * book based on its mime tipe. */
++/*This function chooses the archive decompression support
++ * book based on its mime type. */
+ static gboolean
+-comics_check_decompress_command	(gchar          *mime_type,
++comics_check_decompress_support	(gchar          *mime_type,
+ 				 ComicsDocument *comics_document,
+ 				 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 (g_content_type_is_a (mime_type, "application/x-cbr") ||
+ 	    g_content_type_is_a (mime_type, "application/x-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
+-		* the Gna! project. Confusingly enough, the free software RAR
+-		* decoder is also named unrar. For this reason we need to add
+-		* some lines for disambiguation. Sorry for the added the
+-		* complexity but it's life :)
+-		* Finally, some distributions, like Debian, rename this free
+-		* option as unrar-free.
+-		* */
+-		comics_document->selected_command =
+-					g_find_program_in_path ("unrar");
+-		if (comics_document->selected_command) {
+-			/* We only use std_err to avoid printing useless error
+-			 * messages on the terminal */
+-			success =
+-				g_spawn_command_line_sync (
+-				              comics_document->selected_command,
+-							   &std_out, &std_err,
+-							   &retval, &err);
+-			if (!success) {
+-				g_propagate_error (error, err);
+-				g_error_free (err);
+-				return FALSE;
+-			/* I don't check retval status because RARLAB unrar
+-			 * doesn't have a way to return 0 without involving an
+-			 * operation with a file*/
+-			} else if (WIFEXITED (retval)) {
+-				if (g_strrstr (std_out,"freeware") != NULL)
+-					/* The RARLAB freeware client */
+-					comics_document->command_usage = RARLABS;
+-				else
+-					/* The Gna! free software client */
+-					comics_document->command_usage = GNAUNRAR;
+-
+-				g_free (std_out);
+-				g_free (std_err);
+-				return TRUE;
+-			}
+-		}
+-		/* The Gna! free software client with Debian naming convention */
+-		comics_document->selected_command =
+-				g_find_program_in_path ("unrar-free");
+-		if (comics_document->selected_command) {
+-			comics_document->command_usage = GNAUNRAR;
+-			return TRUE;
+-		}
+-		comics_document->selected_command =
+-				g_find_program_in_path ("lsar");
+-		if (comics_document->selected_command) {
+-			comics_document->command_usage = UNARCHIVER;
+-			return TRUE;
+-		}
+-		comics_document->selected_command =
+-				g_find_program_in_path ("bsdtar");
+-		if (comics_document->selected_command) {
+-			comics_document->command_usage = TAR;
++		if (ev_archive_set_archive_type (comics_document->archive, EV_ARCHIVE_TYPE_RAR))
+ 			return TRUE;
+-		}
+-
+ 	} else if (g_content_type_is_a (mime_type, "application/x-cbz") ||
+ 		   g_content_type_is_a (mime_type, "application/zip")) {
+-		/* InfoZIP's unzip program */
+-		comics_document->selected_command =
+-				g_find_program_in_path ("unzip");
+-		comics_document->alternative_command =
+-				g_find_program_in_path ("zipnote");
+-		if (comics_document->selected_command &&
+-		    comics_document->alternative_command) {
+-			comics_document->command_usage = UNZIP;
++		if (ev_archive_set_archive_type (comics_document->archive, EV_ARCHIVE_TYPE_ZIP))
+ 			return TRUE;
+-		}
+-		comics_document->selected_command =
+-				g_find_program_in_path ("bsdtar");
+-		if (comics_document->selected_command) {
+-			comics_document->command_usage = TAR;
+-			return TRUE;
+-		}
+-		comics_document->selected_command =
+-				g_find_program_in_path ("lsar");
+-		if (comics_document->selected_command) {
+-			comics_document->command_usage = UNARCHIVER;
+-			return TRUE;
+-		}
+-
+ 	} else if (g_content_type_is_a (mime_type, "application/x-cb7") ||
+ 		   g_content_type_is_a (mime_type, "application/x-7z-compressed")) {
+-		/* 7zr, 7za and 7z are the commands from the p7zip project able
+-		 * to decompress .7z files */
+-		comics_document->selected_command =
+-			g_find_program_in_path ("7zr");
+-		if (comics_document->selected_command) {
+-			comics_document->command_usage = P7ZIP;
++		if (ev_archive_set_archive_type (comics_document->archive, EV_ARCHIVE_TYPE_7Z))
+ 			return TRUE;
+-		}
+-		comics_document->selected_command =
+-			g_find_program_in_path ("7za");
+-		if (comics_document->selected_command) {
+-			comics_document->command_usage = P7ZIP;
+-			return TRUE;
+-		}
+-		comics_document->selected_command =
+-			g_find_program_in_path ("7z");
+-		if (comics_document->selected_command) {
+-			comics_document->command_usage = P7ZIP;
+-			return TRUE;
+-		}
+-		comics_document->selected_command =
+-				g_find_program_in_path ("bsdtar");
+-		if (comics_document->selected_command) {
+-			comics_document->command_usage = TAR;
+-			return TRUE;
+-		}
+-		comics_document->selected_command =
+-				g_find_program_in_path ("lsar");
+-		if (comics_document->selected_command) {
+-			comics_document->command_usage = UNARCHIVER;
+-			return TRUE;
+-		}
+ 	} else if (g_content_type_is_a (mime_type, "application/x-cbt") ||
+ 		   g_content_type_is_a (mime_type, "application/x-tar")) {
+-		/* tar utility (Tape ARchive) */
+-		comics_document->selected_command =
+-				g_find_program_in_path ("tar");
+-		if (comics_document->selected_command) {
+-			comics_document->command_usage = TAR;
++	if (ev_archive_set_archive_type (comics_document->archive, EV_ARCHIVE_TYPE_TAR))
+ 			return TRUE;
+-		}
+-		comics_document->selected_command =
+-				g_find_program_in_path ("bsdtar");
+-		if (comics_document->selected_command) {
+-			comics_document->command_usage = TAR;
+-			return TRUE;
+-		}
+-		comics_document->selected_command =
+-				g_find_program_in_path ("lsar");
+-		if (comics_document->selected_command) {
+-			comics_document->command_usage = UNARCHIVER;
+-			return TRUE;
+-		}
+ 	} else {
+ 		g_set_error (error,
+ 			     EV_DOCUMENT_ERROR,
+@@ -461,8 +325,9 @@ comics_check_decompress_command	(gchar          *mime_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"));
++		             _("libarchive lacks support for this comic book’s "
++			     "compression, please contact your distributor"));
++
+ 	return FALSE;
+ }
+ 
+@@ -470,43 +335,15 @@ static int
+ sort_page_names (gconstpointer a,
+                  gconstpointer b)
+ {
+-	const char *name_1, *name_2;
+-	gchar *key_1, *key_2;
+-	gboolean sort_last_1, sort_last_2;
+-	int compare;
+-
+-	name_1 = * (const char **) a;
+-	name_2 = * (const char **) b;
+-
+-	#define SORT_LAST_CHAR1 '.'
+-	#define SORT_LAST_CHAR2 '#'
+-
+-	sort_last_1 = name_1[0] == SORT_LAST_CHAR1 || name_1[0] == SORT_LAST_CHAR2;
+-	sort_last_2 = name_2[0] == SORT_LAST_CHAR1 || name_2[0] == SORT_LAST_CHAR2;
+-
+-	#undef SORT_LAST_CHAR1
+-	#undef SORT_LAST_CHAR2
+-
+-	if (sort_last_1 && !sort_last_2)
+-	{
+-		compare = +1;
+-	}
+-	else if (!sort_last_1 && sort_last_2)
+-	{
+-		compare = -1;
+-	}
+-	else
+-	{
+-		key_1 = g_utf8_collate_key_for_filename (name_1, -1);
+-		key_2 = g_utf8_collate_key_for_filename (name_2, -1);
+-
+-		compare = strcmp (key_1, key_2);
+-
+-		g_free (key_1);
+-		g_free (key_2);
+-	}
+-
+-	return compare;
++	gchar *temp1, *temp2;
++	gint ret;
++	temp1 = g_utf8_collate_key_for_filename (* (const char **) a, -1);
++	temp2 = g_utf8_collate_key_for_filename (* (const char **) b, -1);
++	ret = strcmp (temp1, temp2);
++
++	g_free (temp1);
++	g_free (temp2);
++	return ret;
+ }
+ 
+ static gboolean
+@@ -515,50 +352,13 @@ comics_document_load (EvDocument *document,
+ 		      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);
+-		return FALSE;
+-	} else if (!comics_generate_command_lines (comics_document, error)) {
+-		   g_free (mime_type);
+-		return FALSE;
+-	}
++	GFile *file;
++	file = g_file_new_for_uri (uri);
++	comics_document->archive_path = g_file_get_path (file);
++	g_object_unref (file);
+ 
+-	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);
+-
+-	if (!success) {
+-		return FALSE;
+-	} else if (!WIFEXITED(retval) || WEXITSTATUS(retval) != EXIT_SUCCESS) {
++	if (!comics_document->archive_path) {
+ 		g_set_error_literal (error,
+                                      EV_DOCUMENT_ERROR,
+                                      EV_DOCUMENT_ERROR_INVALID,
+@@ -566,58 +366,26 @@ comics_document_load (EvDocument *document,
+ 		return FALSE;
+ 	}
+ 
+-	/* FIXME: is this safe against filenames containing \n in the archive ? */
+-	cb_files = g_strsplit (std_out, EV_EOL, 0);
++	comics_document->archive_uri = g_strdup (uri);
++	mime_type = ev_file_get_mime_type (uri, FALSE, error);
+ 
+-	g_free (std_out);
++	if (mime_type == NULL)
++		return FALSE;
+ 
+-	if (!cb_files) {
+-		g_set_error_literal (error,
+-				     EV_DOCUMENT_ERROR,
+-				     EV_DOCUMENT_ERROR_INVALID,
+-				     _("No files in archive"));
++	if (!comics_check_decompress_support (mime_type, comics_document, error)) {
++		g_free (mime_type);
+ 		return FALSE;
+ 	}
+ 
+-        comics_document->page_names = g_ptr_array_sized_new (64);
+-
+-	supported_extensions = get_supported_image_extensions ();
+-	for (i = 0; cb_files[i] != NULL; i++) {
+-		if (comics_document->offset != NO_OFFSET) {
+-			if (g_utf8_strlen (cb_files[i],-1) >
+-			    comics_document->offset) {
+-				cb_file =
+-					g_utf8_offset_to_pointer (cb_files[i],
+-						       comics_document->offset);
+-			} else {
+-				continue;
+-			}
+-		} else {
+-			cb_file = cb_files[i];
+-		}
+-		gchar *suffix = g_strrstr (cb_file, ".");
+-		if (!suffix)
+-			continue;
+-		suffix = g_ascii_strdown (suffix + 1, -1);
+-		if (g_slist_find_custom (supported_extensions, suffix,
+-					 (GCompareFunc) strcmp) != NULL) {
+-                        g_ptr_array_add (comics_document->page_names,
+-                                         g_strstrip (g_strdup (cb_file)));
+-		}
+-		g_free (suffix);
+-	}
+-	g_strfreev (cb_files);
+-	g_slist_foreach (supported_extensions, (GFunc) g_free, NULL);
+-	g_slist_free (supported_extensions);
++	g_free (mime_type);
+ 
+-	if (comics_document->page_names->len == 0) {
+-		g_set_error (error,
+-			     EV_DOCUMENT_ERROR,
+-			     EV_DOCUMENT_ERROR_INVALID,
+-			     _("No images found in archive %s"),
+-			     uri);
++	/* Get list of files in archive */
++	comics_document->page_names = comics_document_list (comics_document, error);
++	if (!comics_document->page_names)
+ 		return FALSE;
+-	}
++
++	/* Keep an index */
++	comics_document->page_positions = save_positions (comics_document->page_names);
+ 
+         /* Now sort the pages */
+         g_ptr_array_sort (comics_document->page_names, sort_page_names);
+@@ -632,7 +400,7 @@ comics_document_save (EvDocument *document,
+ {
+ 	ComicsDocument *comics_document = COMICS_DOCUMENT (document);
+ 
+-	return ev_xfer_uri_simple (comics_document->archive, uri, error);
++	return ev_xfer_uri_simple (comics_document->archive_uri, uri, error);
+ }
+ 
+ static int
+@@ -646,6 +414,23 @@ comics_document_get_n_pages (EvDocument *document)
+ 	return comics_document->page_names->len;
+ }
+ 
++typedef struct {
++	gboolean got_info;
++	int height;
++	int width;
++} PixbufInfo;
++
++static void
++get_page_size_prepared_cb (GdkPixbufLoader *loader,
++			   int              width,
++			   int              height,
++			   PixbufInfo      *info)
++{
++	info->got_info = TRUE;
++	info->height = height;
++	info->width = width;
++}
++
+ static void
+ comics_document_get_page_size (EvDocument *document,
+ 			       EvPage     *page,
+@@ -653,74 +438,89 @@ comics_document_get_page_size (EvDocument *document,
+ 			       double     *height)
+ {
+ 	GdkPixbufLoader *loader;
+-	char **argv;
+-	guchar buf[1024];
+-	gboolean success, got_size = FALSE;
+-	gint outpipe = -1;
+-	GPid child_pid;
+-	gssize bytes;
+-	GdkPixbuf *pixbuf;
+-	gchar *filename;
++
+ 	ComicsDocument *comics_document = COMICS_DOCUMENT (document);
+ 
+-	if (!comics_document->decompress_tmp) {
+-		argv = extract_argv (document, page->index);
+-		success = g_spawn_async_with_pipes (NULL, argv, NULL,
+-						    G_SPAWN_SEARCH_PATH |
+-						    G_SPAWN_STDERR_TO_DEV_NULL,
+-						    NULL, NULL,
+-						    &child_pid,
+-						    NULL, &outpipe, NULL, NULL);
+-		g_strfreev (argv);
+-		g_return_if_fail (success == TRUE);
+-
+-		loader = gdk_pixbuf_loader_new ();
+-		g_signal_connect (loader, "area-prepared",
+-				  G_CALLBACK (get_page_size_area_prepared_cb),
+-				  &got_size);
+-
+-		while (outpipe >= 0) {
+-			bytes = read (outpipe, buf, 1024);
+-
+-			if (bytes > 0)
+-			gdk_pixbuf_loader_write (loader, buf, bytes, NULL);
+-			if (bytes <= 0 || got_size) {
+-				close (outpipe);
+-				outpipe = -1;
+-				gdk_pixbuf_loader_close (loader, NULL);
++	const char *page_path;
++	PixbufInfo info;
++	GError *error = NULL;
++
++	page_path = g_ptr_array_index (comics_document->page_names, page->index);
++
++	if (!archive_reopen_if_needed (comics_document, page_path, &error)) {
++		g_warning ("Fatal error opening archive: %s", error->message);
++		g_error_free (error);
++		return;
++	}
++
++	loader = gdk_pixbuf_loader_new ();
++	info.got_info = FALSE;
++	g_signal_connect (loader, "size-prepared",
++			  G_CALLBACK (get_page_size_prepared_cb),
++			  &info);
++
++	while (1) {
++		const char *name;
++		GError *error = NULL;
++
++		if (!ev_archive_read_next_header (comics_document->archive, &error)) {
++			if (error != NULL) {
++				g_warning ("Fatal error handling archive (%s): %s", G_STRFUNC, error->message);
++				g_error_free (error);
+ 			}
++			break;
+ 		}
+-		pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
+-		if (pixbuf) {
+-			if (width)
+-				*width = gdk_pixbuf_get_width (pixbuf);
+-			if (height)
+-				*height = gdk_pixbuf_get_height (pixbuf);
+-		}
+-		g_spawn_close_pid (child_pid);
+-		g_object_unref (loader);
+-	} else {
+-		filename = g_build_filename (comics_document->dir,
+-                                             (char *) comics_document->page_names->pdata[page->index],
+-					     NULL);
+-		pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
+-		if (pixbuf) {
+-			if (width)
+-				*width = gdk_pixbuf_get_width (pixbuf);
+-			if (height)
+-				*height = gdk_pixbuf_get_height (pixbuf);
+-			g_object_unref (pixbuf);
++
++		name = ev_archive_get_entry_pathname (comics_document->archive);
++		if (g_strcmp0 (name, page_path) == 0) {
++			char buf[BLOCK_SIZE];
++			gssize read;
++			gint64 left;
++
++			left = ev_archive_get_entry_size (comics_document->archive);
++			read = ev_archive_read_data (comics_document->archive, buf,
++						     MIN(BLOCK_SIZE, left), &error);
++			while (read > 0 && !info.got_info) {
++				if (!gdk_pixbuf_loader_write (loader, (guchar *) buf, read, &error)) {
++					read = -1;
++					break;
++				}
++				left -= read;
++				read = ev_archive_read_data (comics_document->archive, buf,
++							     MIN(BLOCK_SIZE, left), &error);
++			}
++			if (read < 0) {
++				g_warning ("Fatal error reading '%s' in archive: %s", name, error->message);
++				g_error_free (error);
++			}
++			break;
+ 		}
+-		g_free (filename);
++	}
++
++	gdk_pixbuf_loader_close (loader, NULL);
++	g_object_unref (loader);
++
++	if (info.got_info) {
++		if (width)
++			*width = info.width;
++		if (height)
++			*height = info.height;
+ 	}
+ }
+ 
+ static void
+-get_page_size_area_prepared_cb (GdkPixbufLoader *loader,
+-				gpointer         data)
++render_pixbuf_size_prepared_cb (GdkPixbufLoader *loader,
++				gint             width,
++				gint             height,
++				EvRenderContext *rc)
+ {
+-	gboolean *got_size = data;
+-	*got_size = TRUE;
++	// int scaled_width, scaled_height;
++	double scale = rc->scale;
++	int w = (width  * scale + 0.5);
++	int h = (height * scale + 0.5);
++
++	// ev_render_context_compute_scaled_size (rc, width, height, &scaled_width, &scaled_height);
++	gdk_pixbuf_loader_set_size (loader, w, h);
+ }
+ 
+ static GdkPixbuf *
+@@ -728,69 +528,68 @@ comics_document_render_pixbuf (EvDocument      *document,
+ 			       EvRenderContext *rc)
+ {
+ 	GdkPixbufLoader *loader;
+-	GdkPixbuf *rotated_pixbuf, *tmp_pixbuf;
+-	char **argv;
+-	guchar buf[4096];
+-	gboolean success;
+-	gint outpipe = -1;
+-	GPid child_pid;
+-	gssize bytes;
+-	gint width, height;
+-	gchar *filename;
++	GdkPixbuf *tmp_pixbuf;
++	GdkPixbuf *rotated_pixbuf = NULL;
+ 	ComicsDocument *comics_document = COMICS_DOCUMENT (document);
++	const char *page_path;
++	GError *error = NULL;
++
++	page_path = g_ptr_array_index (comics_document->page_names, rc->page->index);
++
++	if (!archive_reopen_if_needed (comics_document, page_path, &error)) {
++		g_warning ("Fatal error opening archive: %s", error->message);
++		g_error_free (error);
++		return NULL;
++	}
+ 
+-	if (!comics_document->decompress_tmp) {
+-		argv = extract_argv (document, rc->page->index);
+-		success = g_spawn_async_with_pipes (NULL, argv, NULL,
+-						    G_SPAWN_SEARCH_PATH |
+-						    G_SPAWN_STDERR_TO_DEV_NULL,
+-						    NULL, NULL,
+-						    &child_pid,
+-						    NULL, &outpipe, NULL, NULL);
+-		g_strfreev (argv);
+-		g_return_val_if_fail (success == TRUE, NULL);
+-
+-		loader = gdk_pixbuf_loader_new ();
+-		g_signal_connect (loader, "size-prepared",
+-				  G_CALLBACK (render_pixbuf_size_prepared_cb),
+-				  &rc->scale);
+-
+-		while (outpipe >= 0) {
+-			bytes = read (outpipe, buf, 4096);
+-
+-			if (bytes > 0) {
+-				gdk_pixbuf_loader_write (loader, buf, bytes,
+-				NULL);
++	loader = gdk_pixbuf_loader_new ();
++	g_signal_connect (loader, "size-prepared",
++			  G_CALLBACK (render_pixbuf_size_prepared_cb),
++			  rc);
++
++	while (1) {
++		const char *name;
++
++		if (!ev_archive_read_next_header (comics_document->archive, &error)) {
++			if (error != NULL) {
++				g_warning ("Fatal error handling archive (%s): %s", G_STRFUNC, error->message);
++				g_error_free (error);
++			}
++			break;
++		}
++
++		name = ev_archive_get_entry_pathname (comics_document->archive);
++		if (g_strcmp0 (name, page_path) == 0) {
++			size_t size = ev_archive_get_entry_size (comics_document->archive);
++			char *buf;
++			ssize_t read;
++
++			buf = g_malloc (size);
++			read = ev_archive_read_data (comics_document->archive, buf, size, &error);
++			if (read <= 0) {
++				if (read < 0) {
++					g_warning ("Fatal error reading '%s' in archive: %s", name, error->message);
++					g_error_free (error);
++				} else {
++					g_warning ("Read an empty file from the archive");
++				}
+ 			} else {
+-				close (outpipe);
+-				gdk_pixbuf_loader_close (loader, NULL);
+-				outpipe = -1;
++				gdk_pixbuf_loader_write (loader, (guchar *) buf, size, NULL);
+ 			}
++			g_free (buf);
++			gdk_pixbuf_loader_close (loader, NULL);
++			break;
+ 		}
+-		tmp_pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
+-		rotated_pixbuf =
+-			gdk_pixbuf_rotate_simple (tmp_pixbuf,
+-						  360 - rc->rotation);
+-		g_spawn_close_pid (child_pid);
+-		g_object_unref (loader);
+-	} else {
+-		filename =
+-			g_build_filename (comics_document->dir,
+-                                          (char *) comics_document->page_names->pdata[rc->page->index],
+-					  NULL);
+-
+-		gdk_pixbuf_get_file_info (filename, &width, &height);
+-
+-		tmp_pixbuf =
+-			gdk_pixbuf_new_from_file_at_size (
+-				    filename, width * (rc->scale) + 0.5,
+-				    height * (rc->scale) + 0.5, NULL);
+-		rotated_pixbuf =
+-			gdk_pixbuf_rotate_simple (tmp_pixbuf,
+-						  360 - rc->rotation);
+-		g_free (filename);
+-		g_object_unref (tmp_pixbuf);
+ 	}
++	tmp_pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
++	if (tmp_pixbuf) {
++		if ((rc->rotation % 360) == 0)
++			rotated_pixbuf = g_object_ref (tmp_pixbuf);
++		else
++			rotated_pixbuf = gdk_pixbuf_rotate_simple (tmp_pixbuf,
++								   360 - rc->rotation);
++	}
++	g_object_unref (loader);
+ 	return rotated_pixbuf;
+ }
+ 
+@@ -802,79 +601,26 @@ comics_document_render (EvDocument      *document,
+ 	cairo_surface_t *surface;
+ 
+ 	pixbuf = comics_document_render_pixbuf (document, rc);
++	if (!pixbuf)
++		return NULL;
+ 	surface = ev_document_misc_surface_from_pixbuf (pixbuf);
+-	g_object_unref (pixbuf);
+-
++	g_clear_object (&pixbuf);
+ 	return surface;
+ }
+ 
+-static void
+-render_pixbuf_size_prepared_cb (GdkPixbufLoader *loader,
+-				gint             width,
+-				gint             height,
+-				gpointer         data)
+-{
+-	double *scale = data;
+-	int w = (width  * (*scale) + 0.5);
+-	int h = (height * (*scale) + 0.5);
+-
+-	gdk_pixbuf_loader_set_size (loader, w, h);
+-}
+-
+-/**
+- * comics_remove_dir: Removes a directory recursively.
+- * Returns:
+- *   	0 if it was successfully deleted,
+- * 	-1 if an error occurred
+- */
+-static int
+-comics_remove_dir (gchar *path_name)
+-{
+-	GDir  *content_dir;
+-	const gchar *filename;
+-	gchar *filename_with_path;
+-
+-	if (g_file_test (path_name, G_FILE_TEST_IS_DIR)) {
+-		content_dir = g_dir_open  (path_name, 0, NULL);
+-		filename  = g_dir_read_name (content_dir);
+-		while (filename) {
+-			filename_with_path =
+-				g_build_filename (path_name,
+-						  filename, NULL);
+-			comics_remove_dir (filename_with_path);
+-			g_free (filename_with_path);
+-			filename = g_dir_read_name (content_dir);
+-		}
+-		g_dir_close (content_dir);
+-	}
+-	/* Note from g_remove() documentation: on Windows, it is in general not
+-	 * possible to remove a file that is open to some process, or mapped
+-	 * into memory.*/
+-	return (g_remove (path_name));
+-}
+-
+ static void
+ comics_document_finalize (GObject *object)
+ {
+ 	ComicsDocument *comics_document = COMICS_DOCUMENT (object);
+ 
+-	if (comics_document->decompress_tmp) {
+-		if (comics_remove_dir (comics_document->dir) == -1)
+-			g_warning (_("There was an error deleting “%s”."),
+-				   comics_document->dir);
+-		g_free (comics_document->dir);
+-	}
+-
+ 	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);
+ 	}
+-
+-	g_free (comics_document->archive);
+-	g_free (comics_document->selected_command);
+-	g_free (comics_document->alternative_command);
+-	g_free (comics_document->extract_command);
+-	g_free (comics_document->list_command);
++	g_clear_pointer (&comics_document->page_positions, g_hash_table_destroy);
++	g_clear_object (&comics_document->archive);
++	g_free (comics_document->archive_path);
++	g_free (comics_document->archive_uri);
+ 
+ 	G_OBJECT_CLASS (comics_document_parent_class)->finalize (object);
+ }
+@@ -897,33 +643,7 @@ comics_document_class_init (ComicsDocumentClass *klass)
+ static void
+ comics_document_init (ComicsDocument *comics_document)
+ {
+-	comics_document->archive = NULL;
+-	comics_document->page_names = NULL;
+-	comics_document->extract_command = NULL;
+-}
+-
+-/* Returns a list of file extensions supported by gdk-pixbuf */
+-static GSList*
+-get_supported_image_extensions(void)
+-{
+-	GSList *extensions = NULL;
+-	GSList *formats = gdk_pixbuf_get_formats ();
+-	GSList *l;
+-
+-	for (l = formats; l != NULL; l = l->next) {
+-		int i;
+-		gchar **ext = gdk_pixbuf_format_get_extensions (l->data);
+-
+-		for (i = 0; ext[i] != NULL; i++) {
+-			extensions = g_slist_append (extensions,
+-						     g_strdup (ext[i]));
+-		}
+-
+-		g_strfreev (ext);
+-	}
+-
+-	g_slist_free (formats);
+-	return extensions;
++	comics_document->archive = ev_archive_new ();
+ }
+ 
+ static GdkPixbuf *
+@@ -971,48 +691,3 @@ comics_document_document_thumbnails_iface_init (EvDocumentThumbnailsInterface *i
+ 	iface->get_thumbnail = comics_document_thumbnails_get_thumbnail;
+ 	iface->get_dimensions = comics_document_thumbnails_get_dimensions;
+ }
+-
+-static char**
+-extract_argv (EvDocument *document, gint page)
+-{
+-	ComicsDocument *comics_document = COMICS_DOCUMENT (document);
+-	char **argv;
+-	char *command_line, *quoted_archive, *quoted_filename;
+-	GError *err = NULL;
+-
+-	if (g_strrstr (comics_document->page_names->pdata[page], "--checkpoint-action="))
+-	{
+-		g_warning ("File unsupported\n");
+-		gtk_main_quit ();
+-	}
+-
+-        if (page >= comics_document->page_names->len)
+-                return NULL;
+-
+-	if (comics_document->regex_arg) {
+-		quoted_archive = g_shell_quote (comics_document->archive);
+-		quoted_filename =
+-			comics_regex_quote (comics_document->page_names->pdata[page]);
+-	} else {
+-		quoted_archive = g_shell_quote (comics_document->archive);
+-		quoted_filename = g_shell_quote (comics_document->page_names->pdata[page]);
+-	}
+-
+-	command_line = g_strdup_printf ("%s %s %s",
+-					comics_document->extract_command,
+-					quoted_archive,
+-					quoted_filename);
+-	g_free (quoted_archive);
+-	g_free (quoted_filename);
+-
+-	g_shell_parse_argv (command_line, NULL, &argv, &err);
+-	g_free (command_line);
+-
+-	if (err) {
+-		g_warning (_("Error %s"), err->message);
+-		g_error_free (err);
+-		return NULL;
+-	}
+-
+-	return argv;
+-}
+diff --git a/backend/comics/comics-document.h b/backend/comics/comics-document.h
+index f6a4b440..4417a69f 100644
+--- a/backend/comics/comics-document.h
++++ b/backend/comics/comics-document.h
+@@ -16,9 +16,9 @@
+  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+  */
+ 
+-#ifndef __COMICS_DOCUMENT_H__
+-#define __COMICS_DOCUMENT_H__
++#pragma once
+ 
++#include "ev-macros.h"
+ #include "ev-document.h"
+ 
+ G_BEGIN_DECLS
+@@ -30,9 +30,8 @@ G_BEGIN_DECLS
+ typedef struct _ComicsDocument ComicsDocument;
+ 
+ GType                 comics_document_get_type (void) G_GNUC_CONST;
++GType                 register_atril_backend  (GTypeModule *module);
+ 
+-G_MODULE_EXPORT GType register_atril_backend  (GTypeModule *module);
+ 
+ G_END_DECLS
+ 
+-#endif /* __COMICS_DOCUMENT_H__ */
+diff --git a/backend/comics/ev-archive.c b/backend/comics/ev-archive.c
+new file mode 100644
+index 00000000..568e1621
+--- /dev/null
++++ b/backend/comics/ev-archive.c
+@@ -0,0 +1,323 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
++/*
++ * Copyright (C) 2017, Bastien Nocera <hadess@hadess.net>
++ *
++ * 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, 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 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 "config.h"
++#include "ev-archive.h"
++
++#include <archive.h>
++#include <archive_entry.h>
++#include <gio/gio.h>
++
++#define BUFFER_SIZE (64 * 1024)
++
++struct _EvArchive {
++	GObject parent_instance;
++	EvArchiveType type;
++
++	/* libarchive */
++	struct archive *libar;
++	struct archive_entry *libar_entry;
++};
++
++G_DEFINE_TYPE(EvArchive, ev_archive, G_TYPE_OBJECT);
++
++static void
++ev_archive_finalize (GObject *object)
++{
++	EvArchive *archive = EV_ARCHIVE (object);
++
++	switch (archive->type) {
++	case EV_ARCHIVE_TYPE_RAR:
++	case EV_ARCHIVE_TYPE_ZIP:
++	case EV_ARCHIVE_TYPE_7Z:
++	case EV_ARCHIVE_TYPE_TAR:
++		g_clear_pointer (&archive->libar, archive_free);
++		break;
++	default:
++		break;
++	}
++
++	G_OBJECT_CLASS (ev_archive_parent_class)->finalize (object);
++}
++
++static void
++ev_archive_class_init (EvArchiveClass *klass)
++{
++        GObjectClass *object_class = (GObjectClass *) klass;
++
++        object_class->finalize = ev_archive_finalize;
++}
++
++EvArchive *
++ev_archive_new (void)
++{
++	return g_object_new (EV_TYPE_ARCHIVE, NULL);
++}
++
++static void
++libarchive_set_archive_type (EvArchive *archive,
++			     EvArchiveType archive_type)
++{
++	archive->type = archive_type;
++	archive->libar = archive_read_new ();
++
++	if (archive_type == EV_ARCHIVE_TYPE_ZIP)
++		archive_read_support_format_zip (archive->libar);
++	else if (archive_type == EV_ARCHIVE_TYPE_7Z)
++		archive_read_support_format_7zip (archive->libar);
++	else if (archive_type == EV_ARCHIVE_TYPE_TAR)
++		archive_read_support_format_tar (archive->libar);
++	else if (archive_type == EV_ARCHIVE_TYPE_RAR) {
++		archive_read_support_format_rar (archive->libar);
++		archive_read_support_format_rar5 (archive->libar);
++	} else
++		g_assert_not_reached ();
++}
++
++EvArchiveType
++ev_archive_get_archive_type (EvArchive *archive)
++{
++	g_return_val_if_fail (EV_IS_ARCHIVE (archive), EV_ARCHIVE_TYPE_NONE);
++
++	return archive->type;
++}
++
++gboolean
++ev_archive_set_archive_type (EvArchive *archive,
++			     EvArchiveType archive_type)
++{
++	g_return_val_if_fail (EV_IS_ARCHIVE (archive), FALSE);
++	g_return_val_if_fail (archive->type == EV_ARCHIVE_TYPE_NONE, FALSE);
++
++	switch (archive_type) {
++	case EV_ARCHIVE_TYPE_RAR:
++	case EV_ARCHIVE_TYPE_ZIP:
++	case EV_ARCHIVE_TYPE_7Z:
++	case EV_ARCHIVE_TYPE_TAR:
++		libarchive_set_archive_type (archive, archive_type);
++		break;
++	default:
++		g_assert_not_reached ();
++	}
++
++	return TRUE;
++}
++
++gboolean
++ev_archive_open_filename (EvArchive   *archive,
++			  const char  *path,
++			  GError     **error)
++{
++	int r;
++
++	g_return_val_if_fail (EV_IS_ARCHIVE (archive), FALSE);
++	g_return_val_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE, FALSE);
++	g_return_val_if_fail (path != NULL, FALSE);
++
++	switch (archive->type) {
++	case EV_ARCHIVE_TYPE_NONE:
++		g_assert_not_reached ();
++	case EV_ARCHIVE_TYPE_RAR:
++	case EV_ARCHIVE_TYPE_ZIP:
++	case EV_ARCHIVE_TYPE_7Z:
++	case EV_ARCHIVE_TYPE_TAR:
++		r = archive_read_open_filename (archive->libar, path, BUFFER_SIZE);
++		if (r != ARCHIVE_OK) {
++			g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
++				     "Error opening archive: %s", archive_error_string (archive->libar));
++			return FALSE;
++		}
++		return TRUE;
++	}
++
++	return FALSE;
++}
++
++static gboolean
++libarchive_read_next_header (EvArchive *archive,
++			     GError   **error)
++{
++	while (1) {
++		int r;
++
++		r = archive_read_next_header (archive->libar, &archive->libar_entry);
++		if (r != ARCHIVE_OK) {
++			if (r != ARCHIVE_EOF)
++				g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
++					     "Error reading archive: %s", archive_error_string (archive->libar));
++			return FALSE;
++		}
++
++		if (archive_entry_filetype (archive->libar_entry) != AE_IFREG) {
++			g_debug ("Skipping '%s' as it's not a regular file",
++				 archive_entry_pathname (archive->libar_entry));
++			continue;
++		}
++
++		g_debug ("At header for file '%s'", archive_entry_pathname (archive->libar_entry));
++
++		break;
++	}
++
++	return TRUE;
++}
++
++gboolean
++ev_archive_read_next_header (EvArchive *archive,
++			     GError   **error)
++{
++	g_return_val_if_fail (EV_IS_ARCHIVE (archive), FALSE);
++	g_return_val_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE, FALSE);
++
++	switch (archive->type) {
++	case EV_ARCHIVE_TYPE_NONE:
++		g_assert_not_reached ();
++	case EV_ARCHIVE_TYPE_RAR:
++	case EV_ARCHIVE_TYPE_ZIP:
++	case EV_ARCHIVE_TYPE_7Z:
++	case EV_ARCHIVE_TYPE_TAR:
++		return libarchive_read_next_header (archive, error);
++	}
++
++	return FALSE;
++}
++
++gboolean
++ev_archive_at_entry (EvArchive *archive)
++{
++	g_return_val_if_fail (EV_IS_ARCHIVE (archive), FALSE);
++	g_return_val_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE, FALSE);
++
++	return (archive->libar_entry != NULL);
++}
++
++const char *
++ev_archive_get_entry_pathname (EvArchive *archive)
++{
++	g_return_val_if_fail (EV_IS_ARCHIVE (archive), NULL);
++	g_return_val_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE, NULL);
++
++	switch (archive->type) {
++	case EV_ARCHIVE_TYPE_NONE:
++		g_assert_not_reached ();
++	case EV_ARCHIVE_TYPE_RAR:
++	case EV_ARCHIVE_TYPE_ZIP:
++	case EV_ARCHIVE_TYPE_7Z:
++	case EV_ARCHIVE_TYPE_TAR:
++		g_return_val_if_fail (archive->libar_entry != NULL, NULL);
++		return archive_entry_pathname (archive->libar_entry);
++	}
++
++	return NULL;
++}
++
++gint64
++ev_archive_get_entry_size (EvArchive *archive)
++{
++	g_return_val_if_fail (EV_IS_ARCHIVE (archive), -1);
++	g_return_val_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE, -1);
++
++	switch (archive->type) {
++	case EV_ARCHIVE_TYPE_NONE:
++		g_assert_not_reached ();
++	case EV_ARCHIVE_TYPE_RAR:
++	case EV_ARCHIVE_TYPE_ZIP:
++	case EV_ARCHIVE_TYPE_7Z:
++	case EV_ARCHIVE_TYPE_TAR:
++		g_return_val_if_fail (archive->libar_entry != NULL, -1);
++		return archive_entry_size (archive->libar_entry);
++	}
++
++	return -1;
++}
++
++gboolean
++ev_archive_get_entry_is_encrypted (EvArchive *archive)
++{
++	g_return_val_if_fail (EV_IS_ARCHIVE (archive), FALSE);
++	g_return_val_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE, FALSE);
++
++	switch (archive->type) {
++	case EV_ARCHIVE_TYPE_NONE:
++		g_assert_not_reached ();
++	case EV_ARCHIVE_TYPE_RAR:
++	case EV_ARCHIVE_TYPE_ZIP:
++	case EV_ARCHIVE_TYPE_7Z:
++	case EV_ARCHIVE_TYPE_TAR:
++		g_return_val_if_fail (archive->libar_entry != NULL, -1);
++		return archive_entry_is_encrypted (archive->libar_entry);
++	}
++
++	return FALSE;
++}
++
++gssize
++ev_archive_read_data (EvArchive *archive,
++		      void      *buf,
++		      gsize      count,
++		      GError   **error)
++{
++	gssize r = -1;
++
++	g_return_val_if_fail (EV_IS_ARCHIVE (archive), -1);
++	g_return_val_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE, -1);
++
++	switch (archive->type) {
++	case EV_ARCHIVE_TYPE_NONE:
++		g_assert_not_reached ();
++	case EV_ARCHIVE_TYPE_RAR:
++	case EV_ARCHIVE_TYPE_ZIP:
++	case EV_ARCHIVE_TYPE_7Z:
++	case EV_ARCHIVE_TYPE_TAR:
++		g_return_val_if_fail (archive->libar_entry != NULL, -1);
++		r = archive_read_data (archive->libar, buf, count);
++		if (r < 0) {
++			g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
++				     "Failed to decompress data: %s", archive_error_string (archive->libar));
++		}
++		break;
++	}
++
++	return r;
++}
++
++void
++ev_archive_reset (EvArchive *archive)
++{
++	g_return_if_fail (EV_IS_ARCHIVE (archive));
++	g_return_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE);
++
++	switch (archive->type) {
++	case EV_ARCHIVE_TYPE_RAR:
++	case EV_ARCHIVE_TYPE_ZIP:
++	case EV_ARCHIVE_TYPE_7Z:
++	case EV_ARCHIVE_TYPE_TAR:
++		g_clear_pointer (&archive->libar, archive_free);
++		libarchive_set_archive_type (archive, archive->type);
++		archive->libar_entry = NULL;
++		break;
++	default:
++		g_assert_not_reached ();
++	}
++}
++
++static void
++ev_archive_init (EvArchive *archive)
++{
++}
+diff --git a/backend/comics/ev-archive.h b/backend/comics/ev-archive.h
+new file mode 100644
+index 00000000..b4e1399c
+--- /dev/null
++++ b/backend/comics/ev-archive.h
+@@ -0,0 +1,56 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
++/*
++ * Copyright (C) 2017, Bastien Nocera <hadess@hadess.net>
++ *
++ * 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, 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 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.
++ */
++
++#pragma once
++
++#include <glib-object.h>
++
++G_BEGIN_DECLS
++
++#define EV_TYPE_ARCHIVE ev_archive_get_type ()
++G_DECLARE_FINAL_TYPE (EvArchive, ev_archive, EV, ARCHIVE, GObject)
++
++typedef enum {
++	EV_ARCHIVE_TYPE_NONE = 0,
++	EV_ARCHIVE_TYPE_RAR,
++	EV_ARCHIVE_TYPE_ZIP,
++	EV_ARCHIVE_TYPE_7Z,
++	EV_ARCHIVE_TYPE_TAR
++} EvArchiveType;
++
++EvArchive     *ev_archive_new                (void);
++gboolean       ev_archive_set_archive_type   (EvArchive     *archive,
++					      EvArchiveType  archive_type);
++EvArchiveType  ev_archive_get_archive_type   (EvArchive     *archive);
++gboolean       ev_archive_open_filename      (EvArchive     *archive,
++					      const char    *path,
++					      GError       **error);
++gboolean       ev_archive_read_next_header   (EvArchive     *archive,
++					      GError       **error);
++gboolean       ev_archive_at_entry           (EvArchive     *archive);
++const char    *ev_archive_get_entry_pathname (EvArchive     *archive);
++gint64         ev_archive_get_entry_size     (EvArchive     *archive);
++gboolean       ev_archive_get_entry_is_encrypted (EvArchive *archive);
++gssize         ev_archive_read_data          (EvArchive     *archive,
++					      void          *buf,
++					      gsize          count,
++					      GError       **error);
++void           ev_archive_reset              (EvArchive     *archive);
++
++G_END_DECLS
+diff --git a/configure.ac b/configure.ac
+index e25de054..d5830716 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -580,8 +580,11 @@ AC_ARG_ENABLE(comics,
+     [enable_comics=$enableval],
+     [enable_comics=yes])
+ 
++COMICS_DEPS="libarchive"
+ if test "x$enable_comics" = "xyes"; then
+     AC_DEFINE([ENABLE_COMICS], [1], [Enable support for comics.])
++    PKG_CHECK_MODULES([COMICS], [$COMICS_DEPS])
++    AC_SUBST(COMICS_LIBS)
+ fi
+ AM_CONDITIONAL(ENABLE_COMICS, test x$enable_comics = xyes)
+ 
+diff --git a/libdocument/ev-document.h b/libdocument/ev-document.h
+index 67f53abb..8f54e6b5 100644
+--- a/libdocument/ev-document.h
++++ b/libdocument/ev-document.h
+@@ -59,6 +59,7 @@ typedef struct _EvDocumentPrivate EvDocumentPrivate;
+ typedef enum
+ {
+         EV_DOCUMENT_ERROR_INVALID,
++        EV_DOCUMENT_ERROR_UNSUPPORTED_CONTENT,
+         EV_DOCUMENT_ERROR_ENCRYPTED
+ } EvDocumentError;
+ 
+-- 
+2.39.2
+
diff -Nru atril-1.26.0/debian/patches/1002-avoid-crash-on-certain-epub-files.patch atril-1.26.0/debian/patches/1002-avoid-crash-on-certain-epub-files.patch
--- atril-1.26.0/debian/patches/1002-avoid-crash-on-certain-epub-files.patch	1970-01-01 01:00:00.000000000 +0100
+++ atril-1.26.0/debian/patches/1002-avoid-crash-on-certain-epub-files.patch	2024-01-23 10:05:56.000000000 +0100
@@ -0,0 +1,27 @@
+Description: Avoid crash on certain epub files
+
+Author: Bernhard Übelacker <bernhardu@mailbox.org>
+Bug-Debian: https://bugs.debian.org/972715
+Forwarded: no
+Last-Update: 2020-11-01
+
+--- a/backend/epub/epub-document.c
++++ b/backend/epub/epub-document.c
+@@ -1279,7 +1279,7 @@
+             xml_parse_children_of_node(navLabel,(xmlChar*)"text",NULL,NULL);
+             linknode *newnode = g_new0(linknode,1);
+             newnode->linktext = NULL;
+-            while (newnode->linktext == NULL) {
++            while (xmlretval && newnode->linktext == NULL) {
+                 newnode->linktext = (gchar*)xml_get_data_from_node(xmlretval,XML_KEYWORD,NULL);
+                 xmlretval = xmlretval->next;
+             }
+@@ -1597,7 +1597,7 @@
+     contentListNode *pagedata;
+ 
+     guint flag=0;
+-    while (!flag) {
++    while (listiter && !flag) {
+         pagedata = listiter->data;
+         if (link_present_on_page(Link->pagelink, pagedata->value)) {
+             flag=1;
diff -Nru atril-1.26.0/debian/patches/series atril-1.26.0/debian/patches/series
--- atril-1.26.0/debian/patches/series	2022-10-27 10:40:29.000000000 +0200
+++ atril-1.26.0/debian/patches/series	2024-01-23 10:06:53.000000000 +0100
@@ -1 +1,7 @@
 1001-webkit2gtk4.1.patch
+1002-avoid-crash-on-certain-epub-files.patch
+0001-Accessibility-add-button-description.patch
+0003-epub-Fix-index-loading-for-certain-documents-look-fo.patch
+0004-epub-add-fallback-for-malformed-epub-files-in-check_.patch
+0005-Use-a-blank-line-at-most.patch
+0006-comics-Use-libarchive-to-unpack-documents.patch
diff -Nru atril-1.26.0/debian/changelog atril-1.26.0/debian/changelog
--- atril-1.26.0/debian/changelog	2024-01-06 07:18:28.000000000 +0100
+++ atril-1.26.0/debian/changelog	2024-01-23 10:08:40.000000000 +0100
@@ -1,3 +1,12 @@
+atril (1.26.0-2+deb12u2) bookworm; urgency=medium
+
+  * debian/patches:
+    + Add 0005-Use-a-blank-line-at-most.patch and 0006-comics-Use-libarchive-
+      to-unpack-documents.patch. Use libarchive instead of external command for
+      extracing documents (CVE-2023-51698, closes: #1060751).
+
+ -- Mike Gabriel <sunweaver@debian.org>  Tue, 23 Jan 2024 10:08:40 +0100
+
 atril (1.26.0-2+deb12u1) bookworm; urgency=medium
 
   * debian/patches:
diff -Nru atril-1.26.0/debian/patches/0005-Use-a-blank-line-at-most.patch atril-1.26.0/debian/patches/0005-Use-a-blank-line-at-most.patch
--- atril-1.26.0/debian/patches/0005-Use-a-blank-line-at-most.patch	1970-01-01 01:00:00.000000000 +0100
+++ atril-1.26.0/debian/patches/0005-Use-a-blank-line-at-most.patch	2024-01-23 10:08:40.000000000 +0100
@@ -0,0 +1,1866 @@
+From 658fab1f008bff7e1ec147d95baa04bc44c2fbcd Mon Sep 17 00:00:00 2001
+From: rbuj <robert.buj@gmail.com>
+Date: Wed, 27 Oct 2021 17:30:36 +0200
+Subject: [PATCH 1/2] Use a blank line at most
+
+Signed-off-by: Mike Gabriel <mike.gabriel@das-netzwerkteam.de>
+---
+ backend/comics/comics-document.c              |  3 --
+ backend/djvu/djvu-document.c                  |  3 --
+ backend/djvu/djvu-links.c                     |  2 -
+ backend/djvu/djvu-text-page.c                 |  3 --
+ backend/djvu/djvu-text-page.h                 |  1 -
+ backend/dvi/dvi-document.c                    |  2 -
+ backend/dvi/fonts.c                           |  1 -
+ backend/dvi/mdvi-lib/afmparse.c               | 18 --------
+ backend/dvi/mdvi-lib/bitmap.c                 |  2 -
+ backend/dvi/mdvi-lib/color.c                  |  1 -
+ backend/dvi/mdvi-lib/color.h                  |  1 -
+ backend/dvi/mdvi-lib/fontmap.c                |  1 -
+ backend/dvi/mdvi-lib/hash.c                   |  1 -
+ backend/dvi/mdvi-lib/hash.h                   |  2 -
+ backend/dvi/mdvi-lib/mdvi.h                   |  2 -
+ backend/dvi/mdvi-lib/paper.h                  |  1 -
+ backend/dvi/mdvi-lib/special.c                |  1 -
+ backend/dvi/mdvi-lib/tfmfile.c                |  1 -
+ backend/epub/epub-document.c                  |  6 ---
+ backend/epub/minizip/ioapi.c                  |  6 ---
+ backend/epub/minizip/ioapi.h                  |  7 ---
+ backend/epub/minizip/unzip.c                  | 45 -------------------
+ backend/epub/minizip/unzip.h                  | 11 -----
+ backend/pdf/ev-poppler.h                      |  1 -
+ backend/pixbuf/pixbuf-document.c              |  1 -
+ backend/tiff/tiff-document.c                  |  1 -
+ backend/tiff/tiff2ps.c                        |  2 -
+ backend/xps/xps-document.c                    |  2 -
+ .../toolbar-editor/egg-editable-toolbar.c     |  2 -
+ .../toolbar-editor/egg-toolbar-editor.c       |  1 -
+ .../toolbar-editor/egg-toolbar-editor.h       |  2 -
+ .../toolbar-editor/egg-toolbars-model.c       |  2 -
+ cut-n-paste/zoom-control/ephy-zoom.c          |  1 -
+ libdocument/ev-document-attachments.c         |  1 -
+ libdocument/ev-document-factory.c             |  1 -
+ libdocument/ev-document-fonts.h               |  1 -
+ libdocument/ev-document-misc.c                |  1 -
+ libdocument/ev-document-security.h            |  1 -
+ libdocument/ev-document-text.c                |  1 -
+ libdocument/ev-document.c                     |  1 -
+ libdocument/ev-file-helpers.h                 |  1 -
+ libdocument/ev-form-field.h                   |  1 -
+ libdocument/ev-image.h                        |  1 -
+ libdocument/ev-render-context.h               |  2 -
+ libdocument/ev-transition-effect.h            |  2 -
+ libmisc/ev-page-action-widget.c               |  3 --
+ libview/ev-page-accessible.c                  |  2 -
+ libview/ev-pixbuf-cache.c                     |  6 ---
+ libview/ev-pixbuf-cache.h                     |  2 -
+ libview/ev-timeline.c                         |  2 -
+ libview/ev-timeline.h                         |  2 -
+ libview/ev-transition-animation.c             |  2 -
+ libview/ev-transition-animation.h             |  2 -
+ libview/ev-view-presentation.c                |  1 -
+ libview/ev-view.c                             |  2 -
+ libview/ev-web-view.c                         |  2 -
+ libview/ev-web-view.h                         |  1 -
+ previewer/ev-previewer-window.c               |  1 -
+ shell/eggfindbar.c                            |  1 -
+ shell/eggfindbar.h                            |  1 -
+ shell/ev-application.c                        |  2 -
+ shell/ev-bookmarks.h                          |  2 -
+ shell/ev-daemon.c                             |  1 -
+ shell/ev-history.c                            |  1 -
+ shell/ev-loading-message.c                    |  1 -
+ shell/ev-media-player-keys.h                  |  1 -
+ shell/ev-navigation-action.c                  |  1 -
+ shell/ev-open-recent-action.c                 |  1 -
+ shell/ev-password-view.c                      |  2 -
+ shell/ev-sidebar-attachments.c                |  1 -
+ shell/ev-sidebar-bookmarks.c                  |  1 -
+ shell/ev-sidebar-layers.c                     |  1 -
+ shell/ev-sidebar-links.c                      |  3 --
+ shell/ev-sidebar-links.h                      |  1 -
+ shell/ev-sidebar-page.c                       |  1 -
+ shell/ev-sidebar-page.h                       |  1 -
+ shell/ev-sidebar-thumbnails.c                 |  1 -
+ shell/ev-sidebar-thumbnails.h                 |  1 -
+ shell/ev-sidebar.c                            |  1 -
+ shell/ev-sidebar.h                            |  1 -
+ shell/ev-window.c                             |  9 ----
+ shell/ev-window.h                             |  2 -
+ shell/main.c                                  |  4 --
+ 83 files changed, 220 deletions(-)
+
+--- a/backend/comics/comics-document.c
++++ b/backend/comics/comics-document.c
+@@ -126,7 +126,6 @@
+ static char**     extract_argv                   (EvDocument *document,
+ 						  gint page);
+ 
+-
+ EV_BACKEND_REGISTER_WITH_CODE (ComicsDocument, comics_document,
+ 	{
+ 		EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_THUMBNAILS,
+@@ -186,7 +185,6 @@
+ 	return g_string_free (dest, FALSE);
+ }
+ 
+-
+ /* This function manages the command for decompressing a comic book */
+ static gboolean
+ comics_decompress_temp_dir (const gchar *command_decompress_tmp,
+@@ -627,7 +625,6 @@
+ 	return TRUE;
+ }
+ 
+-
+ static gboolean
+ comics_document_save (EvDocument *document,
+ 		      const char *uri,
+--- a/backend/djvu/djvu-document.c
++++ b/backend/djvu/djvu-document.c
+@@ -66,7 +66,6 @@
+       EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_SELECTION, djvu_selection_iface_init);
+      });
+ 
+-
+ #define EV_DJVU_ERROR ev_djvu_error_quark ()
+ 
+ static GQuark
+@@ -256,7 +255,6 @@
+ 	return TRUE;
+ }
+ 
+-
+ static gboolean
+ djvu_document_save (EvDocument  *document,
+ 		    const char  *uri,
+@@ -676,7 +674,6 @@
+ 		r->y2 = height - tmp * SCALE_FACTOR;
+ 	}
+ 
+-
+ 	return matches;
+ }
+ 
+--- a/backend/djvu/djvu-links.c
++++ b/backend/djvu/djvu-links.c
+@@ -181,7 +181,6 @@
+ 		if (!string_from_miniexp (miniexp_car (iter), &title)) goto unknown_entry;
+ 		if (!string_from_miniexp (miniexp_cadr (iter), &link_dest)) goto unknown_entry;
+ 
+-
+ 		if (!g_utf8_validate (title, -1, NULL)) {
+ 			utf8_title = str_to_utf8 (title);
+ 			title_markup = g_markup_escape_text (utf8_title, -1);
+@@ -342,7 +341,6 @@
+ 	return NULL;
+ }
+ 
+-
+ gboolean
+ djvu_links_has_document_links (EvDocumentLinks *document_links)
+ {
+--- a/backend/djvu/djvu-text-page.c
++++ b/backend/djvu/djvu-text-page.c
+@@ -23,7 +23,6 @@
+ #include <libdjvu/miniexp.h>
+ #include "djvu-text-page.h"
+ 
+-
+ /**
+  * djvu_text_page_selection_process:
+  * @page: #DjvuTextPage instance
+@@ -117,7 +116,6 @@
+ 	}
+ }
+ 
+-
+ static void
+ djvu_text_page_limits (DjvuTextPage *page,
+ 			  miniexp_t     p,
+@@ -404,7 +402,6 @@
+ 	g_free (search_text);
+ }
+ 
+-
+ /**
+  * djvu_text_page_prepare_search:
+  * @page: #DjvuTextPage instance
+--- a/backend/djvu/djvu-text-page.h
++++ b/backend/djvu/djvu-text-page.h
+@@ -25,7 +25,6 @@
+ #include <glib.h>
+ #include <libdjvu/miniexp.h>
+ 
+-
+ typedef struct _DjvuTextPage DjvuTextPage;
+ typedef struct _DjvuTextLink DjvuTextLink;
+ 
+--- a/backend/dvi/dvi-document.c
++++ b/backend/dvi/dvi-document.c
+@@ -110,7 +110,6 @@
+ 
+ 	mdvi_cairo_device_init (&dvi_document->context->device);
+ 
+-
+ 	dvi_document->base_width = dvi_document->context->dvi_page_w * dvi_document->context->params.conv
+ 		+ 2 * unit2pix(dvi_document->params->dpi, MDVI_HMARGIN) / dvi_document->params->hshrink;
+ 
+@@ -123,7 +122,6 @@
+ 	return TRUE;
+ }
+ 
+-
+ static gboolean
+ dvi_document_save (EvDocument  *document,
+ 		      const char  *uri,
+--- a/backend/dvi/fonts.c
++++ b/backend/dvi/fonts.c
+@@ -54,4 +54,3 @@
+ 	return;
+ }
+ 
+-
+--- a/backend/dvi/mdvi-lib/afmparse.c
++++ b/backend/dvi/mdvi-lib/afmparse.c
+@@ -81,13 +81,10 @@
+ 
+ #define MATCH(A,B)		(strncmp((A),(B), MAX_NAME) == 0)
+ 
+-
+-
+ /*************************** GLOBALS ***********************/
+ 
+ static char *ident = NULL; /* storage buffer for keywords */
+ 
+-
+ /* "shorts" for fast case statement
+  * The values of each of these enumerated items correspond to an entry in the
+  * table of strings defined below. Therefore, if you add a new string as
+@@ -175,7 +172,6 @@
+ 
+ } /* token */
+ 
+-
+ /*************************** linetoken *************************/
+ 
+ /*  "linetoken" will get read all tokens until the EOL character from
+@@ -203,7 +199,6 @@
+ 
+ } /* linetoken */
+ 
+-
+ /*************************** recognize *************************/
+ 
+ /*  This function tries to match a string to a known list of
+@@ -234,7 +229,6 @@
+ 
+ } /* recognize */
+ 
+-
+ /************************* parseGlobals *****************************/
+ 
+ /*  This function is called by "parseFile". It will parse the AFM File
+@@ -401,8 +395,6 @@
+ 
+ } /* parseGlobals */
+ 
+-
+-
+ #if 0 /* this function does not seem to be used anywhere */
+ /************************* initializeArray ************************/
+ 
+@@ -584,7 +576,6 @@
+ 
+ } /* parseCharWidths */
+ 
+-
+ /************************* parseCharMetrics ************************/
+ 
+ /*  This function is called by parseFile if the caller of parseFile
+@@ -694,8 +685,6 @@
+ 
+ } /* parseCharMetrics */
+ 
+-
+-
+ /************************* parseTrackKernData ***********************/
+ 
+ /*  This function is called by "parseFile". It will parse the AFM File
+@@ -797,7 +786,6 @@
+ 
+ } /* parseTrackKernData */
+ 
+-
+ /************************* parsePairKernData ************************/
+ 
+ /*  This function is called by "parseFile". It will parse the AFM File
+@@ -918,7 +906,6 @@
+ 
+ } /* parsePairKernData */
+ 
+-
+ /************************* parseCompCharData **************************/
+ 
+ /*  This function is called by "parseFile". It will parse the AFM File
+@@ -1043,12 +1030,8 @@
+ 
+ } /* parseCompCharData */
+ 
+-
+-
+-
+ /*************************** 'PUBLIC' FUNCTION ********************/
+ 
+-
+ /*************************** parseFile *****************************/
+ 
+ /*  parseFile is the only 'public' procedure available. It is called
+@@ -1078,7 +1061,6 @@
+ 
+     register char *keyword; /* used to store a token */
+ 
+-
+     /* storage data for the global variable ident */
+     ident = (char *) calloc(MAX_NAME, sizeof(char));
+     if (ident == NULL) {error = storageProblem; return(error);}
+--- a/backend/dvi/mdvi-lib/bitmap.c
++++ b/backend/dvi/mdvi-lib/bitmap.c
+@@ -117,7 +117,6 @@
+ 	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
+ };
+ 
+-
+ /*
+  * next we have three bitmap functions to convert bitmaps in LSB bit order
+  * with 8, 16 and 32 bits per unit, to our internal format. The differences
+@@ -192,7 +191,6 @@
+ 	return bm;
+ }
+ 
+-
+ BITMAP	*bitmap_copy(BITMAP *bm)
+ {
+ 	BITMAP	*nb = bitmap_alloc(bm->width, bm->height);
+--- a/backend/dvi/mdvi-lib/color.c
++++ b/backend/dvi/mdvi-lib/color.c
+@@ -79,7 +79,6 @@
+ 
+ #define GAMMA_DIFF	0.005
+ 
+-
+ /* create a color table */
+ Ulong	*get_color_table(DviDevice *dev,
+ 			 int nlevels, Ulong fg, Ulong bg, double gamma, int density)
+--- a/backend/dvi/mdvi-lib/color.h
++++ b/backend/dvi/mdvi-lib/color.h
+@@ -16,7 +16,6 @@
+  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+  */
+ 
+-
+ #ifndef _COLOR_H_
+ #define _COLOR_H_
+ 
+--- a/backend/dvi/mdvi-lib/fontmap.c
++++ b/backend/dvi/mdvi-lib/fontmap.c
+@@ -834,7 +834,6 @@
+ 	return 0;
+ }
+ 
+-
+ void	mdvi_flush_encodings(void)
+ {
+ 	DviEncoding *enc;
+--- a/backend/dvi/mdvi-lib/hash.c
++++ b/backend/dvi/mdvi-lib/hash.c
+@@ -21,7 +21,6 @@
+ 
+ /* simple hash tables for MDVI */
+ 
+-
+ struct _DviHashBucket {
+ 	DviHashBucket *next;
+ 	DviHashKey	key;
+--- a/backend/dvi/mdvi-lib/hash.h
++++ b/backend/dvi/mdvi-lib/hash.h
+@@ -3,7 +3,6 @@
+ 
+ /* Hash tables */
+ 
+-
+ typedef struct _DviHashBucket DviHashBucket;
+ typedef struct _DviHashTable DviHashTable;
+ 
+@@ -18,7 +17,6 @@
+ typedef int	(*DviHashComp) __PROTO((DviHashKey key1, DviHashKey key2));
+ typedef void	(*DviHashFree) __PROTO((DviHashKey key, void *data));
+ 
+-
+ struct _DviHashTable {
+ 	DviHashBucket	**buckets;
+ 	int	nbucks;
+--- a/backend/dvi/mdvi-lib/mdvi.h
++++ b/backend/dvi/mdvi-lib/mdvi.h
+@@ -414,7 +414,6 @@
+ 	int	step;		/* step */
+ };
+ 
+-
+ typedef void (*DviSpecialHandler)
+ 	__PROTO((DviContext *dvi, const char *prefix, const char *arg));
+ 
+@@ -600,7 +599,6 @@
+ 
+ extern int mdvi_encode_font __PROTO((DviParams *, DviFont *));
+ 
+-
+ /* font lookup functions */
+ extern int mdvi_register_font_type __PROTO((DviFontInfo *, int));
+ extern char **mdvi_list_font_class __PROTO((int));
+--- a/backend/dvi/mdvi-lib/paper.h
++++ b/backend/dvi/mdvi-lib/paper.h
+@@ -24,7 +24,6 @@
+ 	const char *height;
+ };
+ 
+-
+ extern int 	mdvi_get_paper_size __PROTO((const char *, DviPaper *));
+ extern DviPaperSpec* mdvi_get_paper_specs __PROTO((DviPaperClass));
+ extern void	mdvi_free_paper_specs __PROTO((DviPaperSpec *));
+--- a/backend/dvi/mdvi-lib/special.c
++++ b/backend/dvi/mdvi-lib/special.c
+@@ -212,7 +212,6 @@
+ {
+ 	DviSpecial *sp, *list;
+ 
+-
+ 	for(list = (DviSpecial *)specials.head; (sp = list); ) {
+ 		list = sp->next;
+ 		if(sp->prefix) mdvi_free(sp->prefix);
+--- a/backend/dvi/mdvi-lib/tfmfile.c
++++ b/backend/dvi/mdvi-lib/tfmfile.c
+@@ -258,7 +258,6 @@
+ 	/* allocate characters */
+ 	info->chars = xnalloc(TFMChar, size);
+ 
+-
+ #ifdef WORD_LITTLE_ENDIAN
+ 	/* byte-swap the three arrays at once (they are consecutive in memory) */
+ 	swap_array((Uint32 *)widths, nw + nh + nd);
+--- a/backend/epub/epub-document.c
++++ b/backend/epub/epub-document.c
+@@ -224,7 +224,6 @@
+     return TRUE;
+ }
+ 
+-
+ typedef struct _LinksCBStruct {
+     GtkTreeModel *model;
+     GtkTreeIter  *parent;
+@@ -413,7 +412,6 @@
+     return (g_remove (path_name));
+ }
+ 
+-
+ static gboolean
+ check_mime_type             (const gchar* uri,
+                              GError** error);
+@@ -1562,7 +1560,6 @@
+ 
+         gchar *csspath = g_strdup_printf("%s/atrilnightstyle.css",epub_document->documentdir);
+ 
+-
+         GFile *styles = g_file_new_for_path (csspath);
+         GOutputStream *outstream = (GOutputStream*)g_file_create(styles,G_FILE_CREATE_PRIVATE,NULL,NULL);
+         if ( g_output_stream_write((GOutputStream*)outstream,style,strlen(style),NULL,NULL) == -1 )
+@@ -1636,7 +1633,6 @@
+     g_list_foreach(index,(GFunc)page_set_function,contentList);
+ }
+ 
+-
+ static void
+ add_mathjax_script_node_to_file(gchar *filename, gchar *data)
+ {
+@@ -1784,7 +1780,6 @@
+     epub_document->docTitle = NULL;
+ }
+ 
+-
+ static void
+ epub_document_finalize (GObject *object)
+ {
+@@ -1826,7 +1821,6 @@
+     G_OBJECT_CLASS (epub_document_parent_class)->finalize (object);
+ }
+ 
+-
+ static void
+ epub_document_class_init (EpubDocumentClass *klass)
+ {
+--- a/backend/epub/minizip/ioapi.c
++++ b/backend/epub/minizip/ioapi.c
+@@ -25,7 +25,6 @@
+ #define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin)
+ #endif
+ 
+-
+ #include "ioapi.h"
+ 
+ voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)
+@@ -82,8 +81,6 @@
+     p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file;
+ }
+ 
+-
+-
+ static voidpf  ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode));
+ static uLong   ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size));
+ static uLong   ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size));
+@@ -128,7 +125,6 @@
+     return file;
+ }
+ 
+-
+ static uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size)
+ {
+     uLong ret;
+@@ -150,7 +146,6 @@
+     return ret;
+ }
+ 
+-
+ static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream)
+ {
+     ZPOS64_T ret;
+@@ -206,7 +201,6 @@
+     return ret;
+ }
+ 
+-
+ static int ZCALLBACK fclose_file_func (voidpf opaque, voidpf stream)
+ {
+     int ret;
+--- a/backend/epub/minizip/ioapi.h
++++ b/backend/epub/minizip/ioapi.h
+@@ -110,7 +110,6 @@
+ extern "C" {
+ #endif
+ 
+-
+ #define ZLIB_FILEFUNC_SEEK_CUR (1)
+ #define ZLIB_FILEFUNC_SEEK_END (2)
+ #define ZLIB_FILEFUNC_SEEK_SET (0)
+@@ -122,7 +121,6 @@
+ #define ZLIB_FILEFUNC_MODE_EXISTING (4)
+ #define ZLIB_FILEFUNC_MODE_CREATE   (8)
+ 
+-
+ #ifndef ZCALLBACK
+  #if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK)
+    #define ZCALLBACK CALLBACK
+@@ -131,9 +129,6 @@
+  #endif
+ #endif
+ 
+-
+-
+-
+ typedef voidpf   (ZCALLBACK *open_file_func)      OF((voidpf opaque, const char* filename, int mode));
+ typedef uLong    (ZCALLBACK *read_file_func)      OF((voidpf opaque, voidpf stream, void* buf, uLong size));
+ typedef uLong    (ZCALLBACK *write_file_func)     OF((voidpf opaque, voidpf stream, const void* buf, uLong size));
+@@ -143,7 +138,6 @@
+ typedef long     (ZCALLBACK *tell_file_func)      OF((voidpf opaque, voidpf stream));
+ typedef long     (ZCALLBACK *seek_file_func)      OF((voidpf opaque, voidpf stream, uLong offset, int origin));
+ 
+-
+ /* here is the "old" 32 bits structure structure */
+ typedef struct zlib_filefunc_def_s
+ {
+@@ -185,7 +179,6 @@
+     seek_file_func      zseek32_file;
+ } zlib_filefunc64_32_def;
+ 
+-
+ #define ZREAD64(filefunc,filestream,buf,size)     ((*((filefunc).zfile_func64.zread_file))   ((filefunc).zfile_func64.opaque,filestream,buf,size))
+ #define ZWRITE64(filefunc,filestream,buf,size)    ((*((filefunc).zfile_func64.zwrite_file))  ((filefunc).zfile_func64.opaque,filestream,buf,size))
+ //#define ZTELL64(filefunc,filestream)            ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream))
+--- a/backend/epub/minizip/unzip.c
++++ b/backend/epub/minizip/unzip.c
+@@ -12,7 +12,6 @@
+ 
+          For more info read MiniZip_info.txt
+ 
+-
+   ------------------------------------------------------------------------------------
+   Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of
+   compatibility with older software. The following is from the original crypt.c.
+@@ -48,7 +47,6 @@
+ 
+         Copyright (C) 2007-2008 Even Rouault
+ 
+-
+         Oct-2009 - Mathias Svensson - Removed cpl_* from symbol names (Even Rouault added them but since this is now moved to a new project (minizip64) I renamed them again).
+   Oct-2009 - Mathias Svensson - Fixed problem if uncompressed size was > 4G and compressed size was <4G
+                                 should only read the compressed/uncompressed size from the Zip64 format if
+@@ -63,7 +61,6 @@
+ 
+ */
+ 
+-
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+@@ -86,20 +83,17 @@
+ #   include <errno.h>
+ #endif
+ 
+-
+ #ifndef local
+ #  define local static
+ #endif
+ /* compile with -Dlocal if your debugger can't find static symbols */
+ 
+-
+ #ifndef CASESENSITIVITYDEFAULT_NO
+ #  if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES)
+ #    define CASESENSITIVITYDEFAULT_NO
+ #  endif
+ #endif
+ 
+-
+ #ifndef UNZ_BUFSIZE
+ #define UNZ_BUFSIZE (16384)
+ #endif
+@@ -118,14 +112,12 @@
+ #define SIZECENTRALDIRITEM (0x2e)
+ #define SIZEZIPLOCALHEADER (0x1e)
+ 
+-
+ /* unz_file_info_interntal contain internal info about a file in zipfile*/
+ typedef struct unz_file_info64_internal_s
+ {
+     ZPOS64_T offset_curfile;/* relative offset of local header 8 bytes */
+ } unz_file_info64_internal;
+ 
+-
+ /* file_in_zip_read_info_s contain internal information about a file in zipfile,
+     when reading and decompress it */
+ typedef struct
+@@ -156,7 +148,6 @@
+     int   raw;
+ } file_in_zip64_read_info_s;
+ 
+-
+ /* unz64_s contain internal information about the zipfile
+ */
+ typedef struct
+@@ -189,7 +180,6 @@
+ #    endif
+ } unz64_s;
+ 
+-
+ #ifndef NOUNCRYPT
+ #include "crypt.h"
+ #endif
+@@ -200,7 +190,6 @@
+    IN assertion: the stream s has been successfully opened for reading.
+ */
+ 
+-
+ local int unz64local_getByte OF((
+     const zlib_filefunc64_32_def* pzlib_filefunc_def,
+     voidpf filestream,
+@@ -224,7 +213,6 @@
+     }
+ }
+ 
+-
+ /* ===========================================================================
+    Reads a long in LSB order from the given gz_stream. Sets
+ */
+@@ -295,7 +283,6 @@
+     voidpf filestream,
+     ZPOS64_T *pX));
+ 
+-
+ local int unz64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def,
+                             voidpf filestream,
+                             ZPOS64_T *pX)
+@@ -364,7 +351,6 @@
+     }
+ }
+ 
+-
+ #ifdef  CASESENSITIVITYDEFAULT_NO
+ #define CASESENSITIVITYDEFAULTVALUE 2
+ #else
+@@ -418,7 +404,6 @@
+     if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
+         return 0;
+ 
+-
+     uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);
+ 
+     if (uMaxBack>uSizeFile)
+@@ -463,7 +448,6 @@
+     return uPosFound;
+ }
+ 
+-
+ /*
+   Locate the Central directory 64 of a zipfile (at the end, just before
+     the global comment)
+@@ -486,7 +470,6 @@
+     if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
+         return 0;
+ 
+-
+     uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);
+ 
+     if (uMaxBack>uSizeFile)
+@@ -605,8 +588,6 @@
+         us.z_filefunc = *pzlib_filefunc64_32_def;
+     us.is64bitOpenFunction = is64bitOpenFunction;
+ 
+-
+-
+     us.filestream = ZOPEN64(us.z_filefunc,
+                                                  path,
+                                                  ZLIB_FILEFUNC_MODE_READ |
+@@ -745,7 +726,6 @@
+     us.pfile_in_zip_read = NULL;
+     us.encrypted = 0;
+ 
+-
+     s=(unz64_s*)ALLOC(sizeof(unz64_s));
+     if( s != NULL)
+     {
+@@ -755,7 +735,6 @@
+     return (unzFile)s;
+ }
+ 
+-
+ extern unzFile ZEXPORT unzOpen2 (const char *path,
+                                         zlib_filefunc_def* pzlib_filefunc32_def)
+ {
+@@ -814,7 +793,6 @@
+     return UNZ_OK;
+ }
+ 
+-
+ /*
+   Write info about the ZipFile in the *pglobal_info structure.
+   No preparation of the structure is needed
+@@ -897,7 +875,6 @@
+               ZLIB_FILEFUNC_SEEK_SET)!=0)
+         err=UNZ_ERRNO;
+ 
+-
+     /* we check the magic */
+     if (err==UNZ_OK)
+     {
+@@ -1002,7 +979,6 @@
+     else
+         lSeek += file_info.size_file_extra;
+ 
+-
+     if ((err==UNZ_OK) && (file_info.size_file_extra != 0))
+     {
+                                 uLong acc = 0;
+@@ -1096,7 +1072,6 @@
+     else
+         lSeek+=file_info.size_file_comment;
+ 
+-
+     if ((err==UNZ_OK) && (pfile_info!=NULL))
+         *pfile_info=file_info;
+ 
+@@ -1106,8 +1081,6 @@
+     return err;
+ }
+ 
+-
+-
+ /*
+   Write info about the ZipFile in the *pglobal_info structure.
+   No preparation of the structure is needed
+@@ -1156,7 +1129,6 @@
+ 
+         pfile_info->tmu_date = file_info64.tmu_date,
+ 
+-
+         pfile_info->compressed_size = (uLong)file_info64.compressed_size;
+         pfile_info->uncompressed_size = (uLong)file_info64.uncompressed_size;
+ 
+@@ -1212,7 +1184,6 @@
+     return err;
+ }
+ 
+-
+ /*
+   Try locate the file szFileName in the zipfile.
+   For the iCaseSensitivity signification, see unzStringFileNameCompare
+@@ -1234,7 +1205,6 @@
+     ZPOS64_T num_fileSaved;
+     ZPOS64_T pos_in_central_dirSaved;
+ 
+-
+     if (file==NULL)
+         return UNZ_PARAMERROR;
+ 
+@@ -1278,7 +1248,6 @@
+     return err;
+ }
+ 
+-
+ /*
+ ///////////////////////////////////////////
+ // Contributed by Ryan Haksi (mailto://cryogen@infoserve.net)
+@@ -1391,7 +1360,6 @@
+                                 s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0)
+         return UNZ_ERRNO;
+ 
+-
+     if (err==UNZ_OK)
+     {
+         if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK)
+@@ -1594,7 +1562,6 @@
+     pfile_in_zip_read_info->rest_read_uncompressed =
+             s->cur_file_info.uncompressed_size ;
+ 
+-
+     pfile_in_zip_read_info->pos_in_zipfile =
+             s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER +
+               iSizeVar;
+@@ -1626,7 +1593,6 @@
+     }
+ #    endif
+ 
+-
+     return UNZ_OK;
+ }
+ 
+@@ -1687,7 +1653,6 @@
+     if (pfile_in_zip_read_info==NULL)
+         return UNZ_PARAMERROR;
+ 
+-
+     if (pfile_in_zip_read_info->read_buffer == NULL)
+         return UNZ_END_OF_LIST_OF_FILE;
+     if (len==0)
+@@ -1731,7 +1696,6 @@
+                       uReadThis)!=uReadThis)
+                 return UNZ_ERRNO;
+ 
+-
+ #            ifndef NOUNCRYPT
+             if(s->encrypted)
+             {
+@@ -1743,7 +1707,6 @@
+             }
+ #            endif
+ 
+-
+             pfile_in_zip_read_info->pos_in_zipfile += uReadThis;
+ 
+             pfile_in_zip_read_info->rest_read_compressed-=uReadThis;
+@@ -1874,7 +1837,6 @@
+     return err;
+ }
+ 
+-
+ /*
+   Give the current position in uncompressed data
+ */
+@@ -1909,7 +1871,6 @@
+     return pfile_in_zip_read_info->total_out_64;
+ }
+ 
+-
+ /*
+   return 1 if the end of file was reached, 0 elsewhere
+ */
+@@ -1931,8 +1892,6 @@
+         return 0;
+ }
+ 
+-
+-
+ /*
+ Read extra field from the current file (opened by unzOpenCurrentFile)
+ This is the local-header version of the extra field (sometimes, there is
+@@ -2007,7 +1966,6 @@
+     if (pfile_in_zip_read_info==NULL)
+         return UNZ_PARAMERROR;
+ 
+-
+     if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) &&
+         (!pfile_in_zip_read_info->raw))
+     {
+@@ -2015,7 +1973,6 @@
+             err=UNZ_CRCERROR;
+     }
+ 
+-
+     TRYFREE(pfile_in_zip_read_info->read_buffer);
+     pfile_in_zip_read_info->read_buffer = NULL;
+     if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED)
+@@ -2025,7 +1982,6 @@
+         BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream);
+ #endif
+ 
+-
+     pfile_in_zip_read_info->stream_initialised = 0;
+     TRYFREE(pfile_in_zip_read_info);
+ 
+@@ -2034,7 +1990,6 @@
+     return err;
+ }
+ 
+-
+ /*
+   Get the global comment string of the ZipFile, in the szComment buffer.
+   uSizeBuf is the size of the szComment buffer.
+--- a/backend/epub/minizip/unzip.h
++++ b/backend/epub/minizip/unzip.h
+@@ -70,7 +70,6 @@
+ typedef voidp unzFile;
+ #endif
+ 
+-
+ #define UNZ_OK                          (0)
+ #define UNZ_END_OF_LIST_OF_FILE         (-100)
+ #define UNZ_ERRNO                       (Z_ERRNO)
+@@ -162,7 +161,6 @@
+     (like 1 on Unix, 2 on Windows)
+ */
+ 
+-
+ extern unzFile ZEXPORT unzOpen OF((const char *path));
+ extern unzFile ZEXPORT unzOpen64 OF((const void *path));
+ /*
+@@ -180,7 +178,6 @@
+        does not describe the reality
+ */
+ 
+-
+ extern unzFile ZEXPORT unzOpen2 OF((const char *path,
+                                     zlib_filefunc_def* pzlib_filefunc_def));
+ /*
+@@ -212,7 +209,6 @@
+   No preparation of the structure is needed
+   return UNZ_OK if there is no problem. */
+ 
+-
+ extern int ZEXPORT unzGetGlobalComment OF((unzFile file,
+                                            char *szComment,
+                                            uLong uSizeBuf));
+@@ -222,7 +218,6 @@
+   return the number of byte copied or an error code <0
+ */
+ 
+-
+ /***************************************************************************/
+ /* Unzip package allow you browse the directory of the zipfile */
+ 
+@@ -251,7 +246,6 @@
+   UNZ_END_OF_LIST_OF_FILE if the file is not found
+ */
+ 
+-
+ /* ****************************************** */
+ /* Ryan supplied functions */
+ /* unz_file_info contain information about a file in the zipfile */
+@@ -315,14 +309,12 @@
+             (commentBufferSize is the size of the buffer)
+ */
+ 
+-
+ /** Addition for GDAL : START */
+ 
+ extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file));
+ 
+ /** Addition for GDAL : END */
+ 
+-
+ /***************************************************************************/
+ /* for reading the content of the current zipfile, you can open it, read data
+    from it, and close it (you can close it before reading all the file)
+@@ -369,7 +361,6 @@
+          but you CANNOT set method parameter as NULL
+ */
+ 
+-
+ extern int ZEXPORT unzCloseCurrentFile OF((unzFile file));
+ /*
+   Close the file in zip opened with unzOpenCurrentFile
+@@ -428,8 +419,6 @@
+ extern int ZEXPORT unzSetOffset64 (unzFile file, ZPOS64_T pos);
+ extern int ZEXPORT unzSetOffset (unzFile file, uLong pos);
+ 
+-
+-
+ #ifdef __cplusplus
+ }
+ #endif
+--- a/backend/pdf/ev-poppler.h
++++ b/backend/pdf/ev-poppler.h
+@@ -34,7 +34,6 @@
+ 
+ G_MODULE_EXPORT GType register_atril_backend (GTypeModule *module);
+ 
+-
+ G_END_DECLS
+ 
+ #endif /* __PDF_DOCUMENT_H__ */
+--- a/backend/pixbuf/pixbuf-document.c
++++ b/backend/pixbuf/pixbuf-document.c
+@@ -201,7 +201,6 @@
+ 	iface->get_dimensions = pixbuf_document_thumbnails_get_dimensions;
+ }
+ 
+-
+ static void
+ pixbuf_document_init (PixbufDocument *pixbuf_document)
+ {
+--- a/backend/tiff/tiff-document.c
++++ b/backend/tiff/tiff-document.c
+@@ -361,7 +361,6 @@
+ 	if (width <= 0 || height <= 0)
+ 		return NULL;
+ 
+-
+ 	if (width >= INT_MAX / 4)
+ 		/* overflow */
+ 		return NULL;
+--- a/backend/tiff/tiff2ps.c
++++ b/backend/tiff/tiff2ps.c
+@@ -449,7 +449,6 @@
+ 	return splitpage;
+ }
+ 
+-
+ void
+ tiff2ps_process_page(TIFF2PSContext* ctx, TIFF* tif, double pw, double ph,
+ 		     double lm, double bm, gboolean cnt)
+@@ -592,7 +591,6 @@
+ 	}
+ }
+ 
+-
+ static char DuplexPreamble[] = "\
+ %%BeginFeature: *Duplex True\n\
+ systemdict begin\n\
+--- a/backend/xps/xps-document.c
++++ b/backend/xps/xps-document.c
+@@ -176,7 +176,6 @@
+ 		EV_DOCUMENT_INFO_N_PAGES |
+ 		EV_DOCUMENT_INFO_PAPER_SIZE;
+ 
+-
+ 	if (gxps_document_get_n_pages (xps->doc) > 0) {
+ 		ev_document_get_page_size (document, 0,
+ 					   &(info->paper_width),
+@@ -483,7 +482,6 @@
+ 	iface->find_link_page = xps_document_links_find_link_page;
+ }
+ 
+-
+ /* EvDocumentPrint */
+ static void
+ xps_document_print_print_page (EvDocumentPrint *document,
+--- a/cut-n-paste/toolbar-editor/egg-editable-toolbar.c
++++ b/cut-n-paste/toolbar-editor/egg-editable-toolbar.c
+@@ -541,7 +541,6 @@
+     }
+ }
+ 
+-
+ static void
+ configure_item_tooltip (GtkToolItem *item)
+ {
+@@ -557,7 +556,6 @@
+     }
+ }
+ 
+-
+ static void
+ connect_widget_signals (GtkWidget *proxy, EggEditableToolbar *etoolbar)
+ {
+--- a/cut-n-paste/toolbar-editor/egg-toolbar-editor.c
++++ b/cut-n-paste/toolbar-editor/egg-toolbar-editor.c
+@@ -36,7 +36,6 @@
+   {EGG_TOOLBAR_ITEM_TYPE, GTK_TARGET_SAME_APP, 0},
+ };
+ 
+-
+ static void egg_toolbar_editor_finalize         (GObject *object);
+ static void update_editor_sheet                 (EggToolbarEditor *editor);
+ 
+--- a/cut-n-paste/toolbar-editor/egg-toolbar-editor.h
++++ b/cut-n-paste/toolbar-editor/egg-toolbar-editor.h
+@@ -34,7 +34,6 @@
+ #define EGG_IS_TOOLBAR_EDITOR_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_TOOLBAR_EDITOR))
+ #define EGG_TOOLBAR_EDITOR_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_TOOLBAR_EDITOR, EggToolbarEditorClass))
+ 
+-
+ typedef struct EggToolbarEditor EggToolbarEditor;
+ typedef struct EggToolbarEditorPrivate EggToolbarEditorPrivate;
+ 
+@@ -51,7 +50,6 @@
+   GtkBoxClass parent_class;
+ };
+ 
+-
+ GType            egg_toolbar_editor_get_type     (void);
+ GtkWidget        *egg_toolbar_editor_new         (GtkUIManager *manager,
+                                                   EggToolbarsModel *model);
+--- a/cut-n-paste/toolbar-editor/egg-toolbars-model.c
++++ b/cut-n-paste/toolbar-editor/egg-toolbars-model.c
+@@ -213,7 +213,6 @@
+   EggToolbarsItem *idata2;
+   GNode *toolbar, *item;
+ 
+-
+   for(toolbar = g_node_first_child (model->priv->toolbars);
+       toolbar != NULL; toolbar = g_node_next_sibling (toolbar))
+     {
+@@ -330,7 +329,6 @@
+ 		 0, toolbar_position);
+ }
+ 
+-
+ char *
+ egg_toolbars_model_get_data (EggToolbarsModel *model,
+                              GdkAtom           type,
+--- a/cut-n-paste/zoom-control/ephy-zoom.c
++++ b/cut-n-paste/zoom-control/ephy-zoom.c
+@@ -54,7 +54,6 @@
+ 	return n_zoom_levels - 1;
+ }
+ 
+-
+ float
+ ephy_zoom_get_changed_zoom_level (float level, gint steps)
+ {
+--- a/libdocument/ev-document-attachments.c
++++ b/libdocument/ev-document-attachments.c
+@@ -52,4 +52,3 @@
+ 	return iface->get_attachments (document_attachments);
+ }
+ 
+-
+--- a/libdocument/ev-document-factory.c
++++ b/libdocument/ev-document-factory.c
+@@ -106,7 +106,6 @@
+ 	return EV_COMPRESSION_NONE;
+ }
+ 
+-
+ /*
+  * get_document_from_uri:
+  * @uri: the document URI
+--- a/libdocument/ev-document-fonts.h
++++ b/libdocument/ev-document-fonts.h
+@@ -37,7 +37,6 @@
+ 
+ G_BEGIN_DECLS
+ 
+-
+ #define EV_TYPE_DOCUMENT_FONTS		  (ev_document_fonts_get_type ())
+ #define EV_DOCUMENT_FONTS(o)		  (G_TYPE_CHECK_INSTANCE_CAST ((o), EV_TYPE_DOCUMENT_FONTS, EvDocumentFonts))
+ #define EV_DOCUMENT_FONTS_IFACE(k)	  (G_TYPE_CHECK_CLASS_CAST((k), EV_TYPE_DOCUMENT_FONTS, EvDocumentFontsInterface))
+--- a/libdocument/ev-document-misc.c
++++ b/libdocument/ev-document-misc.c
+@@ -149,7 +149,6 @@
+ 	}
+ }
+ 
+-
+ void
+ ev_document_misc_paint_one_page (cairo_t      *cr,
+ 				 GtkWidget    *widget,
+--- a/libdocument/ev-document-security.h
++++ b/libdocument/ev-document-security.h
+@@ -35,7 +35,6 @@
+ 
+ G_BEGIN_DECLS
+ 
+-
+ #define EV_TYPE_DOCUMENT_SECURITY		  (ev_document_security_get_type ())
+ #define EV_DOCUMENT_SECURITY(o)			  (G_TYPE_CHECK_INSTANCE_CAST ((o), EV_TYPE_DOCUMENT_SECURITY, EvDocumentSecurity))
+ #define EV_DOCUMENT_SECURITY_IFACE(k)	  	  (G_TYPE_CHECK_CLASS_CAST((k), EV_TYPE_DOCUMENT_SECURITY, EvDocumentSecurityInterface))
+--- a/libdocument/ev-document-text.c
++++ b/libdocument/ev-document-text.c
+@@ -42,7 +42,6 @@
+ 	return iface->get_text (document_text, page);
+ }
+ 
+-
+ gboolean
+ ev_document_text_get_text_layout (EvDocumentText   *document_text,
+ 				  EvPage           *page,
+--- a/libdocument/ev-document.c
++++ b/libdocument/ev-document.c
+@@ -388,7 +388,6 @@
+ 	return klass->get_page (document, index);
+ }
+ 
+-
+ #ifdef ENABLE_SYNCTEX
+ static gboolean
+ _ev_document_support_synctex (EvDocument *document)
+--- a/libdocument/ev-file-helpers.h
++++ b/libdocument/ev-file-helpers.h
+@@ -66,7 +66,6 @@
+ 				       EvCompressionType  type,
+ 				       GError           **error);
+ 
+-
+ G_END_DECLS
+ 
+ #endif /* EV_FILE_HELPERS_H */
+--- a/libdocument/ev-form-field.h
++++ b/libdocument/ev-form-field.h
+@@ -209,7 +209,6 @@
+ GType        ev_form_field_signature_get_type (void) G_GNUC_CONST;
+ EvFormField *ev_form_field_signature_new      (gint                  id);
+ 
+-
+ G_END_DECLS
+ 
+ #endif /* !EV_FORM_FIELD_H */
+--- a/libdocument/ev-image.h
++++ b/libdocument/ev-image.h
+@@ -62,7 +62,6 @@
+ 					GdkPixbuf       *pixbuf);
+ const gchar *ev_image_get_tmp_uri      (EvImage         *image);
+ 
+-
+ G_END_DECLS
+ 
+ #endif /* __EV_IMAGE_H__ */
+--- a/libdocument/ev-render-context.h
++++ b/libdocument/ev-render-context.h
+@@ -52,7 +52,6 @@
+ 	gdouble scale;
+ };
+ 
+-
+ GType            ev_render_context_get_type        (void) G_GNUC_CONST;
+ EvRenderContext *ev_render_context_new             (EvPage          *page,
+ 						    gint             rotation,
+@@ -64,7 +63,6 @@
+ void             ev_render_context_set_scale       (EvRenderContext *rc,
+ 						    gdouble          scale);
+ 
+-
+ G_END_DECLS
+ 
+ #endif /* !EV_RENDER_CONTEXT */
+--- a/libdocument/ev-transition-effect.h
++++ b/libdocument/ev-transition-effect.h
+@@ -61,7 +61,6 @@
+ 	EV_TRANSITION_DIRECTION_OUTWARD
+ } EvTransitionEffectDirection;
+ 
+-
+ typedef struct EvTransitionEffect      EvTransitionEffect;
+ typedef struct EvTransitionEffectClass EvTransitionEffectClass;
+ 
+@@ -75,7 +74,6 @@
+ 	GObjectClass parent_class;
+ };
+ 
+-
+ GType                 ev_transition_effect_get_type           (void) G_GNUC_CONST;
+ 
+ EvTransitionEffect   *ev_transition_effect_new                (EvTransitionEffectType  type,
+--- a/libmisc/ev-page-action-widget.c
++++ b/libmisc/ev-page-action-widget.c
+@@ -305,7 +305,6 @@
+ 	return TRUE;
+ }
+ 
+-
+ static void
+ display_completion_text (GtkCellLayout      *cell_layout,
+ 			 GtkCellRenderer    *renderer,
+@@ -349,7 +348,6 @@
+ 			    EV_DOCUMENT_LINKS_COLUMN_LINK, &link,
+ 			    -1);
+ 
+-
+ 	if (link) {
+ 		text = ev_link_get_title (link);
+ 		g_object_unref (link);
+@@ -445,7 +443,6 @@
+ 	return filter_model;
+ }
+ 
+-
+ void
+ ev_page_action_widget_update_links_model (EvPageActionWidget *proxy, GtkTreeModel *model)
+ {
+--- a/libview/ev-page-accessible.c
++++ b/libview/ev-page-accessible.c
+@@ -37,7 +37,6 @@
+ 	gboolean          children_initialized;
+ };
+ 
+-
+ enum {
+ 	PROP_0,
+ 	PROP_VIEW_ACCESSIBLE,
+@@ -412,7 +411,6 @@
+ 	EvRectangle *next_word_end;
+ 	gint prev_offset, next_offset;
+ 
+-
+ 	if (!log_attrs[offset].is_white)
+ 		return FALSE;
+ 
+--- a/libview/ev-pixbuf-cache.c
++++ b/libview/ev-pixbuf-cache.c
+@@ -72,7 +72,6 @@
+ 	void (* job_finished) (EvPixbufCache *pixbuf_cache);
+ };
+ 
+-
+ enum
+ {
+ 	JOB_FINISHED,
+@@ -92,7 +91,6 @@
+ 						  gint                page,
+ 						  gfloat              scale);
+ 
+-
+ /* These are used for iterating through the prev and next arrays */
+ #define FIRST_VISIBLE_PREV(pixbuf_cache) \
+ 	(MAX (0, pixbuf_cache->preload_cache_size - pixbuf_cache->start_page))
+@@ -223,7 +221,6 @@
+ 	G_OBJECT_CLASS (ev_pixbuf_cache_parent_class)->dispose (object);
+ }
+ 
+-
+ EvPixbufCache *
+ ev_pixbuf_cache_new (GtkWidget       *view,
+ 		     EvDocumentModel *model,
+@@ -985,7 +982,6 @@
+ 	}
+ }
+ 
+-
+ void
+ ev_pixbuf_cache_style_changed (EvPixbufCache *pixbuf_cache)
+ {
+@@ -1265,7 +1261,6 @@
+ 	}
+ }
+ 
+-
+ /* Returns what the pixbuf cache thinks is */
+ 
+ GList *
+@@ -1356,4 +1351,3 @@
+ 		 EV_JOB_PRIORITY_URGENT);
+ }
+ 
+-
+--- a/libview/ev-pixbuf-cache.h
++++ b/libview/ev-pixbuf-cache.h
+@@ -39,8 +39,6 @@
+ #define EV_PIXBUF_CACHE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_PIXBUF_CACHE, EvPixbufCache))
+ #define EV_IS_PIXBUF_CACHE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EV_TYPE_PIXBUF_CACHE))
+ 
+-
+-
+ /* The coordinates in the rect here are at scale == 1.0, so that we can ignore
+  * resizings.  There is one per page, maximum.
+  */
+--- a/libview/ev-timeline.c
++++ b/libview/ev-timeline.c
+@@ -56,10 +56,8 @@
+ 
+ static guint signals [LAST_SIGNAL] = { 0, };
+ 
+-
+ G_DEFINE_TYPE_WITH_PRIVATE (EvTimeline, ev_timeline, G_TYPE_OBJECT)
+ 
+-
+ static void
+ ev_timeline_init (EvTimeline *timeline)
+ {
+--- a/libview/ev-timeline.h
++++ b/libview/ev-timeline.h
+@@ -59,7 +59,6 @@
+ 				    gdouble     progress);
+ };
+ 
+-
+ GType                 ev_timeline_get_type           (void) G_GNUC_CONST;
+ 
+ EvTimeline           *ev_timeline_new                (guint                    duration);
+@@ -84,7 +83,6 @@
+ 
+ gdouble               ev_timeline_get_progress       (EvTimeline             *timeline);
+ 
+-
+ G_END_DECLS
+ 
+ #endif /* __EV_TIMELINE_H__ */
+--- a/libview/ev-transition-animation.c
++++ b/libview/ev-transition-animation.c
+@@ -41,10 +41,8 @@
+ 	PROP_DEST_SURFACE
+ };
+ 
+-
+ G_DEFINE_TYPE_WITH_PRIVATE (EvTransitionAnimation, ev_transition_animation, EV_TYPE_TIMELINE)
+ 
+-
+ static void
+ ev_transition_animation_init (EvTransitionAnimation *animation)
+ {
+--- a/libview/ev-transition-animation.h
++++ b/libview/ev-transition-animation.h
+@@ -50,7 +50,6 @@
+ 	EvTimelineClass parent_class;
+ };
+ 
+-
+ GType                   ev_transition_animation_get_type           (void) G_GNUC_CONST;
+ 
+ EvTransitionAnimation * ev_transition_animation_new                (EvTransitionEffect    *effect);
+@@ -67,7 +66,6 @@
+ 								    GdkRectangle           page_area);
+ gboolean                ev_transition_animation_ready              (EvTransitionAnimation *animation);
+ 
+-
+ G_END_DECLS
+ 
+ #endif /* __EV_TRANSITION_ANIMATION_H__ */
+--- a/libview/ev-view-presentation.c
++++ b/libview/ev-view-presentation.c
+@@ -1385,7 +1385,6 @@
+ 	return TRUE;
+ }
+ 
+-
+ static void
+ add_change_page_binding_keypad (GtkBindingSet  *binding_set,
+ 				guint           keyval,
+--- a/libview/ev-view.c
++++ b/libview/ev-view.c
+@@ -5621,7 +5621,6 @@
+ 
+ /*** Drawing ***/
+ 
+-
+ static void
+ draw_rubberband (EvView             *view,
+ 		 cairo_t            *cr,
+@@ -5652,7 +5651,6 @@
+ 	cairo_restore (cr);
+ }
+ 
+-
+ static void
+ highlight_find_results (EvView *view, cairo_t *cr, int page)
+ {
+--- a/libview/ev-web-view.c
++++ b/libview/ev-web-view.c
+@@ -31,7 +31,6 @@
+ #include "ev-document-model.h"
+ #include "ev-jobs.h"
+ 
+-
+  typedef enum {
+  	EV_WEB_VIEW_FIND_NEXT,
+  	EV_WEB_VIEW_FIND_PREV
+@@ -322,7 +321,6 @@
+ 	web_view_update_range_and_current_page (webview);
+ }
+ 
+-
+ gboolean
+ ev_web_view_next_page (EvWebView *webview)
+ {
+--- a/libview/ev-web-view.h
++++ b/libview/ev-web-view.h
+@@ -35,7 +35,6 @@
+ #include <glib-object.h>
+ G_BEGIN_DECLS
+ 
+-
+ typedef struct _EvWebView       EvWebView;
+ typedef struct _EvWebViewClass  EvWebViewClass;
+ 
+--- a/previewer/ev-previewer-window.c
++++ b/previewer/ev-previewer-window.c
+@@ -621,7 +621,6 @@
+ 	return object;
+ }
+ 
+-
+ static void
+ ev_previewer_window_class_init (EvPreviewerWindowClass *klass)
+ {
+--- a/shell/eggfindbar.c
++++ b/shell/eggfindbar.c
+@@ -573,7 +573,6 @@
+   g_object_thaw_notify (G_OBJECT (find_bar));
+ }
+ 
+-
+ /**
+  * egg_find_bar_get_search_string:
+  *
+--- a/shell/eggfindbar.h
++++ b/shell/eggfindbar.h
+@@ -77,4 +77,3 @@
+ 
+ #endif /* __EGG_FIND_BAR_H__ */
+ 
+-
+--- a/shell/ev-application.c
++++ b/shell/ev-application.c
+@@ -21,7 +21,6 @@
+  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+  */
+ 
+-
+ #include <config.h>
+ #include <stdlib.h>
+ #include <string.h>
+@@ -311,7 +310,6 @@
+ 	return empty_window;
+ }
+ 
+-
+ #ifdef ENABLE_DBUS
+ typedef struct {
+ 	gchar          *uri;
+--- a/shell/ev-bookmarks.h
++++ b/shell/ev-bookmarks.h
+@@ -50,8 +50,6 @@
+ void         ev_bookmarks_update        (EvBookmarks *bookmarks,
+                                          EvBookmark  *bookmark);
+ 
+-
+-
+ G_END_DECLS
+ 
+ #endif /* EV_BOOKMARKS_H */
+--- a/shell/ev-daemon.c
++++ b/shell/ev-daemon.c
+@@ -43,7 +43,6 @@
+ 
+ #define LOG g_debug
+ 
+-
+ #define EV_TYPE_DAEMON_APPLICATION              (ev_daemon_application_get_type ())
+ #define EV_DAEMON_APPLICATION(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), EV_TYPE_DAEMON_APPLICATION, EvDaemonApplication))
+ 
+--- a/shell/ev-history.c
++++ b/shell/ev-history.c
+@@ -24,7 +24,6 @@
+ 
+ #include "ev-history.h"
+ 
+-
+ enum
+ {
+ 	HISTORY_CHANGED,
+--- a/shell/ev-loading-message.c
++++ b/shell/ev-loading-message.c
+@@ -174,4 +174,3 @@
+         return message;
+ }
+ 
+-
+--- a/shell/ev-media-player-keys.h
++++ b/shell/ev-media-player-keys.h
+@@ -37,7 +37,6 @@
+ typedef struct _EvMediaPlayerKeys EvMediaPlayerKeys;
+ typedef struct _EvMediaPlayerKeysClass EvMediaPlayerKeysClass;
+ 
+-
+ GType	           ev_media_player_keys_get_type  (void) G_GNUC_CONST;
+ 
+ EvMediaPlayerKeys *ev_media_player_keys_new	  (void);
+--- a/shell/ev-navigation-action.c
++++ b/shell/ev-navigation-action.c
+@@ -26,7 +26,6 @@
+ #include "ev-navigation-action.h"
+ #include "ev-navigation-action-widget.h"
+ 
+-
+ enum
+ {
+ 	WIDGET_ACTIVATE_LINK,
+--- a/shell/ev-open-recent-action.c
++++ b/shell/ev-open-recent-action.c
+@@ -24,7 +24,6 @@
+ 
+ #include "ev-open-recent-action.h"
+ 
+-
+ enum {
+ 	ITEM_ACTIVATED,
+ 	N_SIGNALS
+--- a/shell/ev-password-view.c
++++ b/shell/ev-password-view.c
+@@ -18,7 +18,6 @@
+  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+  */
+ 
+-
+ #ifdef HAVE_CONFIG_H
+ #include "config.h"
+ #endif
+@@ -47,7 +46,6 @@
+ 
+ static guint password_view_signals [LAST_SIGNAL] = { 0 };
+ 
+-
+ G_DEFINE_TYPE_WITH_PRIVATE (EvPasswordView, ev_password_view, GTK_TYPE_VIEWPORT)
+ 
+ static void
+--- a/shell/ev-sidebar-attachments.c
++++ b/shell/ev-sidebar-attachments.c
+@@ -631,7 +631,6 @@
+ 	g_object_unref (job);
+ }
+ 
+-
+ static void
+ ev_sidebar_attachments_document_changed_cb (EvDocumentModel      *model,
+ 					    GParamSpec           *pspec,
+--- a/shell/ev-sidebar-bookmarks.c
++++ b/shell/ev-sidebar-bookmarks.c
+@@ -122,7 +122,6 @@
+         GtkTreeModel              *model;
+         GtkTreeIter                iter;
+ 
+-
+         selection = gtk_tree_view_get_selection (tree_view);
+         if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
+                 GtkTreePath *path;
+--- a/shell/ev-sidebar-layers.c
++++ b/shell/ev-sidebar-layers.c
+@@ -239,7 +239,6 @@
+ 	gtk_tree_selection_set_mode (gtk_tree_view_get_selection (tree_view),
+ 				     GTK_SELECTION_NONE);
+ 
+-
+ 	column = gtk_tree_view_column_new ();
+ 
+ 	renderer = gtk_cell_renderer_toggle_new ();
+--- a/shell/ev-sidebar-links.c
++++ b/shell/ev-sidebar-links.c
+@@ -379,7 +379,6 @@
+ 	return FALSE;
+ }
+ 
+-
+ static void
+ ev_sidebar_links_construct (EvSidebarLinks *ev_sidebar_links)
+ {
+@@ -425,7 +424,6 @@
+ 					     "markup", EV_DOCUMENT_LINKS_COLUMN_MARKUP,
+ 					     NULL);
+ 
+-
+ 	renderer = gtk_cell_renderer_text_new ();
+ 	gtk_tree_view_column_pack_end (GTK_TREE_VIEW_COLUMN (column), renderer, FALSE);
+ 	gtk_tree_view_column_set_attributes (GTK_TREE_VIEW_COLUMN (column), renderer,
+@@ -566,7 +564,6 @@
+ 	}
+ }
+ 
+-
+ static gint
+ page_link_tree_sort (gconstpointer a, gconstpointer b, void *data)
+ {
+--- a/shell/ev-sidebar-links.h
++++ b/shell/ev-sidebar-links.h
+@@ -63,4 +63,3 @@
+ 
+ #endif /* __EV_SIDEBAR_LINKS_H__ */
+ 
+-
+--- a/shell/ev-sidebar-page.c
++++ b/shell/ev-sidebar-page.c
+@@ -74,7 +74,6 @@
+ 	return iface->get_label (sidebar_page);
+ }
+ 
+-
+ static void
+ ev_sidebar_page_default_init (EvSidebarPageInterface *iface)
+ {
+--- a/shell/ev-sidebar-page.h
++++ b/shell/ev-sidebar-page.h
+@@ -58,7 +58,6 @@
+ 				                 EvDocumentModel *model);
+ const gchar*  ev_sidebar_page_get_label         (EvSidebarPage *page);
+ 
+-
+ G_END_DECLS
+ 
+ #endif /* EV_SIDEBAR_PAGE */
+--- a/shell/ev-sidebar-thumbnails.c
++++ b/shell/ev-sidebar-thumbnails.c
+@@ -245,7 +245,6 @@
+ 	return cache;
+ }
+ 
+-
+ static void
+ ev_sidebar_thumbnails_dispose (GObject *object)
+ {
+--- a/shell/ev-sidebar-thumbnails.h
++++ b/shell/ev-sidebar-thumbnails.h
+@@ -56,4 +56,3 @@
+ 
+ #endif /* __EV_SIDEBAR_THUMBNAILS_H__ */
+ 
+-
+--- a/shell/ev-sidebar.c
++++ b/shell/ev-sidebar.c
+@@ -446,7 +446,6 @@
+ 	gtk_list_store_move_before(GTK_LIST_STORE(ev_sidebar->priv->page_model),
+ 					   &iter, NULL);
+ 
+-
+ 	/* Set the first item added as active */
+ 	gtk_tree_model_get_iter_first (ev_sidebar->priv->page_model, &iter);
+ 	gtk_tree_model_get (ev_sidebar->priv->page_model,
+--- a/shell/ev-sidebar.h
++++ b/shell/ev-sidebar.h
+@@ -64,4 +64,3 @@
+ 
+ #endif /* __EV_SIDEBAR_H__ */
+ 
+-
+--- a/shell/ev-window.c
++++ b/shell/ev-window.c
+@@ -418,7 +418,6 @@
+ 	G_GNUC_END_IGNORE_DEPRECATIONS;
+ }
+ 
+-
+ static void
+ ev_window_setup_action_sensitivity (EvWindow *ev_window)
+ {
+@@ -1555,7 +1554,6 @@
+ 		ev_document_model_set_scale (model, g_settings_get_double (settings, "zoom"));
+ }
+ 
+-
+ static void
+ ev_window_clear_thumbnail_job (EvWindow *ev_window)
+ {
+@@ -3636,7 +3634,6 @@
+ 		GtkWidget *dialog;
+ 		GError    *error = NULL;
+ 
+-
+ 		ev_print_operation_get_error (op, &error);
+ 
+ 		/* The message area is already used by
+@@ -3891,7 +3888,6 @@
+ 		return FALSE;
+ 	}
+ 
+-
+ 	text = g_markup_printf_escaped (_("Save a copy of document “%s” before closing?"),
+ 					gtk_window_get_title (GTK_WINDOW (ev_window)));
+ 
+@@ -4414,7 +4410,6 @@
+                                          _("Running in presentation mode"));
+ }
+ 
+-
+ static void
+ ev_window_uninhibit_screensaver (EvWindow *window)
+ {
+@@ -4727,7 +4722,6 @@
+ 	ev_window_update_actions (window);
+ }
+ 
+-
+ static void
+ ev_window_cmd_edit_rotate_left (GtkAction *action, EvWindow *ev_window)
+ {
+@@ -5977,7 +5971,6 @@
+ 		 * the new expanded window size.
+ 		 */
+ 
+-
+ 		if (ev_window->priv->chrome & EV_CHROME_SIDEBAR)
+ 		{
+ 			GtkAllocation alloc;
+@@ -6491,7 +6484,6 @@
+ 	{ "EditSaveSettings", NULL, N_("Save Current Settings as _Default"), "<control>T", NULL,
+ 	  G_CALLBACK (ev_window_cmd_edit_save_settings) },
+ 
+-
+         /* View menu */
+         { "ViewZoomIn", "zoom-in", N_("Zoom _In"), "<control>plus",
+           N_("Enlarge the document"),
+@@ -7746,7 +7738,6 @@
+         ev_atril_window_emit_document_loaded (window->priv->skeleton, window->priv->uri);
+ }
+ 
+-
+ #ifdef ENABLE_SYNCTEX
+ static gboolean
+ handle_sync_view_cb (EvAtrilWindow        *object,
+--- a/shell/ev-window.h
++++ b/shell/ev-window.h
+@@ -58,7 +58,6 @@
+ #define EV_IS_WINDOW_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE((klass), EV_TYPE_WINDOW))
+ #define EV_WINDOW_GET_CLASS(object)	(G_TYPE_INSTANCE_GET_CLASS((object), EV_TYPE_WINDOW, EvWindowClass))
+ 
+-
+ struct _EvWindow {
+ 	GtkApplicationWindow base_instance;
+ 	EvWindowPrivate     *priv;
+@@ -87,7 +86,6 @@
+ 					 int		 last_page);
+ const gchar *	ev_window_get_dbus_object_path (EvWindow *ev_window);
+ 
+-
+ G_END_DECLS
+ 
+ #endif /* !EV_WINDOW_H */
+--- a/shell/main.c
++++ b/shell/main.c
+@@ -36,7 +36,6 @@
+ #include "eggsmclient.h"
+ #include "eggdesktopfile.h"
+ 
+-
+ static gchar   *ev_page_label;
+ static gchar   *ev_find_string;
+ static gint     ev_page_index = 0;
+@@ -48,7 +47,6 @@
+ static gchar   *print_settings;
+ static const char **file_arguments = NULL;
+ 
+-
+ static gboolean
+ option_version_cb (const gchar *option_name,
+                    const gchar *value,
+@@ -206,8 +204,6 @@
+ 			continue;
+ 		}
+ 
+-
+-
+ 		ev_application_open_uri_at_dest (EV_APP, uri, screen, dest,
+ 						 mode, ev_find_string,
+ 						 GDK_CURRENT_TIME);
diff -Nru atril-1.26.0/debian/patches/0006-comics-Use-libarchive-to-unpack-documents.patch atril-1.26.0/debian/patches/0006-comics-Use-libarchive-to-unpack-documents.patch
--- atril-1.26.0/debian/patches/0006-comics-Use-libarchive-to-unpack-documents.patch	1970-01-01 01:00:00.000000000 +0100
+++ atril-1.26.0/debian/patches/0006-comics-Use-libarchive-to-unpack-documents.patch	2024-01-23 10:06:08.000000000 +0100
@@ -0,0 +1,1814 @@
+From aa8e9dad472cbadc96719a8f521768aeeb0913f0 Mon Sep 17 00:00:00 2001
+From: lukefromdc <lukefromdc@hushmail.com>
+Date: Mon, 25 Dec 2023 15:11:04 -0500
+Subject: [PATCH 2/2] comics: Use libarchive to unpack documents
+
+This commit eliminates the use of external commands for opening
+comic documents, and uses libarchive instead.
+
+Signed-off-by: Mike Gabriel <mike.gabriel@das-netzwerkteam.de>
+---
+ backend/comics/Makefile.am       |    5 +-
+ backend/comics/comics-document.c | 1143 +++++++++++-------------------
+ backend/comics/comics-document.h |    7 +-
+ backend/comics/ev-archive.c      |  323 +++++++++
+ backend/comics/ev-archive.h      |   56 ++
+ configure.ac                     |    3 +
+ libdocument/ev-document.h        |    1 +
+ 7 files changed, 799 insertions(+), 739 deletions(-)
+ create mode 100644 backend/comics/ev-archive.c
+ create mode 100644 backend/comics/ev-archive.h
+
+diff --git a/backend/comics/Makefile.am b/backend/comics/Makefile.am
+index b27f9b85..77f3dedb 100644
+--- a/backend/comics/Makefile.am
++++ b/backend/comics/Makefile.am
+@@ -12,12 +12,15 @@ backend_LTLIBRARIES = libcomicsdocument.la
+ 
+ libcomicsdocument_la_SOURCES = \
+ 	comics-document.c      \
+-	comics-document.h
++	comics-document.h      \
++	ev-archive.c     \
++	ev-archive.h
+ 
+ libcomicsdocument_la_LDFLAGS = $(BACKEND_LIBTOOL_FLAGS)
+ libcomicsdocument_la_LIBADD =				\
+ 	$(top_builddir)/libdocument/libatrildocument.la	\
+ 	$(BACKEND_LIBS)					\
++	$(COMICS_LIBS)					\
+ 	$(LIB_LIBS)
+ 
+ backend_in_files = comicsdocument.atril-backend.desktop.in
+diff --git a/backend/comics/comics-document.c b/backend/comics/comics-document.c
+index ed02a35c..1da1eee2 100644
+--- a/backend/comics/comics-document.c
++++ b/backend/comics/comics-document.c
+@@ -30,24 +30,17 @@
+ #include <glib/gstdio.h>
+ #include <gio/gio.h>
+ 
+-#include <sys/wait.h>
+-
+ #include "comics-document.h"
+ #include "ev-document-misc.h"
+ #include "ev-document-thumbnails.h"
+ #include "ev-file-helpers.h"
++#include "ev-archive.h"
++#include <archive.h>
++#include <archive_entry.h>
+ 
+ #define EV_EOL "\n"
+ 
+-typedef enum
+-{
+-	RARLABS,
+-	GNAUNRAR,
+-	UNZIP,
+-	P7ZIP,
+-	TAR,
+-	UNARCHIVER
+-} ComicBookDecompressType;
++#define BLOCK_SIZE 10240
+ 
+ typedef struct _ComicsDocumentClass ComicsDocumentClass;
+ 
+@@ -58,398 +51,269 @@ struct _ComicsDocumentClass
+ 
+ struct _ComicsDocument
+ {
+-	EvDocument parent_instance;
+-
+-	gchar    *archive, *dir;
+-	GPtrArray *page_names;
+-	gchar    *selected_command, *alternative_command;
+-	gchar    *extract_command, *list_command, *decompress_tmp;
+-	gboolean regex_arg;
+-	gint     offset;
+-	ComicBookDecompressType command_usage;
++	EvDocument     parent_instance;
++	EvArchive     *archive;
++	gchar         *archive_path;
++	gchar         *archive_uri;
++	GPtrArray     *page_names; /* elem: char * */
++	GHashTable    *page_positions; /* key: char *, value: uint + 1 */
++
+ };
+ 
+-#define OFFSET_7Z 53
+-#define OFFSET_ZIP 2
+-#define NO_OFFSET 0
+-
+-/* For perfomance reasons of 7z* we've choosen to decompress on the temporary
+- * directory instead of decompressing on the stdout */
+-
+-/**
+- * @extract: command line arguments to pass to extract a file from the archive
+- *   to stdout.
+- * @list: command line arguments to list the archive contents
+- * @decompress_tmp: command line arguments to pass to extract the archive
+- *   into a directory.
+- * @regex_arg: whether the command can accept regex expressions
+- * @offset: the position offset of the filename on each line in the output of
+- *   running the @list command
+- */
+-typedef struct {
+-        char *extract;
+-        char *list;
+-        char *decompress_tmp;
+-        gboolean regex_arg;
+-        gint offset;
+-} ComicBookDecompressCommand;
++static void       
++comics_document_document_thumbnails_iface_init (EvDocumentThumbnailsInterface *iface);
++EV_BACKEND_REGISTER_WITH_CODE (ComicsDocument, comics_document,
++    {
++        EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_THUMBNAILS,
++                        comics_document_document_thumbnails_iface_init);
++    } );
++
++#define FORMAT_UNKNOWN     0
++#define FORMAT_SUPPORTED   1
++#define FORMAT_UNSUPPORTED 2
++
++/* Returns a GHashTable of:
++ * <key>: file extensions
++ * <value>: degree of support in gdk-pixbuf */
++static GHashTable *
++get_image_extensions(void)
++{
++	GHashTable *extensions;
++	GSList *formats = gdk_pixbuf_get_formats ();
++	GSList *l;
++	guint i;
++	const char *known_image_formats[] = {
++		"png",
++		"jpg",
++		"jpeg",
++		"webp"
++	};
++
++	extensions = g_hash_table_new_full (g_str_hash, g_str_equal,
++					    g_free, NULL);
++	for (l = formats; l != NULL; l = l->next) {
++		int i;
++		gchar **ext = gdk_pixbuf_format_get_extensions (l->data);
++
++		for (i = 0; ext[i] != NULL; i++) {
++			g_hash_table_insert (extensions,
++					     g_strdup (ext[i]),
++					     GINT_TO_POINTER (FORMAT_SUPPORTED));
++		}
+ 
+-static const ComicBookDecompressCommand command_usage_def[] = {
+-        /* RARLABS unrar */
+-	{"%s p -c- -ierr --", "%s vb -c- -- %s", NULL             , FALSE, NO_OFFSET},
++		g_strfreev (ext);
++	}
++	g_slist_free (formats);
+ 
+-        /* GNA! unrar */
+-	{NULL               , "%s t %s"        , "%s -xf %s %s"   , FALSE, NO_OFFSET},
++	/* Add known image formats that aren't supported by gdk-pixbuf */
++	for (i = 0; i < G_N_ELEMENTS (known_image_formats); i++) {
++		if (!g_hash_table_lookup (extensions, known_image_formats[i])) {
++			g_hash_table_insert (extensions,
++					     g_strdup (known_image_formats[i]),
++					     GINT_TO_POINTER (FORMAT_UNSUPPORTED));
++		}
++	}
+ 
+-        /* unzip */
+-	{"%s -p -C --"      , "%s %s"          , NULL             , TRUE , OFFSET_ZIP},
++	return extensions;
++}
+ 
+-        /* 7zip */
+-	{NULL               , "%s l -- %s"     , "%s x -y %s -o%s", FALSE, OFFSET_7Z},
++static int
++has_supported_extension (const char *name,
++			 GHashTable *supported_extensions)
++{
++	gboolean ret = FALSE;
++	gchar *suffix;
++	suffix = g_strrstr (name, ".");
++	if (!suffix)
++		return ret;
+ 
+-        /* tar */
+-	{"%s -xOf"          , "%s -tf %s"      , NULL             , FALSE, NO_OFFSET},
++	suffix = g_ascii_strdown (suffix + 1, -1);
++	ret = GPOINTER_TO_INT (g_hash_table_lookup (supported_extensions, suffix));
++	g_free (suffix);
+ 
+-	/* UNARCHIVER */
+-	{"unar -o -"	    , "%s %s"	       , NULL		  , FALSE, NO_OFFSET}
+-};
++	return ret;
++}
+ 
+-static void       comics_document_document_thumbnails_iface_init (EvDocumentThumbnailsInterface *iface);
++#define APPLE_DOUBLE_PREFIX "._"
++static gboolean
++is_apple_double (const char *name)
++{
++char *basename;
++	gboolean ret = FALSE;
+ 
+-static GSList*    get_supported_image_extensions (void);
+-static void       get_page_size_area_prepared_cb (GdkPixbufLoader *loader,
+-						  gpointer data);
+-static void       render_pixbuf_size_prepared_cb (GdkPixbufLoader *loader,
+-						  gint width,
+-						  gint height,
+-						  gpointer data);
+-static char**     extract_argv                   (EvDocument *document,
+-						  gint page);
++	basename = g_path_get_basename (name);
++	if (basename == NULL) {
++		g_debug ("Filename '%s' doesn't have a basename?", name);
++		return ret;
++	}
++	ret = g_str_has_prefix (basename, APPLE_DOUBLE_PREFIX);
++	g_free (basename);
+ 
+-EV_BACKEND_REGISTER_WITH_CODE (ComicsDocument, comics_document,
+-	{
+-		EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_THUMBNAILS,
+-						comics_document_document_thumbnails_iface_init);
+-	} );
+-
+-/**
+- * comics_regex_quote:
+- * @unquoted_string: a literal string
+- *
+- * Quotes a string so unzip will not interpret the regex expressions of
+- * @unquoted_string. Basically, this functions uses [] to disable regex
+- * expressions. The return value must be freed with * g_free()
+- *
+- * Return value: quoted and disabled-regex string
+- **/
+-static gchar *
+-comics_regex_quote (const gchar *unquoted_string)
++	return ret;
++}
++
++static gboolean
++archive_reopen_if_needed (ComicsDocument  *comics_document,
++			  const char      *page_wanted,
++			  GError         **error)
+ {
+-	const gchar *p;
+-	GString *dest;
+-
+-	dest = g_string_new ("'");
+-
+-	p = unquoted_string;
+-
+-	while (*p) {
+-		switch (*p) {
+-			/* * matches a sequence of 0 or more characters */
+-			case ('*'):
+-			/* ? matches exactly 1 charactere */
+-			case ('?'):
+-			/* [...]  matches any single character found inside
+-			 * the brackets. Disabling the first bracket is enough.
+-			 */
+-			case ('['):
+-				g_string_append (dest, "[");
+-				g_string_append_c (dest, *p);
+-				g_string_append (dest, "]");
+-				break;
+-			/* Because \ escapes regex expressions that we are
+-			 * disabling for unzip, we need to disable \ too */
+-			case ('\\'):
+-				g_string_append (dest, "[\\\\]");
+-				break;
+-			/* Escape single quote inside the string */
+-			case ('\''):
+-				g_string_append (dest, "'\\''");
+-				break;
+-			default:
+-				g_string_append_c (dest, *p);
+-				break;
++	const char *current_page;
++	guint current_page_idx, page_wanted_idx;
++
++	if (ev_archive_at_entry (comics_document->archive)) {
++		current_page = ev_archive_get_entry_pathname (comics_document->archive);
++		if (current_page) {
++			current_page_idx = GPOINTER_TO_UINT (g_hash_table_lookup (comics_document->page_positions, current_page));
++			page_wanted_idx = GPOINTER_TO_UINT (g_hash_table_lookup (comics_document->page_positions, page_wanted));
++
++			if (current_page_idx != 0 &&
++			    page_wanted_idx != 0 &&
++			    page_wanted_idx > current_page_idx)
++				return TRUE;
+ 		}
+-		++p;
++
++		ev_archive_reset (comics_document->archive);
+ 	}
+-	g_string_append_c (dest, '\'');
+-	return g_string_free (dest, FALSE);
++return ev_archive_open_filename (comics_document->archive, comics_document->archive_path, error);
+ }
+ 
+-/* This function manages the command for decompressing a comic book */
+-static gboolean
+-comics_decompress_temp_dir (const gchar *command_decompress_tmp,
+-			    const gchar *command,
+-			    GError      **error)
++static GPtrArray *
++comics_document_list (ComicsDocument  *comics_document,
++		      GError         **error)
+ {
+-	gboolean success;
+-	gchar *std_out, *basename;
+-	GError *err = NULL;
+-	gint retval;
+-
+-	success = g_spawn_command_line_sync (command_decompress_tmp, &std_out,
+-					     NULL, &retval, &err);
+-	basename = g_path_get_basename (command);
+-	if (!success) {
+-		g_set_error (error,
+-			     EV_DOCUMENT_ERROR,
+-			     EV_DOCUMENT_ERROR_INVALID,
+-			     _("Error launching the command “%s” in order to "
+-			     "decompress the comic book: %s"),
+-			     basename,
+-			     err->message);
+-		g_error_free (err);
+-	} else if (WIFEXITED (retval)) {
+-		if (WEXITSTATUS (retval) == EXIT_SUCCESS) {
+-			g_free (std_out);
+-			g_free (basename);
+-			return TRUE;
+-		} else {
+-			g_set_error (error,
++GPtrArray *array = NULL;
++	gboolean has_encrypted_files, has_unsupported_images, has_archive_errors;
++	GHashTable *supported_extensions = NULL;
++
++	if (!ev_archive_open_filename (comics_document->archive, comics_document->archive_path, error)) {
++		if (*error != NULL) {
++			g_warning ("Fatal error handling archive (%s): %s", G_STRFUNC, (*error)->message);
++			g_clear_error (error);
++		}
++
++		g_set_error_literal (error,
+ 				     EV_DOCUMENT_ERROR,
+ 				     EV_DOCUMENT_ERROR_INVALID,
+-				     _("The command “%s” failed at "
+-				     "decompressing the comic book."),
+-				     basename);
+-			g_free (std_out);
++			     _("File is corrupted"));
++		goto out;
++	}
++
++	supported_extensions = get_image_extensions ();
++
++	has_encrypted_files = FALSE;
++	has_unsupported_images = FALSE;
++	has_archive_errors = FALSE;
++	array = g_ptr_array_sized_new (64);
++
++	while (1) {
++		const char *name;
++		int supported;
++
++		if (!ev_archive_read_next_header (comics_document->archive, error)) {
++			if (*error != NULL) {
++				g_debug ("Fatal error handling archive (%s): %s", G_STRFUNC, (*error)->message);
++				g_clear_error (error);
++				has_archive_errors = TRUE;
++				goto out;
++			}
++			break;
+ 		}
+-	} else {
+-		g_set_error (error,
+-			     EV_DOCUMENT_ERROR,
+-			     EV_DOCUMENT_ERROR_INVALID,
+-			     _("The command “%s” did not end normally."),
+-			     basename);
+-		g_free (std_out);
++
++		name = ev_archive_get_entry_pathname (comics_document->archive);
++		/* Ignore https://en.wikipedia.org/wiki/AppleSingle_and_AppleDouble_formats */
++		if (is_apple_double (name)) {
++			g_debug ("Not adding AppleDouble file '%s' to the list of files in the comics", name);
++			continue;
++		}
++
++		supported = has_supported_extension (name, supported_extensions);
++		if (supported == FORMAT_UNKNOWN) {
++			g_debug ("Not adding unsupported file '%s' to the list of files in the comics", name);
++			continue;
++		} else if (supported == FORMAT_UNSUPPORTED) {
++			g_debug ("Not adding unsupported image '%s' to the list of files in the comics", name);
++			has_unsupported_images = TRUE;
++			continue;
++		}
++
++		if (ev_archive_get_entry_is_encrypted (comics_document->archive)) {
++			g_debug ("Not adding encrypted file '%s' to the list of files in the comics", name);
++			has_encrypted_files = TRUE;
++			continue;
++		}
++
++		g_debug ("Adding '%s' to the list of files in the comics", name);
++		g_ptr_array_add (array, g_strdup (name));
+ 	}
+-	g_free (basename);
+-	return FALSE;
++out:
++	if (array->len == 0) {
++		g_ptr_array_free (array, TRUE);
++		array = NULL;
++
++		if (has_encrypted_files) {
++			g_set_error_literal (error,
++					     EV_DOCUMENT_ERROR,
++					     EV_DOCUMENT_ERROR_ENCRYPTED,
++					     _("Archive is encrypted"));
++		} else if (has_unsupported_images) {
++			g_set_error_literal (error,
++					     EV_DOCUMENT_ERROR,
++					     EV_DOCUMENT_ERROR_UNSUPPORTED_CONTENT,
++					     _("No supported images in archive"));
++		} else if (has_archive_errors) {
++			g_set_error_literal (error,
++					     EV_DOCUMENT_ERROR,
++					     EV_DOCUMENT_ERROR_INVALID,
++					     _("File is corrupted"));
++		} else {
++			g_set_error_literal (error,
++					     EV_DOCUMENT_ERROR,
++					     EV_DOCUMENT_ERROR_INVALID,
++					     _("No files in archive"));
++		}
++	}
++
++	if (supported_extensions)
++		g_hash_table_destroy (supported_extensions);
++	ev_archive_reset (comics_document->archive);
++	return array;
+ }
+ 
+-/* This function shows how to use the choosen command for decompressing a
+- * comic book file. It modifies fields of the ComicsDocument struct with
+- * this information */
+-static gboolean
+-comics_generate_command_lines (ComicsDocument *comics_document,
+-			       GError         **error)
++static GHashTable *
++save_positions (GPtrArray *page_names)
+ {
+-	gchar *quoted_file, *quoted_file_aux;
+-	gchar *quoted_command;
+-	ComicBookDecompressType type;
+-
+-	type = comics_document->command_usage;
+-	comics_document->regex_arg = command_usage_def[type].regex_arg;
+-	quoted_command = g_shell_quote (comics_document->selected_command);
+-	if (comics_document->regex_arg) {
+-		quoted_file = comics_regex_quote (comics_document->archive);
+-		quoted_file_aux = g_shell_quote (comics_document->archive);
+-		comics_document->list_command =
+-			   g_strdup_printf (command_usage_def[type].list,
+-			                    comics_document->alternative_command,
+-			                    quoted_file_aux);
+-		g_free (quoted_file_aux);
+-	} else {
+-		quoted_file = g_shell_quote (comics_document->archive);
+-		comics_document->list_command =
+-				g_strdup_printf (command_usage_def[type].list,
+-				                 quoted_command, quoted_file);
+-	}
+-	comics_document->extract_command =
+-			    g_strdup_printf (command_usage_def[type].extract,
+-				             quoted_command);
+-	comics_document->offset = command_usage_def[type].offset;
+-	if (command_usage_def[type].decompress_tmp) {
+-		comics_document->dir = ev_mkdtemp ("atril-comics-XXXXXX", error);
+-                if (comics_document->dir == NULL)
+-                        return FALSE;
+-
+-		/* unrar-free can't create directories, but ev_mkdtemp already created the dir */
+-
+-		comics_document->decompress_tmp =
+-			g_strdup_printf (command_usage_def[type].decompress_tmp,
+-					 quoted_command, quoted_file,
+-					 comics_document->dir);
+-		g_free (quoted_file);
+-		g_free (quoted_command);
+-
+-		if (!comics_decompress_temp_dir (comics_document->decompress_tmp,
+-		    comics_document->selected_command, error))
+-			return FALSE;
+-		else
+-			return TRUE;
+-	} else {
+-		g_free (quoted_file);
+-		g_free (quoted_command);
+-		return TRUE;
+-	}
++	guint i;
++	GHashTable *ht;
+ 
++	ht = g_hash_table_new (g_str_hash, g_str_equal);
++	for (i = 0; i < page_names->len; i++)
++		g_hash_table_insert (ht, page_names->pdata[i], GUINT_TO_POINTER(i + 1));
++	return ht;
+ }
+ 
+-/* This function chooses an external command for decompressing a comic
+- * book based on its mime tipe. */
++/*This function chooses the archive decompression support
++ * book based on its mime type. */
+ static gboolean
+-comics_check_decompress_command	(gchar          *mime_type,
++comics_check_decompress_support	(gchar          *mime_type,
+ 				 ComicsDocument *comics_document,
+ 				 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 (g_content_type_is_a (mime_type, "application/x-cbr") ||
+ 	    g_content_type_is_a (mime_type, "application/x-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
+-		* the Gna! project. Confusingly enough, the free software RAR
+-		* decoder is also named unrar. For this reason we need to add
+-		* some lines for disambiguation. Sorry for the added the
+-		* complexity but it's life :)
+-		* Finally, some distributions, like Debian, rename this free
+-		* option as unrar-free.
+-		* */
+-		comics_document->selected_command =
+-					g_find_program_in_path ("unrar");
+-		if (comics_document->selected_command) {
+-			/* We only use std_err to avoid printing useless error
+-			 * messages on the terminal */
+-			success =
+-				g_spawn_command_line_sync (
+-				              comics_document->selected_command,
+-							   &std_out, &std_err,
+-							   &retval, &err);
+-			if (!success) {
+-				g_propagate_error (error, err);
+-				g_error_free (err);
+-				return FALSE;
+-			/* I don't check retval status because RARLAB unrar
+-			 * doesn't have a way to return 0 without involving an
+-			 * operation with a file*/
+-			} else if (WIFEXITED (retval)) {
+-				if (g_strrstr (std_out,"freeware") != NULL)
+-					/* The RARLAB freeware client */
+-					comics_document->command_usage = RARLABS;
+-				else
+-					/* The Gna! free software client */
+-					comics_document->command_usage = GNAUNRAR;
+-
+-				g_free (std_out);
+-				g_free (std_err);
+-				return TRUE;
+-			}
+-		}
+-		/* The Gna! free software client with Debian naming convention */
+-		comics_document->selected_command =
+-				g_find_program_in_path ("unrar-free");
+-		if (comics_document->selected_command) {
+-			comics_document->command_usage = GNAUNRAR;
+-			return TRUE;
+-		}
+-		comics_document->selected_command =
+-				g_find_program_in_path ("lsar");
+-		if (comics_document->selected_command) {
+-			comics_document->command_usage = UNARCHIVER;
+-			return TRUE;
+-		}
+-		comics_document->selected_command =
+-				g_find_program_in_path ("bsdtar");
+-		if (comics_document->selected_command) {
+-			comics_document->command_usage = TAR;
++		if (ev_archive_set_archive_type (comics_document->archive, EV_ARCHIVE_TYPE_RAR))
+ 			return TRUE;
+-		}
+-
+ 	} else if (g_content_type_is_a (mime_type, "application/x-cbz") ||
+ 		   g_content_type_is_a (mime_type, "application/zip")) {
+-		/* InfoZIP's unzip program */
+-		comics_document->selected_command =
+-				g_find_program_in_path ("unzip");
+-		comics_document->alternative_command =
+-				g_find_program_in_path ("zipnote");
+-		if (comics_document->selected_command &&
+-		    comics_document->alternative_command) {
+-			comics_document->command_usage = UNZIP;
++		if (ev_archive_set_archive_type (comics_document->archive, EV_ARCHIVE_TYPE_ZIP))
+ 			return TRUE;
+-		}
+-		comics_document->selected_command =
+-				g_find_program_in_path ("bsdtar");
+-		if (comics_document->selected_command) {
+-			comics_document->command_usage = TAR;
+-			return TRUE;
+-		}
+-		comics_document->selected_command =
+-				g_find_program_in_path ("lsar");
+-		if (comics_document->selected_command) {
+-			comics_document->command_usage = UNARCHIVER;
+-			return TRUE;
+-		}
+-
+ 	} else if (g_content_type_is_a (mime_type, "application/x-cb7") ||
+ 		   g_content_type_is_a (mime_type, "application/x-7z-compressed")) {
+-		/* 7zr, 7za and 7z are the commands from the p7zip project able
+-		 * to decompress .7z files */
+-		comics_document->selected_command =
+-			g_find_program_in_path ("7zr");
+-		if (comics_document->selected_command) {
+-			comics_document->command_usage = P7ZIP;
++		if (ev_archive_set_archive_type (comics_document->archive, EV_ARCHIVE_TYPE_7Z))
+ 			return TRUE;
+-		}
+-		comics_document->selected_command =
+-			g_find_program_in_path ("7za");
+-		if (comics_document->selected_command) {
+-			comics_document->command_usage = P7ZIP;
+-			return TRUE;
+-		}
+-		comics_document->selected_command =
+-			g_find_program_in_path ("7z");
+-		if (comics_document->selected_command) {
+-			comics_document->command_usage = P7ZIP;
+-			return TRUE;
+-		}
+-		comics_document->selected_command =
+-				g_find_program_in_path ("bsdtar");
+-		if (comics_document->selected_command) {
+-			comics_document->command_usage = TAR;
+-			return TRUE;
+-		}
+-		comics_document->selected_command =
+-				g_find_program_in_path ("lsar");
+-		if (comics_document->selected_command) {
+-			comics_document->command_usage = UNARCHIVER;
+-			return TRUE;
+-		}
+ 	} else if (g_content_type_is_a (mime_type, "application/x-cbt") ||
+ 		   g_content_type_is_a (mime_type, "application/x-tar")) {
+-		/* tar utility (Tape ARchive) */
+-		comics_document->selected_command =
+-				g_find_program_in_path ("tar");
+-		if (comics_document->selected_command) {
+-			comics_document->command_usage = TAR;
++	if (ev_archive_set_archive_type (comics_document->archive, EV_ARCHIVE_TYPE_TAR))
+ 			return TRUE;
+-		}
+-		comics_document->selected_command =
+-				g_find_program_in_path ("bsdtar");
+-		if (comics_document->selected_command) {
+-			comics_document->command_usage = TAR;
+-			return TRUE;
+-		}
+-		comics_document->selected_command =
+-				g_find_program_in_path ("lsar");
+-		if (comics_document->selected_command) {
+-			comics_document->command_usage = UNARCHIVER;
+-			return TRUE;
+-		}
+ 	} else {
+ 		g_set_error (error,
+ 			     EV_DOCUMENT_ERROR,
+@@ -461,8 +325,9 @@ comics_check_decompress_command	(gchar          *mime_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"));
++		             _("libarchive lacks support for this comic book’s "
++			     "compression, please contact your distributor"));
++
+ 	return FALSE;
+ }
+ 
+@@ -470,43 +335,15 @@ static int
+ sort_page_names (gconstpointer a,
+                  gconstpointer b)
+ {
+-	const char *name_1, *name_2;
+-	gchar *key_1, *key_2;
+-	gboolean sort_last_1, sort_last_2;
+-	int compare;
+-
+-	name_1 = * (const char **) a;
+-	name_2 = * (const char **) b;
+-
+-	#define SORT_LAST_CHAR1 '.'
+-	#define SORT_LAST_CHAR2 '#'
+-
+-	sort_last_1 = name_1[0] == SORT_LAST_CHAR1 || name_1[0] == SORT_LAST_CHAR2;
+-	sort_last_2 = name_2[0] == SORT_LAST_CHAR1 || name_2[0] == SORT_LAST_CHAR2;
+-
+-	#undef SORT_LAST_CHAR1
+-	#undef SORT_LAST_CHAR2
+-
+-	if (sort_last_1 && !sort_last_2)
+-	{
+-		compare = +1;
+-	}
+-	else if (!sort_last_1 && sort_last_2)
+-	{
+-		compare = -1;
+-	}
+-	else
+-	{
+-		key_1 = g_utf8_collate_key_for_filename (name_1, -1);
+-		key_2 = g_utf8_collate_key_for_filename (name_2, -1);
+-
+-		compare = strcmp (key_1, key_2);
+-
+-		g_free (key_1);
+-		g_free (key_2);
+-	}
+-
+-	return compare;
++	gchar *temp1, *temp2;
++	gint ret;
++	temp1 = g_utf8_collate_key_for_filename (* (const char **) a, -1);
++	temp2 = g_utf8_collate_key_for_filename (* (const char **) b, -1);
++	ret = strcmp (temp1, temp2);
++
++	g_free (temp1);
++	g_free (temp2);
++	return ret;
+ }
+ 
+ static gboolean
+@@ -515,50 +352,13 @@ comics_document_load (EvDocument *document,
+ 		      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);
+-		return FALSE;
+-	} else if (!comics_generate_command_lines (comics_document, error)) {
+-		   g_free (mime_type);
+-		return FALSE;
+-	}
++	GFile *file;
++	file = g_file_new_for_uri (uri);
++	comics_document->archive_path = g_file_get_path (file);
++	g_object_unref (file);
+ 
+-	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);
+-
+-	if (!success) {
+-		return FALSE;
+-	} else if (!WIFEXITED(retval) || WEXITSTATUS(retval) != EXIT_SUCCESS) {
++	if (!comics_document->archive_path) {
+ 		g_set_error_literal (error,
+                                      EV_DOCUMENT_ERROR,
+                                      EV_DOCUMENT_ERROR_INVALID,
+@@ -566,58 +366,26 @@ comics_document_load (EvDocument *document,
+ 		return FALSE;
+ 	}
+ 
+-	/* FIXME: is this safe against filenames containing \n in the archive ? */
+-	cb_files = g_strsplit (std_out, EV_EOL, 0);
++	comics_document->archive_uri = g_strdup (uri);
++	mime_type = ev_file_get_mime_type (uri, FALSE, error);
+ 
+-	g_free (std_out);
++	if (mime_type == NULL)
++		return FALSE;
+ 
+-	if (!cb_files) {
+-		g_set_error_literal (error,
+-				     EV_DOCUMENT_ERROR,
+-				     EV_DOCUMENT_ERROR_INVALID,
+-				     _("No files in archive"));
++	if (!comics_check_decompress_support (mime_type, comics_document, error)) {
++		g_free (mime_type);
+ 		return FALSE;
+ 	}
+ 
+-        comics_document->page_names = g_ptr_array_sized_new (64);
+-
+-	supported_extensions = get_supported_image_extensions ();
+-	for (i = 0; cb_files[i] != NULL; i++) {
+-		if (comics_document->offset != NO_OFFSET) {
+-			if (g_utf8_strlen (cb_files[i],-1) >
+-			    comics_document->offset) {
+-				cb_file =
+-					g_utf8_offset_to_pointer (cb_files[i],
+-						       comics_document->offset);
+-			} else {
+-				continue;
+-			}
+-		} else {
+-			cb_file = cb_files[i];
+-		}
+-		gchar *suffix = g_strrstr (cb_file, ".");
+-		if (!suffix)
+-			continue;
+-		suffix = g_ascii_strdown (suffix + 1, -1);
+-		if (g_slist_find_custom (supported_extensions, suffix,
+-					 (GCompareFunc) strcmp) != NULL) {
+-                        g_ptr_array_add (comics_document->page_names,
+-                                         g_strstrip (g_strdup (cb_file)));
+-		}
+-		g_free (suffix);
+-	}
+-	g_strfreev (cb_files);
+-	g_slist_foreach (supported_extensions, (GFunc) g_free, NULL);
+-	g_slist_free (supported_extensions);
++	g_free (mime_type);
+ 
+-	if (comics_document->page_names->len == 0) {
+-		g_set_error (error,
+-			     EV_DOCUMENT_ERROR,
+-			     EV_DOCUMENT_ERROR_INVALID,
+-			     _("No images found in archive %s"),
+-			     uri);
++	/* Get list of files in archive */
++	comics_document->page_names = comics_document_list (comics_document, error);
++	if (!comics_document->page_names)
+ 		return FALSE;
+-	}
++
++	/* Keep an index */
++	comics_document->page_positions = save_positions (comics_document->page_names);
+ 
+         /* Now sort the pages */
+         g_ptr_array_sort (comics_document->page_names, sort_page_names);
+@@ -632,7 +400,7 @@ comics_document_save (EvDocument *document,
+ {
+ 	ComicsDocument *comics_document = COMICS_DOCUMENT (document);
+ 
+-	return ev_xfer_uri_simple (comics_document->archive, uri, error);
++	return ev_xfer_uri_simple (comics_document->archive_uri, uri, error);
+ }
+ 
+ static int
+@@ -646,6 +414,23 @@ comics_document_get_n_pages (EvDocument *document)
+ 	return comics_document->page_names->len;
+ }
+ 
++typedef struct {
++	gboolean got_info;
++	int height;
++	int width;
++} PixbufInfo;
++
++static void
++get_page_size_prepared_cb (GdkPixbufLoader *loader,
++			   int              width,
++			   int              height,
++			   PixbufInfo      *info)
++{
++	info->got_info = TRUE;
++	info->height = height;
++	info->width = width;
++}
++
+ static void
+ comics_document_get_page_size (EvDocument *document,
+ 			       EvPage     *page,
+@@ -653,74 +438,89 @@ comics_document_get_page_size (EvDocument *document,
+ 			       double     *height)
+ {
+ 	GdkPixbufLoader *loader;
+-	char **argv;
+-	guchar buf[1024];
+-	gboolean success, got_size = FALSE;
+-	gint outpipe = -1;
+-	GPid child_pid;
+-	gssize bytes;
+-	GdkPixbuf *pixbuf;
+-	gchar *filename;
++
+ 	ComicsDocument *comics_document = COMICS_DOCUMENT (document);
+ 
+-	if (!comics_document->decompress_tmp) {
+-		argv = extract_argv (document, page->index);
+-		success = g_spawn_async_with_pipes (NULL, argv, NULL,
+-						    G_SPAWN_SEARCH_PATH |
+-						    G_SPAWN_STDERR_TO_DEV_NULL,
+-						    NULL, NULL,
+-						    &child_pid,
+-						    NULL, &outpipe, NULL, NULL);
+-		g_strfreev (argv);
+-		g_return_if_fail (success == TRUE);
+-
+-		loader = gdk_pixbuf_loader_new ();
+-		g_signal_connect (loader, "area-prepared",
+-				  G_CALLBACK (get_page_size_area_prepared_cb),
+-				  &got_size);
+-
+-		while (outpipe >= 0) {
+-			bytes = read (outpipe, buf, 1024);
+-
+-			if (bytes > 0)
+-			gdk_pixbuf_loader_write (loader, buf, bytes, NULL);
+-			if (bytes <= 0 || got_size) {
+-				close (outpipe);
+-				outpipe = -1;
+-				gdk_pixbuf_loader_close (loader, NULL);
++	const char *page_path;
++	PixbufInfo info;
++	GError *error = NULL;
++
++	page_path = g_ptr_array_index (comics_document->page_names, page->index);
++
++	if (!archive_reopen_if_needed (comics_document, page_path, &error)) {
++		g_warning ("Fatal error opening archive: %s", error->message);
++		g_error_free (error);
++		return;
++	}
++
++	loader = gdk_pixbuf_loader_new ();
++	info.got_info = FALSE;
++	g_signal_connect (loader, "size-prepared",
++			  G_CALLBACK (get_page_size_prepared_cb),
++			  &info);
++
++	while (1) {
++		const char *name;
++		GError *error = NULL;
++
++		if (!ev_archive_read_next_header (comics_document->archive, &error)) {
++			if (error != NULL) {
++				g_warning ("Fatal error handling archive (%s): %s", G_STRFUNC, error->message);
++				g_error_free (error);
+ 			}
++			break;
+ 		}
+-		pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
+-		if (pixbuf) {
+-			if (width)
+-				*width = gdk_pixbuf_get_width (pixbuf);
+-			if (height)
+-				*height = gdk_pixbuf_get_height (pixbuf);
+-		}
+-		g_spawn_close_pid (child_pid);
+-		g_object_unref (loader);
+-	} else {
+-		filename = g_build_filename (comics_document->dir,
+-                                             (char *) comics_document->page_names->pdata[page->index],
+-					     NULL);
+-		pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
+-		if (pixbuf) {
+-			if (width)
+-				*width = gdk_pixbuf_get_width (pixbuf);
+-			if (height)
+-				*height = gdk_pixbuf_get_height (pixbuf);
+-			g_object_unref (pixbuf);
++
++		name = ev_archive_get_entry_pathname (comics_document->archive);
++		if (g_strcmp0 (name, page_path) == 0) {
++			char buf[BLOCK_SIZE];
++			gssize read;
++			gint64 left;
++
++			left = ev_archive_get_entry_size (comics_document->archive);
++			read = ev_archive_read_data (comics_document->archive, buf,
++						     MIN(BLOCK_SIZE, left), &error);
++			while (read > 0 && !info.got_info) {
++				if (!gdk_pixbuf_loader_write (loader, (guchar *) buf, read, &error)) {
++					read = -1;
++					break;
++				}
++				left -= read;
++				read = ev_archive_read_data (comics_document->archive, buf,
++							     MIN(BLOCK_SIZE, left), &error);
++			}
++			if (read < 0) {
++				g_warning ("Fatal error reading '%s' in archive: %s", name, error->message);
++				g_error_free (error);
++			}
++			break;
+ 		}
+-		g_free (filename);
++	}
++
++	gdk_pixbuf_loader_close (loader, NULL);
++	g_object_unref (loader);
++
++	if (info.got_info) {
++		if (width)
++			*width = info.width;
++		if (height)
++			*height = info.height;
+ 	}
+ }
+ 
+ static void
+-get_page_size_area_prepared_cb (GdkPixbufLoader *loader,
+-				gpointer         data)
++render_pixbuf_size_prepared_cb (GdkPixbufLoader *loader,
++				gint             width,
++				gint             height,
++				EvRenderContext *rc)
+ {
+-	gboolean *got_size = data;
+-	*got_size = TRUE;
++	// int scaled_width, scaled_height;
++	double scale = rc->scale;
++	int w = (width  * scale + 0.5);
++	int h = (height * scale + 0.5);
++
++	// ev_render_context_compute_scaled_size (rc, width, height, &scaled_width, &scaled_height);
++	gdk_pixbuf_loader_set_size (loader, w, h);
+ }
+ 
+ static GdkPixbuf *
+@@ -728,69 +528,68 @@ comics_document_render_pixbuf (EvDocument      *document,
+ 			       EvRenderContext *rc)
+ {
+ 	GdkPixbufLoader *loader;
+-	GdkPixbuf *rotated_pixbuf, *tmp_pixbuf;
+-	char **argv;
+-	guchar buf[4096];
+-	gboolean success;
+-	gint outpipe = -1;
+-	GPid child_pid;
+-	gssize bytes;
+-	gint width, height;
+-	gchar *filename;
++	GdkPixbuf *tmp_pixbuf;
++	GdkPixbuf *rotated_pixbuf = NULL;
+ 	ComicsDocument *comics_document = COMICS_DOCUMENT (document);
++	const char *page_path;
++	GError *error = NULL;
++
++	page_path = g_ptr_array_index (comics_document->page_names, rc->page->index);
++
++	if (!archive_reopen_if_needed (comics_document, page_path, &error)) {
++		g_warning ("Fatal error opening archive: %s", error->message);
++		g_error_free (error);
++		return NULL;
++	}
+ 
+-	if (!comics_document->decompress_tmp) {
+-		argv = extract_argv (document, rc->page->index);
+-		success = g_spawn_async_with_pipes (NULL, argv, NULL,
+-						    G_SPAWN_SEARCH_PATH |
+-						    G_SPAWN_STDERR_TO_DEV_NULL,
+-						    NULL, NULL,
+-						    &child_pid,
+-						    NULL, &outpipe, NULL, NULL);
+-		g_strfreev (argv);
+-		g_return_val_if_fail (success == TRUE, NULL);
+-
+-		loader = gdk_pixbuf_loader_new ();
+-		g_signal_connect (loader, "size-prepared",
+-				  G_CALLBACK (render_pixbuf_size_prepared_cb),
+-				  &rc->scale);
+-
+-		while (outpipe >= 0) {
+-			bytes = read (outpipe, buf, 4096);
+-
+-			if (bytes > 0) {
+-				gdk_pixbuf_loader_write (loader, buf, bytes,
+-				NULL);
++	loader = gdk_pixbuf_loader_new ();
++	g_signal_connect (loader, "size-prepared",
++			  G_CALLBACK (render_pixbuf_size_prepared_cb),
++			  rc);
++
++	while (1) {
++		const char *name;
++
++		if (!ev_archive_read_next_header (comics_document->archive, &error)) {
++			if (error != NULL) {
++				g_warning ("Fatal error handling archive (%s): %s", G_STRFUNC, error->message);
++				g_error_free (error);
++			}
++			break;
++		}
++
++		name = ev_archive_get_entry_pathname (comics_document->archive);
++		if (g_strcmp0 (name, page_path) == 0) {
++			size_t size = ev_archive_get_entry_size (comics_document->archive);
++			char *buf;
++			ssize_t read;
++
++			buf = g_malloc (size);
++			read = ev_archive_read_data (comics_document->archive, buf, size, &error);
++			if (read <= 0) {
++				if (read < 0) {
++					g_warning ("Fatal error reading '%s' in archive: %s", name, error->message);
++					g_error_free (error);
++				} else {
++					g_warning ("Read an empty file from the archive");
++				}
+ 			} else {
+-				close (outpipe);
+-				gdk_pixbuf_loader_close (loader, NULL);
+-				outpipe = -1;
++				gdk_pixbuf_loader_write (loader, (guchar *) buf, size, NULL);
+ 			}
++			g_free (buf);
++			gdk_pixbuf_loader_close (loader, NULL);
++			break;
+ 		}
+-		tmp_pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
+-		rotated_pixbuf =
+-			gdk_pixbuf_rotate_simple (tmp_pixbuf,
+-						  360 - rc->rotation);
+-		g_spawn_close_pid (child_pid);
+-		g_object_unref (loader);
+-	} else {
+-		filename =
+-			g_build_filename (comics_document->dir,
+-                                          (char *) comics_document->page_names->pdata[rc->page->index],
+-					  NULL);
+-
+-		gdk_pixbuf_get_file_info (filename, &width, &height);
+-
+-		tmp_pixbuf =
+-			gdk_pixbuf_new_from_file_at_size (
+-				    filename, width * (rc->scale) + 0.5,
+-				    height * (rc->scale) + 0.5, NULL);
+-		rotated_pixbuf =
+-			gdk_pixbuf_rotate_simple (tmp_pixbuf,
+-						  360 - rc->rotation);
+-		g_free (filename);
+-		g_object_unref (tmp_pixbuf);
+ 	}
++	tmp_pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
++	if (tmp_pixbuf) {
++		if ((rc->rotation % 360) == 0)
++			rotated_pixbuf = g_object_ref (tmp_pixbuf);
++		else
++			rotated_pixbuf = gdk_pixbuf_rotate_simple (tmp_pixbuf,
++								   360 - rc->rotation);
++	}
++	g_object_unref (loader);
+ 	return rotated_pixbuf;
+ }
+ 
+@@ -802,79 +601,26 @@ comics_document_render (EvDocument      *document,
+ 	cairo_surface_t *surface;
+ 
+ 	pixbuf = comics_document_render_pixbuf (document, rc);
++	if (!pixbuf)
++		return NULL;
+ 	surface = ev_document_misc_surface_from_pixbuf (pixbuf);
+-	g_object_unref (pixbuf);
+-
++	g_clear_object (&pixbuf);
+ 	return surface;
+ }
+ 
+-static void
+-render_pixbuf_size_prepared_cb (GdkPixbufLoader *loader,
+-				gint             width,
+-				gint             height,
+-				gpointer         data)
+-{
+-	double *scale = data;
+-	int w = (width  * (*scale) + 0.5);
+-	int h = (height * (*scale) + 0.5);
+-
+-	gdk_pixbuf_loader_set_size (loader, w, h);
+-}
+-
+-/**
+- * comics_remove_dir: Removes a directory recursively.
+- * Returns:
+- *   	0 if it was successfully deleted,
+- * 	-1 if an error occurred
+- */
+-static int
+-comics_remove_dir (gchar *path_name)
+-{
+-	GDir  *content_dir;
+-	const gchar *filename;
+-	gchar *filename_with_path;
+-
+-	if (g_file_test (path_name, G_FILE_TEST_IS_DIR)) {
+-		content_dir = g_dir_open  (path_name, 0, NULL);
+-		filename  = g_dir_read_name (content_dir);
+-		while (filename) {
+-			filename_with_path =
+-				g_build_filename (path_name,
+-						  filename, NULL);
+-			comics_remove_dir (filename_with_path);
+-			g_free (filename_with_path);
+-			filename = g_dir_read_name (content_dir);
+-		}
+-		g_dir_close (content_dir);
+-	}
+-	/* Note from g_remove() documentation: on Windows, it is in general not
+-	 * possible to remove a file that is open to some process, or mapped
+-	 * into memory.*/
+-	return (g_remove (path_name));
+-}
+-
+ static void
+ comics_document_finalize (GObject *object)
+ {
+ 	ComicsDocument *comics_document = COMICS_DOCUMENT (object);
+ 
+-	if (comics_document->decompress_tmp) {
+-		if (comics_remove_dir (comics_document->dir) == -1)
+-			g_warning (_("There was an error deleting “%s”."),
+-				   comics_document->dir);
+-		g_free (comics_document->dir);
+-	}
+-
+ 	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);
+ 	}
+-
+-	g_free (comics_document->archive);
+-	g_free (comics_document->selected_command);
+-	g_free (comics_document->alternative_command);
+-	g_free (comics_document->extract_command);
+-	g_free (comics_document->list_command);
++	g_clear_pointer (&comics_document->page_positions, g_hash_table_destroy);
++	g_clear_object (&comics_document->archive);
++	g_free (comics_document->archive_path);
++	g_free (comics_document->archive_uri);
+ 
+ 	G_OBJECT_CLASS (comics_document_parent_class)->finalize (object);
+ }
+@@ -897,33 +643,7 @@ comics_document_class_init (ComicsDocumentClass *klass)
+ static void
+ comics_document_init (ComicsDocument *comics_document)
+ {
+-	comics_document->archive = NULL;
+-	comics_document->page_names = NULL;
+-	comics_document->extract_command = NULL;
+-}
+-
+-/* Returns a list of file extensions supported by gdk-pixbuf */
+-static GSList*
+-get_supported_image_extensions(void)
+-{
+-	GSList *extensions = NULL;
+-	GSList *formats = gdk_pixbuf_get_formats ();
+-	GSList *l;
+-
+-	for (l = formats; l != NULL; l = l->next) {
+-		int i;
+-		gchar **ext = gdk_pixbuf_format_get_extensions (l->data);
+-
+-		for (i = 0; ext[i] != NULL; i++) {
+-			extensions = g_slist_append (extensions,
+-						     g_strdup (ext[i]));
+-		}
+-
+-		g_strfreev (ext);
+-	}
+-
+-	g_slist_free (formats);
+-	return extensions;
++	comics_document->archive = ev_archive_new ();
+ }
+ 
+ static GdkPixbuf *
+@@ -971,48 +691,3 @@ comics_document_document_thumbnails_iface_init (EvDocumentThumbnailsInterface *i
+ 	iface->get_thumbnail = comics_document_thumbnails_get_thumbnail;
+ 	iface->get_dimensions = comics_document_thumbnails_get_dimensions;
+ }
+-
+-static char**
+-extract_argv (EvDocument *document, gint page)
+-{
+-	ComicsDocument *comics_document = COMICS_DOCUMENT (document);
+-	char **argv;
+-	char *command_line, *quoted_archive, *quoted_filename;
+-	GError *err = NULL;
+-
+-	if (g_strrstr (comics_document->page_names->pdata[page], "--checkpoint-action="))
+-	{
+-		g_warning ("File unsupported\n");
+-		gtk_main_quit ();
+-	}
+-
+-        if (page >= comics_document->page_names->len)
+-                return NULL;
+-
+-	if (comics_document->regex_arg) {
+-		quoted_archive = g_shell_quote (comics_document->archive);
+-		quoted_filename =
+-			comics_regex_quote (comics_document->page_names->pdata[page]);
+-	} else {
+-		quoted_archive = g_shell_quote (comics_document->archive);
+-		quoted_filename = g_shell_quote (comics_document->page_names->pdata[page]);
+-	}
+-
+-	command_line = g_strdup_printf ("%s %s %s",
+-					comics_document->extract_command,
+-					quoted_archive,
+-					quoted_filename);
+-	g_free (quoted_archive);
+-	g_free (quoted_filename);
+-
+-	g_shell_parse_argv (command_line, NULL, &argv, &err);
+-	g_free (command_line);
+-
+-	if (err) {
+-		g_warning (_("Error %s"), err->message);
+-		g_error_free (err);
+-		return NULL;
+-	}
+-
+-	return argv;
+-}
+diff --git a/backend/comics/comics-document.h b/backend/comics/comics-document.h
+index f6a4b440..4417a69f 100644
+--- a/backend/comics/comics-document.h
++++ b/backend/comics/comics-document.h
+@@ -16,9 +16,9 @@
+  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+  */
+ 
+-#ifndef __COMICS_DOCUMENT_H__
+-#define __COMICS_DOCUMENT_H__
++#pragma once
+ 
++#include "ev-macros.h"
+ #include "ev-document.h"
+ 
+ G_BEGIN_DECLS
+@@ -30,9 +30,8 @@ G_BEGIN_DECLS
+ typedef struct _ComicsDocument ComicsDocument;
+ 
+ GType                 comics_document_get_type (void) G_GNUC_CONST;
++GType                 register_atril_backend  (GTypeModule *module);
+ 
+-G_MODULE_EXPORT GType register_atril_backend  (GTypeModule *module);
+ 
+ G_END_DECLS
+ 
+-#endif /* __COMICS_DOCUMENT_H__ */
+diff --git a/backend/comics/ev-archive.c b/backend/comics/ev-archive.c
+new file mode 100644
+index 00000000..568e1621
+--- /dev/null
++++ b/backend/comics/ev-archive.c
+@@ -0,0 +1,323 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
++/*
++ * Copyright (C) 2017, Bastien Nocera <hadess@hadess.net>
++ *
++ * 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, 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 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 "config.h"
++#include "ev-archive.h"
++
++#include <archive.h>
++#include <archive_entry.h>
++#include <gio/gio.h>
++
++#define BUFFER_SIZE (64 * 1024)
++
++struct _EvArchive {
++	GObject parent_instance;
++	EvArchiveType type;
++
++	/* libarchive */
++	struct archive *libar;
++	struct archive_entry *libar_entry;
++};
++
++G_DEFINE_TYPE(EvArchive, ev_archive, G_TYPE_OBJECT);
++
++static void
++ev_archive_finalize (GObject *object)
++{
++	EvArchive *archive = EV_ARCHIVE (object);
++
++	switch (archive->type) {
++	case EV_ARCHIVE_TYPE_RAR:
++	case EV_ARCHIVE_TYPE_ZIP:
++	case EV_ARCHIVE_TYPE_7Z:
++	case EV_ARCHIVE_TYPE_TAR:
++		g_clear_pointer (&archive->libar, archive_free);
++		break;
++	default:
++		break;
++	}
++
++	G_OBJECT_CLASS (ev_archive_parent_class)->finalize (object);
++}
++
++static void
++ev_archive_class_init (EvArchiveClass *klass)
++{
++        GObjectClass *object_class = (GObjectClass *) klass;
++
++        object_class->finalize = ev_archive_finalize;
++}
++
++EvArchive *
++ev_archive_new (void)
++{
++	return g_object_new (EV_TYPE_ARCHIVE, NULL);
++}
++
++static void
++libarchive_set_archive_type (EvArchive *archive,
++			     EvArchiveType archive_type)
++{
++	archive->type = archive_type;
++	archive->libar = archive_read_new ();
++
++	if (archive_type == EV_ARCHIVE_TYPE_ZIP)
++		archive_read_support_format_zip (archive->libar);
++	else if (archive_type == EV_ARCHIVE_TYPE_7Z)
++		archive_read_support_format_7zip (archive->libar);
++	else if (archive_type == EV_ARCHIVE_TYPE_TAR)
++		archive_read_support_format_tar (archive->libar);
++	else if (archive_type == EV_ARCHIVE_TYPE_RAR) {
++		archive_read_support_format_rar (archive->libar);
++		archive_read_support_format_rar5 (archive->libar);
++	} else
++		g_assert_not_reached ();
++}
++
++EvArchiveType
++ev_archive_get_archive_type (EvArchive *archive)
++{
++	g_return_val_if_fail (EV_IS_ARCHIVE (archive), EV_ARCHIVE_TYPE_NONE);
++
++	return archive->type;
++}
++
++gboolean
++ev_archive_set_archive_type (EvArchive *archive,
++			     EvArchiveType archive_type)
++{
++	g_return_val_if_fail (EV_IS_ARCHIVE (archive), FALSE);
++	g_return_val_if_fail (archive->type == EV_ARCHIVE_TYPE_NONE, FALSE);
++
++	switch (archive_type) {
++	case EV_ARCHIVE_TYPE_RAR:
++	case EV_ARCHIVE_TYPE_ZIP:
++	case EV_ARCHIVE_TYPE_7Z:
++	case EV_ARCHIVE_TYPE_TAR:
++		libarchive_set_archive_type (archive, archive_type);
++		break;
++	default:
++		g_assert_not_reached ();
++	}
++
++	return TRUE;
++}
++
++gboolean
++ev_archive_open_filename (EvArchive   *archive,
++			  const char  *path,
++			  GError     **error)
++{
++	int r;
++
++	g_return_val_if_fail (EV_IS_ARCHIVE (archive), FALSE);
++	g_return_val_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE, FALSE);
++	g_return_val_if_fail (path != NULL, FALSE);
++
++	switch (archive->type) {
++	case EV_ARCHIVE_TYPE_NONE:
++		g_assert_not_reached ();
++	case EV_ARCHIVE_TYPE_RAR:
++	case EV_ARCHIVE_TYPE_ZIP:
++	case EV_ARCHIVE_TYPE_7Z:
++	case EV_ARCHIVE_TYPE_TAR:
++		r = archive_read_open_filename (archive->libar, path, BUFFER_SIZE);
++		if (r != ARCHIVE_OK) {
++			g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
++				     "Error opening archive: %s", archive_error_string (archive->libar));
++			return FALSE;
++		}
++		return TRUE;
++	}
++
++	return FALSE;
++}
++
++static gboolean
++libarchive_read_next_header (EvArchive *archive,
++			     GError   **error)
++{
++	while (1) {
++		int r;
++
++		r = archive_read_next_header (archive->libar, &archive->libar_entry);
++		if (r != ARCHIVE_OK) {
++			if (r != ARCHIVE_EOF)
++				g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
++					     "Error reading archive: %s", archive_error_string (archive->libar));
++			return FALSE;
++		}
++
++		if (archive_entry_filetype (archive->libar_entry) != AE_IFREG) {
++			g_debug ("Skipping '%s' as it's not a regular file",
++				 archive_entry_pathname (archive->libar_entry));
++			continue;
++		}
++
++		g_debug ("At header for file '%s'", archive_entry_pathname (archive->libar_entry));
++
++		break;
++	}
++
++	return TRUE;
++}
++
++gboolean
++ev_archive_read_next_header (EvArchive *archive,
++			     GError   **error)
++{
++	g_return_val_if_fail (EV_IS_ARCHIVE (archive), FALSE);
++	g_return_val_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE, FALSE);
++
++	switch (archive->type) {
++	case EV_ARCHIVE_TYPE_NONE:
++		g_assert_not_reached ();
++	case EV_ARCHIVE_TYPE_RAR:
++	case EV_ARCHIVE_TYPE_ZIP:
++	case EV_ARCHIVE_TYPE_7Z:
++	case EV_ARCHIVE_TYPE_TAR:
++		return libarchive_read_next_header (archive, error);
++	}
++
++	return FALSE;
++}
++
++gboolean
++ev_archive_at_entry (EvArchive *archive)
++{
++	g_return_val_if_fail (EV_IS_ARCHIVE (archive), FALSE);
++	g_return_val_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE, FALSE);
++
++	return (archive->libar_entry != NULL);
++}
++
++const char *
++ev_archive_get_entry_pathname (EvArchive *archive)
++{
++	g_return_val_if_fail (EV_IS_ARCHIVE (archive), NULL);
++	g_return_val_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE, NULL);
++
++	switch (archive->type) {
++	case EV_ARCHIVE_TYPE_NONE:
++		g_assert_not_reached ();
++	case EV_ARCHIVE_TYPE_RAR:
++	case EV_ARCHIVE_TYPE_ZIP:
++	case EV_ARCHIVE_TYPE_7Z:
++	case EV_ARCHIVE_TYPE_TAR:
++		g_return_val_if_fail (archive->libar_entry != NULL, NULL);
++		return archive_entry_pathname (archive->libar_entry);
++	}
++
++	return NULL;
++}
++
++gint64
++ev_archive_get_entry_size (EvArchive *archive)
++{
++	g_return_val_if_fail (EV_IS_ARCHIVE (archive), -1);
++	g_return_val_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE, -1);
++
++	switch (archive->type) {
++	case EV_ARCHIVE_TYPE_NONE:
++		g_assert_not_reached ();
++	case EV_ARCHIVE_TYPE_RAR:
++	case EV_ARCHIVE_TYPE_ZIP:
++	case EV_ARCHIVE_TYPE_7Z:
++	case EV_ARCHIVE_TYPE_TAR:
++		g_return_val_if_fail (archive->libar_entry != NULL, -1);
++		return archive_entry_size (archive->libar_entry);
++	}
++
++	return -1;
++}
++
++gboolean
++ev_archive_get_entry_is_encrypted (EvArchive *archive)
++{
++	g_return_val_if_fail (EV_IS_ARCHIVE (archive), FALSE);
++	g_return_val_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE, FALSE);
++
++	switch (archive->type) {
++	case EV_ARCHIVE_TYPE_NONE:
++		g_assert_not_reached ();
++	case EV_ARCHIVE_TYPE_RAR:
++	case EV_ARCHIVE_TYPE_ZIP:
++	case EV_ARCHIVE_TYPE_7Z:
++	case EV_ARCHIVE_TYPE_TAR:
++		g_return_val_if_fail (archive->libar_entry != NULL, -1);
++		return archive_entry_is_encrypted (archive->libar_entry);
++	}
++
++	return FALSE;
++}
++
++gssize
++ev_archive_read_data (EvArchive *archive,
++		      void      *buf,
++		      gsize      count,
++		      GError   **error)
++{
++	gssize r = -1;
++
++	g_return_val_if_fail (EV_IS_ARCHIVE (archive), -1);
++	g_return_val_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE, -1);
++
++	switch (archive->type) {
++	case EV_ARCHIVE_TYPE_NONE:
++		g_assert_not_reached ();
++	case EV_ARCHIVE_TYPE_RAR:
++	case EV_ARCHIVE_TYPE_ZIP:
++	case EV_ARCHIVE_TYPE_7Z:
++	case EV_ARCHIVE_TYPE_TAR:
++		g_return_val_if_fail (archive->libar_entry != NULL, -1);
++		r = archive_read_data (archive->libar, buf, count);
++		if (r < 0) {
++			g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
++				     "Failed to decompress data: %s", archive_error_string (archive->libar));
++		}
++		break;
++	}
++
++	return r;
++}
++
++void
++ev_archive_reset (EvArchive *archive)
++{
++	g_return_if_fail (EV_IS_ARCHIVE (archive));
++	g_return_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE);
++
++	switch (archive->type) {
++	case EV_ARCHIVE_TYPE_RAR:
++	case EV_ARCHIVE_TYPE_ZIP:
++	case EV_ARCHIVE_TYPE_7Z:
++	case EV_ARCHIVE_TYPE_TAR:
++		g_clear_pointer (&archive->libar, archive_free);
++		libarchive_set_archive_type (archive, archive->type);
++		archive->libar_entry = NULL;
++		break;
++	default:
++		g_assert_not_reached ();
++	}
++}
++
++static void
++ev_archive_init (EvArchive *archive)
++{
++}
+diff --git a/backend/comics/ev-archive.h b/backend/comics/ev-archive.h
+new file mode 100644
+index 00000000..b4e1399c
+--- /dev/null
++++ b/backend/comics/ev-archive.h
+@@ -0,0 +1,56 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
++/*
++ * Copyright (C) 2017, Bastien Nocera <hadess@hadess.net>
++ *
++ * 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, 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 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.
++ */
++
++#pragma once
++
++#include <glib-object.h>
++
++G_BEGIN_DECLS
++
++#define EV_TYPE_ARCHIVE ev_archive_get_type ()
++G_DECLARE_FINAL_TYPE (EvArchive, ev_archive, EV, ARCHIVE, GObject)
++
++typedef enum {
++	EV_ARCHIVE_TYPE_NONE = 0,
++	EV_ARCHIVE_TYPE_RAR,
++	EV_ARCHIVE_TYPE_ZIP,
++	EV_ARCHIVE_TYPE_7Z,
++	EV_ARCHIVE_TYPE_TAR
++} EvArchiveType;
++
++EvArchive     *ev_archive_new                (void);
++gboolean       ev_archive_set_archive_type   (EvArchive     *archive,
++					      EvArchiveType  archive_type);
++EvArchiveType  ev_archive_get_archive_type   (EvArchive     *archive);
++gboolean       ev_archive_open_filename      (EvArchive     *archive,
++					      const char    *path,
++					      GError       **error);
++gboolean       ev_archive_read_next_header   (EvArchive     *archive,
++					      GError       **error);
++gboolean       ev_archive_at_entry           (EvArchive     *archive);
++const char    *ev_archive_get_entry_pathname (EvArchive     *archive);
++gint64         ev_archive_get_entry_size     (EvArchive     *archive);
++gboolean       ev_archive_get_entry_is_encrypted (EvArchive *archive);
++gssize         ev_archive_read_data          (EvArchive     *archive,
++					      void          *buf,
++					      gsize          count,
++					      GError       **error);
++void           ev_archive_reset              (EvArchive     *archive);
++
++G_END_DECLS
+diff --git a/configure.ac b/configure.ac
+index e25de054..d5830716 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -580,8 +580,11 @@ AC_ARG_ENABLE(comics,
+     [enable_comics=$enableval],
+     [enable_comics=yes])
+ 
++COMICS_DEPS="libarchive"
+ if test "x$enable_comics" = "xyes"; then
+     AC_DEFINE([ENABLE_COMICS], [1], [Enable support for comics.])
++    PKG_CHECK_MODULES([COMICS], [$COMICS_DEPS])
++    AC_SUBST(COMICS_LIBS)
+ fi
+ AM_CONDITIONAL(ENABLE_COMICS, test x$enable_comics = xyes)
+ 
+diff --git a/libdocument/ev-document.h b/libdocument/ev-document.h
+index 67f53abb..8f54e6b5 100644
+--- a/libdocument/ev-document.h
++++ b/libdocument/ev-document.h
+@@ -59,6 +59,7 @@ typedef struct _EvDocumentPrivate EvDocumentPrivate;
+ typedef enum
+ {
+         EV_DOCUMENT_ERROR_INVALID,
++        EV_DOCUMENT_ERROR_UNSUPPORTED_CONTENT,
+         EV_DOCUMENT_ERROR_ENCRYPTED
+ } EvDocumentError;
+ 
+-- 
+2.39.2
+
diff -Nru atril-1.26.0/debian/patches/series atril-1.26.0/debian/patches/series
--- atril-1.26.0/debian/patches/series	2024-01-06 07:18:28.000000000 +0100
+++ atril-1.26.0/debian/patches/series	2024-01-23 10:06:53.000000000 +0100
@@ -3,3 +3,5 @@
 0001-Accessibility-add-button-description.patch
 0003-epub-Fix-index-loading-for-certain-documents-look-fo.patch
 0004-epub-add-fallback-for-malformed-epub-files-in-check_.patch
+0005-Use-a-blank-line-at-most.patch
+0006-comics-Use-libarchive-to-unpack-documents.patch

--- End Message ---
--- Begin Message ---
Version: 12.5

The upload requested in this bug has been released as part of 12.5.

--- End Message ---

Reply to: