]> www.fi.muni.cz Git - evince.git/blobdiff - backend/comics/comics-document.c
a11: using ATK_ROLE_DOCUMENT_FRAME it's more correct
[evince.git] / backend / comics / comics-document.c
index 2e867b5c825871e6e20920c47ada466a989dc1a2..0481de864b586ce7e118820fddd422a4d0907c4d 100644 (file)
@@ -1,5 +1,6 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
 /*
+ * Copyright (C) 2009-2010 Juanjo MarĂ­n <juanj.marin@juntadeandalucia.es>
  * Copyright (C) 2005, Teemu Tervo <teemu.tervo@gmx.net>
  *
  * This program is free software; you can redistribute it and/or modify
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
 #include <config.h>
 
 #include <unistd.h>
 #include <string.h>
-#include <sys/wait.h>
 #include <stdlib.h>
 #include <errno.h>
 
 #include <glib/gstdio.h>
 #include <gio/gio.h>
 
+#ifdef G_OS_WIN32
+# define WIFEXITED(x) ((x) != 3)
+# define WEXITSTATUS(x) (x)
+#else
+# include <sys/wait.h>
+#endif
+
 #include "comics-document.h"
 #include "ev-document-misc.h"
-#include "ev-document-thumbnails.h"
 #include "ev-file-helpers.h"
 
+#ifdef G_OS_WIN32
+/* On windows g_spawn_command_line_sync reads stdout in O_BINARY mode, not in O_TEXT mode.
+ * As a consequence, newlines are in a platform dependent representation (\r\n). This
+ * might be considered a bug in glib.
+ */
+#define EV_EOL "\r\n"
+#else
+#define EV_EOL "\n"
+#endif
+
 typedef enum
 {
        RARLABS,
@@ -57,7 +73,7 @@ struct _ComicsDocument
 
        gchar    *archive, *dir;
        GPtrArray *page_names;
-       gchar    *selected_command;
+       gchar    *selected_command, *alternative_command;
        gchar    *extract_command, *list_command, *decompress_tmp;
        gboolean regex_arg;
        gint     offset;
@@ -65,6 +81,7 @@ struct _ComicsDocument
 };
 
 #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 
@@ -72,14 +89,12 @@ struct _ComicsDocument
 
 /**
  * @extract: command line arguments to pass to extract a file from the archive
- *   to stdout. The archive file and the file to extract will be appended after
- *   a "--".
+ *   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. The archive file and the directory to extract to will be
- *   appended after a "--".
- * @regex_arg: whether the command expects one filename or accepts a regex (glob?)
- * @offset: the byte offset of the filename on each line in the output of
+ *   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 {
@@ -95,10 +110,10 @@ static const ComicBookDecompressCommand command_usage_def[] = {
        {"%s p -c- -ierr --", "%s vb -c- -- %s", NULL             , FALSE, NO_OFFSET},
 
         /* GNA! unrar */
-       {NULL               , "%s t %s"        , "%s -xf %s %s"   , TRUE , NO_OFFSET},
+       {NULL               , "%s t %s"        , "%s -xf %s %s"   , FALSE, NO_OFFSET},
 
         /* unzip */
-       {"%s -p -C --"      , "%s -Z -1 -- %s" , NULL             , TRUE , NO_OFFSET},
+       {"%s -p -C --"      , "%s %s"          , NULL             , TRUE , OFFSET_ZIP},
 
         /* 7zip */
        {NULL               , "%s l -- %s"     , "%s x -y %s -o%s", FALSE, OFFSET_7Z},
@@ -107,8 +122,6 @@ static const ComicBookDecompressCommand command_usage_def[] = {
        {"%s -xOf"          , "%s -tf %s"      , NULL             , FALSE, NO_OFFSET}
 };
 
-static void       comics_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface);
-
 static GSList*    get_supported_image_extensions (void);
 static void       get_page_size_area_prepared_cb (GdkPixbufLoader *loader,
                                                  gpointer data);
@@ -120,46 +133,62 @@ static char**     extract_argv                   (EvDocument *document,
                                                  gint page);
 
 
-EV_BACKEND_REGISTER_WITH_CODE (ComicsDocument, comics_document,
-       {
-               EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_THUMBNAILS,
-                                               comics_document_document_thumbnails_iface_init);
-       } );
+EV_BACKEND_REGISTER (ComicsDocument, comics_document)
 
