1844 lines
54 KiB
Diff
1844 lines
54 KiB
Diff
From 71c3efaf1e42e6ba87f5385c5524ad403dd864d2 Mon Sep 17 00:00:00 2001
|
||
From: peijiankang <peijiankang@kylinos.cn>
|
||
Date: Wed, 24 Apr 2024 11:34:50 +0800
|
||
Subject: [PATCH] CVE-2023-51698
|
||
|
||
---
|
||
backend/comics/Makefile.am | 5 +-
|
||
backend/comics/comics-document.c | 1158 +++++++++++-------------------
|
||
backend/comics/comics-document.h | 9 +-
|
||
backend/comics/ev-archive.c | 323 +++++++++
|
||
backend/comics/ev-archive.h | 56 ++
|
||
configure.ac | 3 +
|
||
libdocument/ev-document.h | 1 +
|
||
7 files changed, 806 insertions(+), 749 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 99ef5f4..519cb49 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.in
|
||
diff --git a/backend/comics/comics-document.c b/backend/comics/comics-document.c
|
||
index 4d4d293..1da1eee 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,400 +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);
|
||
|
||
-static const ComicBookDecompressCommand command_usage_def[] = {
|
||
- /* RARLABS unrar */
|
||
- {"%s p -c- -ierr --", "%s vb -c- -- %s", NULL , FALSE, NO_OFFSET},
|
||
+ for (i = 0; ext[i] != NULL; i++) {
|
||
+ g_hash_table_insert (extensions,
|
||
+ g_strdup (ext[i]),
|
||
+ GINT_TO_POINTER (FORMAT_SUPPORTED));
|
||
+ }
|
||
|
||
- /* GNA! unrar */
|
||
- {NULL , "%s t %s" , "%s -xf %s %s" , FALSE, NO_OFFSET},
|
||
+ g_strfreev (ext);
|
||
+ }
|
||
+ g_slist_free (formats);
|
||
|
||
- /* unzip */
|
||
- {"%s -p -C --" , "%s %s" , NULL , TRUE , OFFSET_ZIP},
|
||
+ /* 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));
|
||
+ }
|
||
+ }
|
||
|
||
- /* 7zip */
|
||
- {NULL , "%s l -- %s" , "%s x -y %s -o%s", FALSE, OFFSET_7Z},
|
||
+ return extensions;
|
||
+}
|
||
|
||
- /* tar */
|
||
- {"%s -xOf" , "%s -tf %s" , NULL , FALSE, NO_OFFSET},
|
||
+static int
|
||
+has_supported_extension (const char *name,
|
||
+ GHashTable *supported_extensions)
|
||
+{
|
||
+ gboolean ret = FALSE;
|
||
+ gchar *suffix;
|
||
+ suffix = g_strrstr (name, ".");
|
||
+ if (!suffix)
|
||
+ return ret;
|
||
|
||
- /* UNARCHIVER */
|
||
- {"unar -o -" , "%s %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);
|
||
|
||
-static void comics_document_document_thumbnails_iface_init (EvDocumentThumbnailsInterface *iface);
|
||
+ return ret;
|
||
+}
|
||
|
||
-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);
|
||
+#define APPLE_DOUBLE_PREFIX "._"
|
||
+static gboolean
|
||
+is_apple_double (const char *name)
|
||
+{
|
||
+char *basename;
|
||
+ gboolean ret = FALSE;
|
||
|
||
+ 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. */
|
||
-static gboolean
|
||
-comics_check_decompress_command (gchar *mime_type,
|
||
+/*This function chooses the archive decompression support
|
||
+ * book based on its mime type. */
|
||
+static gboolean
|
||
+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;
|
||
+ if (ev_archive_set_archive_type (comics_document->archive, EV_ARCHIVE_TYPE_RAR))
|
||
return TRUE;
|
||
- }
|
||
- comics_document->selected_command =
|
||
- g_find_program_in_path ("bsdtar");
|
||
- if (comics_document->selected_command) {
|
||
- comics_document->command_usage = TAR;
|
||
- 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;
|
||
- return TRUE;
|
||
- }
|
||
- comics_document->selected_command =
|
||
- g_find_program_in_path ("7za");
|
||
- 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 ("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;
|
||
- 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_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,
|
||
@@ -463,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;
|
||
}
|
||
|
||
@@ -472,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
|
||
@@ -517,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"));
|
||
- }
|
||
+ GFile *file;
|
||
+ file = g_file_new_for_uri (uri);
|
||
+ comics_document->archive_path = g_file_get_path (file);
|
||
+ g_object_unref (file);
|
||
|
||
- 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;
|
||
- }
|
||
-
|
||
- 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,
|
||
@@ -568,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);
|
||
@@ -627,7 +393,6 @@ comics_document_load (EvDocument *document,
|
||
return TRUE;
|
||
}
|
||
|
||
-
|
||
static gboolean
|
||
comics_document_save (EvDocument *document,
|
||
const char *uri,
|
||
@@ -635,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
|
||
@@ -649,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,
|
||
@@ -656,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 *
|
||
@@ -731,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);
|
||
-
|
||
- 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);
|
||
- } else if (bytes <= 0) {
|
||
- close (outpipe);
|
||
- gdk_pixbuf_loader_close (loader, NULL);
|
||
- outpipe = -1;
|
||
+ 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;
|
||
+ }
|
||
+
|
||
+ 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;
|
||
}
|
||
- 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);
|
||
+
|
||
+ 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 {
|
||
+ 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);
|
||
+ 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;
|
||
}
|
||
|
||
@@ -805,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);
|
||
}
|
||
@@ -900,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 *
|
||
@@ -940,7 +657,7 @@ comics_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document,
|
||
|
||
if (border) {
|
||
GdkPixbuf *tmp_pixbuf = thumbnail;
|
||
-
|
||
+
|
||
thumbnail = ev_document_misc_get_thumbnail_frame (-1, -1, tmp_pixbuf);
|
||
g_object_unref (tmp_pixbuf);
|
||
}
|
||
@@ -955,7 +672,7 @@ comics_document_thumbnails_get_dimensions (EvDocumentThumbnails *document,
|
||
gint *height)
|
||
{
|
||
gdouble page_width, page_height;
|
||
-
|
||
+
|
||
comics_document_get_page_size (EV_DOCUMENT (document), rc->page,
|
||
&page_width, &page_height);
|
||
|
||
@@ -974,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 6cc55f0..4417a69 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 0000000..568e162
|
||
--- /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 0000000..b4e1399
|
||
--- /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 90d2f09..5fced50 100644
|
||
--- a/configure.ac
|
||
+++ b/configure.ac
|
||
@@ -560,8 +560,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 6c492da..d57d002 100644
|
||
--- a/libdocument/ev-document.h
|
||
+++ b/libdocument/ev-document.h
|
||
@@ -56,6 +56,7 @@ typedef struct _EvDocumentPrivate EvDocumentPrivate;
|
||
typedef enum
|
||
{
|
||
EV_DOCUMENT_ERROR_INVALID,
|
||
+ EV_DOCUMENT_ERROR_UNSUPPORTED_CONTENT,
|
||
EV_DOCUMENT_ERROR_ENCRYPTED
|
||
} EvDocumentError;
|
||
|
||
--
|
||
2.43.0
|
||
|