-static char *
-comics_regex_quote (const char *s)
+/**
+ * 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)
 {
-    char *ret, *d;
-
-    d = ret = g_malloc (strlen (s) * 4 + 3);
-    
-    *d++ = '\'';
-
-    for (; *s; s++, d++) {
-       switch (*s) {
-       case '?':
-       case '|':
-       case '[':
-       case ']':
-       case '*':
-       case '\\':
-           *d++ = '\\';
-           break;
-       case '\'':
-           *d++ = '\'';
-           *d++ = '\\';
-           *d++ = '\'';
-           break;
+       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;
+               }
+               ++p;
        }
-       *d = *s;
-    }
-    
-    *d++ = '\'';
-    *d = '\0';
-
-    return ret;
+       g_string_append_c (dest, '\'');
+       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,
@@ -216,20 +245,30 @@ static gboolean
 comics_generate_command_lines (ComicsDocument *comics_document, 
                               GError         **error)
 {
-       gchar *quoted_file;
+       gchar *quoted_file, *quoted_file_aux;
+       gchar *quoted_command;
        ComicBookDecompressType type;
        
        type = comics_document->command_usage;
-       quoted_file = g_shell_quote (comics_document->archive);
-       
-       comics_document->extract_command = 
-                           g_strdup_printf (command_usage_def[type].extract, 
-                                            comics_document->selected_command);
-       comics_document->list_command =
-                           g_strdup_printf (command_usage_def[type].list, 
-                                            comics_document->selected_command, 
-                                            quoted_file);
        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 ("evince-comics-XXXXXX", error);
@@ -240,10 +279,10 @@ comics_generate_command_lines (ComicsDocument *comics_document,
 
                comics_document->decompress_tmp =
                        g_strdup_printf (command_usage_def[type].decompress_tmp, 
-                                        comics_document->selected_command, 
-                                        quoted_file, 
+                                        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))
@@ -252,6 +291,7 @@ comics_generate_command_lines (ComicsDocument *comics_document,
                        return TRUE;
        } else {
                g_free (quoted_file);
+               g_free (quoted_command);
                return TRUE;
        }
 
@@ -327,7 +367,10 @@ comics_check_decompress_command    (gchar          *mime_type,
                /* InfoZIP's unzip program */
                comics_document->selected_command = 
                                g_find_program_in_path ("unzip");
-               if (comics_document->selected_command) {
+               comics_document->alternative_command =
+                               g_find_program_in_path ("zipnote");
+               if (comics_document->selected_command &&
+                   comics_document->alternative_command) {
                        comics_document->command_usage = UNZIP;
                        return TRUE;
                }
@@ -444,7 +487,8 @@ comics_document_load (EvDocument *document,
        }
 
        /* FIXME: is this safe against filenames containing \n in the archive ? */
-       cb_files = g_strsplit (std_out, "\n", 0);
+       cb_files = g_strsplit (std_out, EV_EOL, 0);
+
        g_free (std_out);
 
        if (!cb_files) {
@@ -534,7 +578,7 @@ comics_document_get_page_size (EvDocument *document,
        guchar buf[1024];
        gboolean success, got_size = FALSE;
        gint outpipe = -1;
-       GPid child_pid = -1;
+       GPid child_pid;
        gssize bytes;
        GdkPixbuf *pixbuf;
        gchar *filename;
@@ -609,7 +653,7 @@ comics_document_render_pixbuf (EvDocument      *document,
        guchar buf[4096];
        gboolean success;
        gint outpipe = -1;
-       GPid child_pid = -1;
+       GPid child_pid;
        gssize bytes;
        gint width, height;
        gchar *filename;
@@ -746,6 +790,7 @@ comics_document_finalize (GObject *object)
 
        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);
 
@@ -799,52 +844,6 @@ get_supported_image_extensions()
        return extensions;
 }
 
-static GdkPixbuf *
-comics_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document,
-                                         EvRenderContext      *rc,
-                                         gboolean              border)
-{
-       GdkPixbuf *thumbnail;
-
-       thumbnail = comics_document_render_pixbuf (EV_DOCUMENT (document), rc);
-
-       if (border) {
-             GdkPixbuf *tmp_pixbuf = thumbnail;
-             
-             thumbnail = ev_document_misc_get_thumbnail_frame (-1, -1, tmp_pixbuf);
-             g_object_unref (tmp_pixbuf);
-       }
-
-       return thumbnail;
-}
-
-static void
-comics_document_thumbnails_get_dimensions (EvDocumentThumbnails *document,
-                                          EvRenderContext      *rc,
-                                          gint                 *width,
-                                          gint                 *height)
-{
-       gdouble page_width, page_height;
-       
-       comics_document_get_page_size (EV_DOCUMENT (document), rc->page,
-                                      &page_width, &page_height);
-
-       if (rc->rotation == 90 || rc->rotation == 270) {
-               *width = (gint) (page_height * rc->scale);
-               *height = (gint) (page_width * rc->scale);
-       } else {
-               *width = (gint) (page_width * rc->scale);
-               *height = (gint) (page_height * rc->scale);
-       }
-}
-
-static void
-comics_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface)
-{
-       iface->get_thumbnail = comics_document_thumbnails_get_thumbnail;
-       iface->get_dimensions = comics_document_thumbnails_get_dimensions;
-}
-
 static char**
 extract_argv (EvDocument *document, gint page)
 {
@@ -856,10 +855,12 @@ extract_argv (EvDocument *document, gint page)
         if (page >= comics_document->page_names->len)
                 return NULL;
 
-       quoted_archive = g_shell_quote (comics_document->archive);
        if (comics_document->regex_arg) {
-               quoted_filename = comics_regex_quote (comics_document->page_names->pdata[page]);
+               quoted_archive = comics_regex_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]);
        }