| File: | backend/comics/comics-document.c |
| Warning: | line 966, column 31 The left operand of '*' is a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */ | |||
| 2 | /* | |||
| 3 | * Copyright (C) 2009-2010 Juanjo Marín <juanj.marin@juntadeandalucia.es> | |||
| 4 | * Copyright (C) 2005, Teemu Tervo <teemu.tervo@gmx.net> | |||
| 5 | * | |||
| 6 | * This program is free software; you can redistribute it and/or modify | |||
| 7 | * it under the terms of the GNU General Public License as published by | |||
| 8 | * the Free Software Foundation; either version 2, or (at your option) | |||
| 9 | * any later version. | |||
| 10 | * | |||
| 11 | * This program is distributed in the hope that it will be useful, | |||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| 14 | * GNU General Public License for more details. | |||
| 15 | * | |||
| 16 | * You should have received a copy of the GNU General Public License | |||
| 17 | * along with this program; if not, write to the Free Software | |||
| 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
| 19 | */ | |||
| 20 | ||||
| 21 | #include <config.h> | |||
| 22 | ||||
| 23 | #include <unistd.h> | |||
| 24 | #include <string.h> | |||
| 25 | #include <stdlib.h> | |||
| 26 | #include <errno(*__errno_location ()).h> | |||
| 27 | ||||
| 28 | #include <glib.h> | |||
| 29 | #include <glib/gi18n-lib.h> | |||
| 30 | #include <glib/gstdio.h> | |||
| 31 | #include <gio/gio.h> | |||
| 32 | ||||
| 33 | #include <sys/wait.h> | |||
| 34 | ||||
| 35 | #include "comics-document.h" | |||
| 36 | #include "ev-document-misc.h" | |||
| 37 | #include "ev-document-thumbnails.h" | |||
| 38 | #include "ev-file-helpers.h" | |||
| 39 | ||||
| 40 | #define EV_EOL"\n" "\n" | |||
| 41 | ||||
| 42 | typedef enum | |||
| 43 | { | |||
| 44 | RARLABS, | |||
| 45 | GNAUNRAR, | |||
| 46 | UNZIP, | |||
| 47 | P7ZIP, | |||
| 48 | TAR, | |||
| 49 | UNARCHIVER | |||
| 50 | } ComicBookDecompressType; | |||
| 51 | ||||
| 52 | typedef struct _ComicsDocumentClass ComicsDocumentClass; | |||
| 53 | ||||
| 54 | struct _ComicsDocumentClass | |||
| 55 | { | |||
| 56 | EvDocumentClass parent_class; | |||
| 57 | }; | |||
| 58 | ||||
| 59 | struct _ComicsDocument | |||
| 60 | { | |||
| 61 | EvDocument parent_instance; | |||
| 62 | ||||
| 63 | gchar *archive, *dir; | |||
| 64 | GPtrArray *page_names; | |||
| 65 | gchar *selected_command, *alternative_command; | |||
| 66 | gchar *extract_command, *list_command, *decompress_tmp; | |||
| 67 | gboolean regex_arg; | |||
| 68 | gint offset; | |||
| 69 | ComicBookDecompressType command_usage; | |||
| 70 | }; | |||
| 71 | ||||
| 72 | #define OFFSET_7Z53 53 | |||
| 73 | #define OFFSET_ZIP2 2 | |||
| 74 | #define NO_OFFSET0 0 | |||
| 75 | ||||
| 76 | /* For perfomance reasons of 7z* we've choosen to decompress on the temporary | |||
| 77 | * directory instead of decompressing on the stdout */ | |||
| 78 | ||||
| 79 | /** | |||
| 80 | * @extract: command line arguments to pass to extract a file from the archive | |||
| 81 | * to stdout. | |||
| 82 | * @list: command line arguments to list the archive contents | |||
| 83 | * @decompress_tmp: command line arguments to pass to extract the archive | |||
| 84 | * into a directory. | |||
| 85 | * @regex_arg: whether the command can accept regex expressions | |||
| 86 | * @offset: the position offset of the filename on each line in the output of | |||
| 87 | * running the @list command | |||
| 88 | */ | |||
| 89 | typedef struct { | |||
| 90 | char *extract; | |||
| 91 | char *list; | |||
| 92 | char *decompress_tmp; | |||
| 93 | gboolean regex_arg; | |||
| 94 | gint offset; | |||
| 95 | } ComicBookDecompressCommand; | |||
| 96 | ||||
| 97 | static const ComicBookDecompressCommand command_usage_def[] = { | |||
| 98 | /* RARLABS unrar */ | |||
| 99 | {"%s p -c- -ierr --", "%s vb -c- -- %s", NULL((void*)0) , FALSE(0), NO_OFFSET0}, | |||
| 100 | ||||
| 101 | /* GNA! unrar */ | |||
| 102 | {NULL((void*)0) , "%s t %s" , "%s -xf %s %s" , FALSE(0), NO_OFFSET0}, | |||
| 103 | ||||
| 104 | /* unzip */ | |||
| 105 | {"%s -p -C --" , "%s %s" , NULL((void*)0) , TRUE(!(0)) , OFFSET_ZIP2}, | |||
| 106 | ||||
| 107 | /* 7zip */ | |||
| 108 | {NULL((void*)0) , "%s l -- %s" , "%s x -y %s -o%s", FALSE(0), OFFSET_7Z53}, | |||
| 109 | ||||
| 110 | /* tar */ | |||
| 111 | {"%s -xOf" , "%s -tf %s" , NULL((void*)0) , FALSE(0), NO_OFFSET0}, | |||
| 112 | ||||
| 113 | /* UNARCHIVER */ | |||
| 114 | {"unar -o -" , "%s %s" , NULL((void*)0) , FALSE(0), NO_OFFSET0} | |||
| 115 | }; | |||
| 116 | ||||
| 117 | static void comics_document_document_thumbnails_iface_init (EvDocumentThumbnailsInterface *iface); | |||
| 118 | ||||
| 119 | static GSList* get_supported_image_extensions (void); | |||
| 120 | static void get_page_size_area_prepared_cb (GdkPixbufLoader *loader, | |||
| 121 | gpointer data); | |||
| 122 | static void render_pixbuf_size_prepared_cb (GdkPixbufLoader *loader, | |||
| 123 | gint width, | |||
| 124 | gint height, | |||
| 125 | gpointer data); | |||
| 126 | static char** extract_argv (EvDocument *document, | |||
| 127 | gint page); | |||
| 128 | ||||
| 129 | ||||
| 130 | EV_BACKEND_REGISTER_WITH_CODE (ComicsDocument, comics_document,static GType g_define_type_id = 0; GType comics_document_get_type (void) { return g_define_type_id; } static void comics_document_init (ComicsDocument *self); static void comics_document_class_init (ComicsDocumentClass *klass); static gpointer comics_document_parent_class = ((void*)0); static void comics_document_class_intern_init ( gpointer klass) { comics_document_parent_class = g_type_class_peek_parent (klass); comics_document_class_init ((ComicsDocumentClass *) klass); } __attribute__((visibility("default"))) GType register_lector_backend (GTypeModule *module) { const GTypeInfo our_info = { sizeof ( ComicsDocumentClass), ((void*)0), ((void*)0), (GClassInitFunc ) comics_document_class_intern_init, ((void*)0), ((void*)0), sizeof (ComicsDocument), 0, (GInstanceInitFunc) comics_document_init }; bindtextdomain ("lector", "/usr/share/locale"); bind_textdomain_codeset ("lector", "UTF-8"); g_define_type_id = g_type_module_register_type (module, (ev_document_get_type ()), "ComicsDocument", &our_info , (GTypeFlags)0); { { const GInterfaceInfo g_implement_interface_info = { (GInterfaceInitFunc) comics_document_document_thumbnails_iface_init , ((void*)0), ((void*)0) }; g_type_module_add_interface (module , g_define_type_id, (ev_document_thumbnails_get_type ()), & g_implement_interface_info); }; } return g_define_type_id; } | |||
| 131 | {static GType g_define_type_id = 0; GType comics_document_get_type (void) { return g_define_type_id; } static void comics_document_init (ComicsDocument *self); static void comics_document_class_init (ComicsDocumentClass *klass); static gpointer comics_document_parent_class = ((void*)0); static void comics_document_class_intern_init ( gpointer klass) { comics_document_parent_class = g_type_class_peek_parent (klass); comics_document_class_init ((ComicsDocumentClass *) klass); } __attribute__((visibility("default"))) GType register_lector_backend (GTypeModule *module) { const GTypeInfo our_info = { sizeof ( ComicsDocumentClass), ((void*)0), ((void*)0), (GClassInitFunc ) comics_document_class_intern_init, ((void*)0), ((void*)0), sizeof (ComicsDocument), 0, (GInstanceInitFunc) comics_document_init }; bindtextdomain ("lector", "/usr/share/locale"); bind_textdomain_codeset ("lector", "UTF-8"); g_define_type_id = g_type_module_register_type (module, (ev_document_get_type ()), "ComicsDocument", &our_info , (GTypeFlags)0); { { const GInterfaceInfo g_implement_interface_info = { (GInterfaceInitFunc) comics_document_document_thumbnails_iface_init , ((void*)0), ((void*)0) }; g_type_module_add_interface (module , g_define_type_id, (ev_document_thumbnails_get_type ()), & g_implement_interface_info); }; } return g_define_type_id; } | |||
| 132 | EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_THUMBNAILS,static GType g_define_type_id = 0; GType comics_document_get_type (void) { return g_define_type_id; } static void comics_document_init (ComicsDocument *self); static void comics_document_class_init (ComicsDocumentClass *klass); static gpointer comics_document_parent_class = ((void*)0); static void comics_document_class_intern_init ( gpointer klass) { comics_document_parent_class = g_type_class_peek_parent (klass); comics_document_class_init ((ComicsDocumentClass *) klass); } __attribute__((visibility("default"))) GType register_lector_backend (GTypeModule *module) { const GTypeInfo our_info = { sizeof ( ComicsDocumentClass), ((void*)0), ((void*)0), (GClassInitFunc ) comics_document_class_intern_init, ((void*)0), ((void*)0), sizeof (ComicsDocument), 0, (GInstanceInitFunc) comics_document_init }; bindtextdomain ("lector", "/usr/share/locale"); bind_textdomain_codeset ("lector", "UTF-8"); g_define_type_id = g_type_module_register_type (module, (ev_document_get_type ()), "ComicsDocument", &our_info , (GTypeFlags)0); { { const GInterfaceInfo g_implement_interface_info = { (GInterfaceInitFunc) comics_document_document_thumbnails_iface_init , ((void*)0), ((void*)0) }; g_type_module_add_interface (module , g_define_type_id, (ev_document_thumbnails_get_type ()), & g_implement_interface_info); }; } return g_define_type_id; } | |||
| 133 | comics_document_document_thumbnails_iface_init);static GType g_define_type_id = 0; GType comics_document_get_type (void) { return g_define_type_id; } static void comics_document_init (ComicsDocument *self); static void comics_document_class_init (ComicsDocumentClass *klass); static gpointer comics_document_parent_class = ((void*)0); static void comics_document_class_intern_init ( gpointer klass) { comics_document_parent_class = g_type_class_peek_parent (klass); comics_document_class_init ((ComicsDocumentClass *) klass); } __attribute__((visibility("default"))) GType register_lector_backend (GTypeModule *module) { const GTypeInfo our_info = { sizeof ( ComicsDocumentClass), ((void*)0), ((void*)0), (GClassInitFunc ) comics_document_class_intern_init, ((void*)0), ((void*)0), sizeof (ComicsDocument), 0, (GInstanceInitFunc) comics_document_init }; bindtextdomain ("lector", "/usr/share/locale"); bind_textdomain_codeset ("lector", "UTF-8"); g_define_type_id = g_type_module_register_type (module, (ev_document_get_type ()), "ComicsDocument", &our_info , (GTypeFlags)0); { { const GInterfaceInfo g_implement_interface_info = { (GInterfaceInitFunc) comics_document_document_thumbnails_iface_init , ((void*)0), ((void*)0) }; g_type_module_add_interface (module , g_define_type_id, (ev_document_thumbnails_get_type ()), & g_implement_interface_info); }; } return g_define_type_id; } | |||
| 134 | } )static GType g_define_type_id = 0; GType comics_document_get_type (void) { return g_define_type_id; } static void comics_document_init (ComicsDocument *self); static void comics_document_class_init (ComicsDocumentClass *klass); static gpointer comics_document_parent_class = ((void*)0); static void comics_document_class_intern_init ( gpointer klass) { comics_document_parent_class = g_type_class_peek_parent (klass); comics_document_class_init ((ComicsDocumentClass *) klass); } __attribute__((visibility("default"))) GType register_lector_backend (GTypeModule *module) { const GTypeInfo our_info = { sizeof ( ComicsDocumentClass), ((void*)0), ((void*)0), (GClassInitFunc ) comics_document_class_intern_init, ((void*)0), ((void*)0), sizeof (ComicsDocument), 0, (GInstanceInitFunc) comics_document_init }; bindtextdomain ("lector", "/usr/share/locale"); bind_textdomain_codeset ("lector", "UTF-8"); g_define_type_id = g_type_module_register_type (module, (ev_document_get_type ()), "ComicsDocument", &our_info , (GTypeFlags)0); { { const GInterfaceInfo g_implement_interface_info = { (GInterfaceInitFunc) comics_document_document_thumbnails_iface_init , ((void*)0), ((void*)0) }; g_type_module_add_interface (module , g_define_type_id, (ev_document_thumbnails_get_type ()), & g_implement_interface_info); }; } return g_define_type_id; }; | |||
| 135 | ||||
| 136 | /** | |||
| 137 | * comics_regex_quote: | |||
| 138 | * @unquoted_string: a literal string | |||
| 139 | * | |||
| 140 | * Quotes a string so unzip will not interpret the regex expressions of | |||
| 141 | * @unquoted_string. Basically, this functions uses [] to disable regex | |||
| 142 | * expressions. The return value must be freed with * g_free() | |||
| 143 | * | |||
| 144 | * Return value: quoted and disabled-regex string | |||
| 145 | **/ | |||
| 146 | static gchar * | |||
| 147 | comics_regex_quote (const gchar *unquoted_string) | |||
| 148 | { | |||
| 149 | const gchar *p; | |||
| 150 | GString *dest; | |||
| 151 | ||||
| 152 | dest = g_string_new ("'"); | |||
| 153 | ||||
| 154 | p = unquoted_string; | |||
| 155 | ||||
| 156 | while (*p) { | |||
| 157 | switch (*p) { | |||
| 158 | /* * matches a sequence of 0 or more characters */ | |||
| 159 | case ('*'): | |||
| 160 | /* ? matches exactly 1 charactere */ | |||
| 161 | case ('?'): | |||
| 162 | /* [...] matches any single character found inside | |||
| 163 | * the brackets. Disabling the first bracket is enough. | |||
| 164 | */ | |||
| 165 | case ('['): | |||
| 166 | g_string_append (dest, "[")(__builtin_constant_p ("[") ? __extension__ ({ const char * const __val = ("["); g_string_append_len_inline (dest, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize ) -1); }) : g_string_append_len_inline (dest, "[", (gssize) - 1)); | |||
| 167 | g_string_append_c (dest, *p)g_string_append_c_inline (dest, *p); | |||
| 168 | g_string_append (dest, "]")(__builtin_constant_p ("]") ? __extension__ ({ const char * const __val = ("]"); g_string_append_len_inline (dest, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize ) -1); }) : g_string_append_len_inline (dest, "]", (gssize) - 1)); | |||
| 169 | break; | |||
| 170 | /* Because \ escapes regex expressions that we are | |||
| 171 | * disabling for unzip, we need to disable \ too */ | |||
| 172 | case ('\\'): | |||
| 173 | g_string_append (dest, "[\\\\]")(__builtin_constant_p ("[\\\\]") ? __extension__ ({ const char * const __val = ("[\\\\]"); g_string_append_len_inline (dest , __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + ! (__val))) : (gssize) -1); }) : g_string_append_len_inline (dest , "[\\\\]", (gssize) -1)); | |||
| 174 | break; | |||
| 175 | /* Escape single quote inside the string */ | |||
| 176 | case ('\''): | |||
| 177 | g_string_append (dest, "'\\''")(__builtin_constant_p ("'\\''") ? __extension__ ({ const char * const __val = ("'\\''"); g_string_append_len_inline (dest, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + ! (__val))) : (gssize) -1); }) : g_string_append_len_inline (dest , "'\\''", (gssize) -1)); | |||
| 178 | break; | |||
| 179 | default: | |||
| 180 | g_string_append_c (dest, *p)g_string_append_c_inline (dest, *p); | |||
| 181 | break; | |||
| 182 | } | |||
| 183 | ++p; | |||
| 184 | } | |||
| 185 | g_string_append_c (dest, '\'')g_string_append_c_inline (dest, '\''); | |||
| 186 | return g_string_free (dest, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((dest ), ((0))) : g_string_free_and_steal (dest)) : (g_string_free) ((dest), ((0)))); | |||
| 187 | } | |||
| 188 | ||||
| 189 | ||||
| 190 | /* This function manages the command for decompressing a comic book */ | |||
| 191 | static gboolean | |||
| 192 | comics_decompress_temp_dir (const gchar *command_decompress_tmp, | |||
| 193 | const gchar *command, | |||
| 194 | GError **error) | |||
| 195 | { | |||
| 196 | gboolean success; | |||
| 197 | gchar *std_out, *basename; | |||
| 198 | GError *err = NULL((void*)0); | |||
| 199 | gint retval; | |||
| 200 | ||||
| 201 | success = g_spawn_command_line_sync (command_decompress_tmp, &std_out, | |||
| 202 | NULL((void*)0), &retval, &err); | |||
| 203 | basename = g_path_get_basename (command); | |||
| 204 | if (!success) { | |||
| 205 | g_set_error (error, | |||
| 206 | EV_DOCUMENT_ERRORev_document_error_quark (), | |||
| 207 | EV_DOCUMENT_ERROR_INVALID, | |||
| 208 | _("Error launching the command “%s” in order to "((char *) g_dgettext ("lector", "Error launching the command “%s” in order to " "decompress the comic book: %s")) | |||
| 209 | "decompress the comic book: %s")((char *) g_dgettext ("lector", "Error launching the command “%s” in order to " "decompress the comic book: %s")), | |||
| 210 | basename, | |||
| 211 | err->message); | |||
| 212 | g_error_free (err); | |||
| 213 | } else if (WIFEXITED (retval)(((retval) & 0x7f) == 0)) { | |||
| 214 | if (WEXITSTATUS (retval)(((retval) & 0xff00) >> 8) == EXIT_SUCCESS0) { | |||
| 215 | g_free (std_out); | |||
| 216 | g_free (basename); | |||
| 217 | return TRUE(!(0)); | |||
| 218 | } else { | |||
| 219 | g_set_error (error, | |||
| 220 | EV_DOCUMENT_ERRORev_document_error_quark (), | |||
| 221 | EV_DOCUMENT_ERROR_INVALID, | |||
| 222 | _("The command “%s” failed at "((char *) g_dgettext ("lector", "The command “%s” failed at " "decompressing the comic book.")) | |||
| 223 | "decompressing the comic book.")((char *) g_dgettext ("lector", "The command “%s” failed at " "decompressing the comic book.")), | |||
| 224 | basename); | |||
| 225 | g_free (std_out); | |||
| 226 | } | |||
| 227 | } else { | |||
| 228 | g_set_error (error, | |||
| 229 | EV_DOCUMENT_ERRORev_document_error_quark (), | |||
| 230 | EV_DOCUMENT_ERROR_INVALID, | |||
| 231 | _("The command “%s” did not end normally.")((char *) g_dgettext ("lector", "The command “%s” did not end normally." )), | |||
| 232 | basename); | |||
| 233 | g_free (std_out); | |||
| 234 | } | |||
| 235 | g_free (basename); | |||
| 236 | return FALSE(0); | |||
| 237 | } | |||
| 238 | ||||
| 239 | /* This function shows how to use the choosen command for decompressing a | |||
| 240 | * comic book file. It modifies fields of the ComicsDocument struct with | |||
| 241 | * this information */ | |||
| 242 | static gboolean | |||
| 243 | comics_generate_command_lines (ComicsDocument *comics_document, | |||
| 244 | GError **error) | |||
| 245 | { | |||
| 246 | gchar *quoted_file, *quoted_file_aux; | |||
| 247 | gchar *quoted_command; | |||
| 248 | ComicBookDecompressType type; | |||
| 249 | ||||
| 250 | type = comics_document->command_usage; | |||
| 251 | comics_document->regex_arg = command_usage_def[type].regex_arg; | |||
| 252 | quoted_command = g_shell_quote (comics_document->selected_command); | |||
| 253 | if (comics_document->regex_arg) { | |||
| 254 | quoted_file = comics_regex_quote (comics_document->archive); | |||
| 255 | quoted_file_aux = g_shell_quote (comics_document->archive); | |||
| 256 | comics_document->list_command = | |||
| 257 | g_strdup_printf (command_usage_def[type].list, | |||
| 258 | comics_document->alternative_command, | |||
| 259 | quoted_file_aux); | |||
| 260 | g_free (quoted_file_aux); | |||
| 261 | } else { | |||
| 262 | quoted_file = g_shell_quote (comics_document->archive); | |||
| 263 | comics_document->list_command = | |||
| 264 | g_strdup_printf (command_usage_def[type].list, | |||
| 265 | quoted_command, quoted_file); | |||
| 266 | } | |||
| 267 | comics_document->extract_command = | |||
| 268 | g_strdup_printf (command_usage_def[type].extract, | |||
| 269 | quoted_command); | |||
| 270 | comics_document->offset = command_usage_def[type].offset; | |||
| 271 | if (command_usage_def[type].decompress_tmp) { | |||
| 272 | comics_document->dir = ev_mkdtemp ("lector-comics-XXXXXX", error); | |||
| 273 | if (comics_document->dir == NULL((void*)0)) | |||
| 274 | return FALSE(0); | |||
| 275 | ||||
| 276 | /* unrar-free can't create directories, but ev_mkdtemp already created the dir */ | |||
| 277 | ||||
| 278 | comics_document->decompress_tmp = | |||
| 279 | g_strdup_printf (command_usage_def[type].decompress_tmp, | |||
| 280 | quoted_command, quoted_file, | |||
| 281 | comics_document->dir); | |||
| 282 | g_free (quoted_file); | |||
| 283 | g_free (quoted_command); | |||
| 284 | ||||
| 285 | if (!comics_decompress_temp_dir (comics_document->decompress_tmp, | |||
| 286 | comics_document->selected_command, error)) | |||
| 287 | return FALSE(0); | |||
| 288 | else | |||
| 289 | return TRUE(!(0)); | |||
| 290 | } else { | |||
| 291 | g_free (quoted_file); | |||
| 292 | g_free (quoted_command); | |||
| 293 | return TRUE(!(0)); | |||
| 294 | } | |||
| 295 | ||||
| 296 | } | |||
| 297 | ||||
| 298 | /* This function chooses an external command for decompressing a comic | |||
| 299 | * book based on its mime tipe. */ | |||
| 300 | static gboolean | |||
| 301 | comics_check_decompress_command (gchar *mime_type, | |||
| 302 | ComicsDocument *comics_document, | |||
| 303 | GError **error) | |||
| 304 | { | |||
| 305 | gboolean success; | |||
| 306 | gchar *std_out, *std_err; | |||
| 307 | gint retval; | |||
| 308 | GError *err = NULL((void*)0); | |||
| 309 | ||||
| 310 | /* FIXME, use proper cbr/cbz mime types once they're | |||
| 311 | * included in shared-mime-info */ | |||
| 312 | ||||
| 313 | if (g_content_type_is_a (mime_type, "application/x-cbr") || | |||
| 314 | g_content_type_is_a (mime_type, "application/x-rar")) { | |||
| 315 | /* The RARLAB provides a no-charge proprietary (freeware) | |||
| 316 | * decompress-only client for Linux called unrar. Another | |||
| 317 | * option is a GPLv2-licensed command-line tool developed by | |||
| 318 | * the Gna! project. Confusingly enough, the free software RAR | |||
| 319 | * decoder is also named unrar. For this reason we need to add | |||
| 320 | * some lines for disambiguation. Sorry for the added the | |||
| 321 | * complexity but it's life :) | |||
| 322 | * Finally, some distributions, like Debian, rename this free | |||
| 323 | * option as unrar-free. | |||
| 324 | * */ | |||
| 325 | comics_document->selected_command = | |||
| 326 | g_find_program_in_path ("unrar"); | |||
| 327 | if (comics_document->selected_command) { | |||
| 328 | /* We only use std_err to avoid printing useless error | |||
| 329 | * messages on the terminal */ | |||
| 330 | success = | |||
| 331 | g_spawn_command_line_sync ( | |||
| 332 | comics_document->selected_command, | |||
| 333 | &std_out, &std_err, | |||
| 334 | &retval, &err); | |||
| 335 | if (!success) { | |||
| 336 | g_propagate_error (error, err); | |||
| 337 | g_error_free (err); | |||
| 338 | return FALSE(0); | |||
| 339 | /* I don't check retval status because RARLAB unrar | |||
| 340 | * doesn't have a way to return 0 without involving an | |||
| 341 | * operation with a file*/ | |||
| 342 | } else if (WIFEXITED (retval)(((retval) & 0x7f) == 0)) { | |||
| 343 | if (g_strrstr (std_out,"freeware") != NULL((void*)0)) | |||
| 344 | /* The RARLAB freeware client */ | |||
| 345 | comics_document->command_usage = RARLABS; | |||
| 346 | else | |||
| 347 | /* The Gna! free software client */ | |||
| 348 | comics_document->command_usage = GNAUNRAR; | |||
| 349 | ||||
| 350 | g_free (std_out); | |||
| 351 | g_free (std_err); | |||
| 352 | return TRUE(!(0)); | |||
| 353 | } | |||
| 354 | } | |||
| 355 | /* The Gna! free software client with Debian naming convention */ | |||
| 356 | comics_document->selected_command = | |||
| 357 | g_find_program_in_path ("unrar-free"); | |||
| 358 | if (comics_document->selected_command) { | |||
| 359 | comics_document->command_usage = GNAUNRAR; | |||
| 360 | return TRUE(!(0)); | |||
| 361 | } | |||
| 362 | comics_document->selected_command = | |||
| 363 | g_find_program_in_path ("lsar"); | |||
| 364 | if (comics_document->selected_command) { | |||
| 365 | comics_document->command_usage = UNARCHIVER; | |||
| 366 | return TRUE(!(0)); | |||
| 367 | } | |||
| 368 | comics_document->selected_command = | |||
| 369 | g_find_program_in_path ("bsdtar"); | |||
| 370 | if (comics_document->selected_command) { | |||
| 371 | comics_document->command_usage = TAR; | |||
| 372 | return TRUE(!(0)); | |||
| 373 | } | |||
| 374 | ||||
| 375 | } else if (g_content_type_is_a (mime_type, "application/x-cbz") || | |||
| 376 | g_content_type_is_a (mime_type, "application/zip")) { | |||
| 377 | /* InfoZIP's unzip program */ | |||
| 378 | comics_document->selected_command = | |||
| 379 | g_find_program_in_path ("unzip"); | |||
| 380 | comics_document->alternative_command = | |||
| 381 | g_find_program_in_path ("zipnote"); | |||
| 382 | if (comics_document->selected_command && | |||
| 383 | comics_document->alternative_command) { | |||
| 384 | comics_document->command_usage = UNZIP; | |||
| 385 | return TRUE(!(0)); | |||
| 386 | } | |||
| 387 | comics_document->selected_command = | |||
| 388 | g_find_program_in_path ("bsdtar"); | |||
| 389 | if (comics_document->selected_command) { | |||
| 390 | comics_document->command_usage = TAR; | |||
| 391 | return TRUE(!(0)); | |||
| 392 | } | |||
| 393 | comics_document->selected_command = | |||
| 394 | g_find_program_in_path ("lsar"); | |||
| 395 | if (comics_document->selected_command) { | |||
| 396 | comics_document->command_usage = UNARCHIVER; | |||
| 397 | return TRUE(!(0)); | |||
| 398 | } | |||
| 399 | ||||
| 400 | } else if (g_content_type_is_a (mime_type, "application/x-cb7") || | |||
| 401 | g_content_type_is_a (mime_type, "application/x-7z-compressed")) { | |||
| 402 | /* 7zr, 7za and 7z are the commands from the p7zip project able | |||
| 403 | * to decompress .7z files */ | |||
| 404 | comics_document->selected_command = | |||
| 405 | g_find_program_in_path ("7zr"); | |||
| 406 | if (comics_document->selected_command) { | |||
| 407 | comics_document->command_usage = P7ZIP; | |||
| 408 | return TRUE(!(0)); | |||
| 409 | } | |||
| 410 | comics_document->selected_command = | |||
| 411 | g_find_program_in_path ("7za"); | |||
| 412 | if (comics_document->selected_command) { | |||
| 413 | comics_document->command_usage = P7ZIP; | |||
| 414 | return TRUE(!(0)); | |||
| 415 | } | |||
| 416 | comics_document->selected_command = | |||
| 417 | g_find_program_in_path ("7z"); | |||
| 418 | if (comics_document->selected_command) { | |||
| 419 | comics_document->command_usage = P7ZIP; | |||
| 420 | return TRUE(!(0)); | |||
| 421 | } | |||
| 422 | comics_document->selected_command = | |||
| 423 | g_find_program_in_path ("bsdtar"); | |||
| 424 | if (comics_document->selected_command) { | |||
| 425 | comics_document->command_usage = TAR; | |||
| 426 | return TRUE(!(0)); | |||
| 427 | } | |||
| 428 | comics_document->selected_command = | |||
| 429 | g_find_program_in_path ("lsar"); | |||
| 430 | if (comics_document->selected_command) { | |||
| 431 | comics_document->command_usage = UNARCHIVER; | |||
| 432 | return TRUE(!(0)); | |||
| 433 | } | |||
| 434 | } else if (g_content_type_is_a (mime_type, "application/x-cbt") || | |||
| 435 | g_content_type_is_a (mime_type, "application/x-tar")) { | |||
| 436 | /* tar utility (Tape ARchive) */ | |||
| 437 | comics_document->selected_command = | |||
| 438 | g_find_program_in_path ("tar"); | |||
| 439 | if (comics_document->selected_command) { | |||
| 440 | comics_document->command_usage = TAR; | |||
| 441 | return TRUE(!(0)); | |||
| 442 | } | |||
| 443 | comics_document->selected_command = | |||
| 444 | g_find_program_in_path ("bsdtar"); | |||
| 445 | if (comics_document->selected_command) { | |||
| 446 | comics_document->command_usage = TAR; | |||
| 447 | return TRUE(!(0)); | |||
| 448 | } | |||
| 449 | comics_document->selected_command = | |||
| 450 | g_find_program_in_path ("lsar"); | |||
| 451 | if (comics_document->selected_command) { | |||
| 452 | comics_document->command_usage = UNARCHIVER; | |||
| 453 | return TRUE(!(0)); | |||
| 454 | } | |||
| 455 | } else { | |||
| 456 | g_set_error (error, | |||
| 457 | EV_DOCUMENT_ERRORev_document_error_quark (), | |||
| 458 | EV_DOCUMENT_ERROR_INVALID, | |||
| 459 | _("Not a comic book MIME type: %s")((char *) g_dgettext ("lector", "Not a comic book MIME type: %s" )), | |||
| 460 | mime_type); | |||
| 461 | return FALSE(0); | |||
| 462 | } | |||
| 463 | g_set_error_literal (error, | |||
| 464 | EV_DOCUMENT_ERRORev_document_error_quark (), | |||
| 465 | EV_DOCUMENT_ERROR_INVALID, | |||
| 466 | _("Can't find an appropriate command to "((char *) g_dgettext ("lector", "Can't find an appropriate command to " "decompress this type of comic book")) | |||
| 467 | "decompress this type of comic book")((char *) g_dgettext ("lector", "Can't find an appropriate command to " "decompress this type of comic book"))); | |||
| 468 | return FALSE(0); | |||
| 469 | } | |||
| 470 | ||||
| 471 | static int | |||
| 472 | sort_page_names (gconstpointer a, | |||
| 473 | gconstpointer b) | |||
| 474 | { | |||
| 475 | const char *name_1, *name_2; | |||
| 476 | gchar *key_1, *key_2; | |||
| 477 | gboolean sort_last_1, sort_last_2; | |||
| 478 | int compare; | |||
| 479 | ||||
| 480 | name_1 = * (const char **) a; | |||
| 481 | name_2 = * (const char **) b; | |||
| 482 | ||||
| 483 | #define SORT_LAST_CHAR1 '.' | |||
| 484 | #define SORT_LAST_CHAR2 '#' | |||
| 485 | ||||
| 486 | sort_last_1 = name_1[0] == SORT_LAST_CHAR1 || name_1[0] == SORT_LAST_CHAR2; | |||
| 487 | sort_last_2 = name_2[0] == SORT_LAST_CHAR1 || name_2[0] == SORT_LAST_CHAR2; | |||
| 488 | ||||
| 489 | #undef SORT_LAST_CHAR1 | |||
| 490 | #undef SORT_LAST_CHAR2 | |||
| 491 | ||||
| 492 | if (sort_last_1 && !sort_last_2) | |||
| 493 | { | |||
| 494 | compare = +1; | |||
| 495 | } | |||
| 496 | else if (!sort_last_1 && sort_last_2) | |||
| 497 | { | |||
| 498 | compare = -1; | |||
| 499 | } | |||
| 500 | else | |||
| 501 | { | |||
| 502 | key_1 = g_utf8_collate_key_for_filename (name_1, -1); | |||
| 503 | key_2 = g_utf8_collate_key_for_filename (name_2, -1); | |||
| 504 | ||||
| 505 | compare = strcmp (key_1, key_2); | |||
| 506 | ||||
| 507 | g_free (key_1); | |||
| 508 | g_free (key_2); | |||
| 509 | } | |||
| 510 | ||||
| 511 | return compare; | |||
| 512 | } | |||
| 513 | ||||
| 514 | static gboolean | |||
| 515 | comics_document_load (EvDocument *document, | |||
| 516 | const char *uri, | |||
| 517 | GError **error) | |||
| 518 | { | |||
| 519 | ComicsDocument *comics_document = COMICS_DOCUMENT (document)((((ComicsDocument*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((document)), ((comics_document_get_type ())))))); | |||
| 520 | GSList *supported_extensions; | |||
| 521 | gchar *std_out; | |||
| 522 | gchar *mime_type; | |||
| 523 | gchar **cb_files, *cb_file; | |||
| 524 | gboolean success; | |||
| 525 | int i, retval; | |||
| 526 | GError *err = NULL((void*)0); | |||
| 527 | ||||
| 528 | comics_document->archive = g_filename_from_uri (uri, NULL((void*)0), error); | |||
| 529 | if (!comics_document->archive) | |||
| 530 | return FALSE(0); | |||
| 531 | ||||
| 532 | mime_type = ev_file_get_mime_type (uri, FALSE(0), &err); | |||
| 533 | if (!mime_type) { | |||
| 534 | if (err) { | |||
| 535 | g_propagate_error (error, err); | |||
| 536 | } else { | |||
| 537 | g_set_error_literal (error, | |||
| 538 | EV_DOCUMENT_ERRORev_document_error_quark (), | |||
| 539 | EV_DOCUMENT_ERROR_INVALID, | |||
| 540 | _("Unknown MIME Type")((char *) g_dgettext ("lector", "Unknown MIME Type"))); | |||
| 541 | } | |||
| 542 | ||||
| 543 | return FALSE(0); | |||
| 544 | } | |||
| 545 | ||||
| 546 | if (!comics_check_decompress_command (mime_type, comics_document, | |||
| 547 | error)) { | |||
| 548 | g_free (mime_type); | |||
| 549 | return FALSE(0); | |||
| 550 | } else if (!comics_generate_command_lines (comics_document, error)) { | |||
| 551 | g_free (mime_type); | |||
| 552 | return FALSE(0); | |||
| 553 | } | |||
| 554 | ||||
| 555 | g_free (mime_type); | |||
| 556 | ||||
| 557 | /* Get list of files in archive */ | |||
| 558 | success = g_spawn_command_line_sync (comics_document->list_command, | |||
| 559 | &std_out, NULL((void*)0), &retval, error); | |||
| 560 | ||||
| 561 | if (!success) { | |||
| 562 | return FALSE(0); | |||
| 563 | } else if (!WIFEXITED(retval)(((retval) & 0x7f) == 0) || WEXITSTATUS(retval)(((retval) & 0xff00) >> 8) != EXIT_SUCCESS0) { | |||
| 564 | g_set_error_literal (error, | |||
| 565 | EV_DOCUMENT_ERRORev_document_error_quark (), | |||
| 566 | EV_DOCUMENT_ERROR_INVALID, | |||
| 567 | _("File corrupted")((char *) g_dgettext ("lector", "File corrupted"))); | |||
| 568 | return FALSE(0); | |||
| 569 | } | |||
| 570 | ||||
| 571 | /* FIXME: is this safe against filenames containing \n in the archive ? */ | |||
| 572 | cb_files = g_strsplit (std_out, EV_EOL"\n", 0); | |||
| 573 | ||||
| 574 | g_free (std_out); | |||
| 575 | ||||
| 576 | if (!cb_files) { | |||
| 577 | g_set_error_literal (error, | |||
| 578 | EV_DOCUMENT_ERRORev_document_error_quark (), | |||
| 579 | EV_DOCUMENT_ERROR_INVALID, | |||
| 580 | _("No files in archive")((char *) g_dgettext ("lector", "No files in archive"))); | |||
| 581 | return FALSE(0); | |||
| 582 | } | |||
| 583 | ||||
| 584 | comics_document->page_names = g_ptr_array_sized_new (64); | |||
| 585 | ||||
| 586 | supported_extensions = get_supported_image_extensions (); | |||
| 587 | for (i = 0; cb_files[i] != NULL((void*)0); i++) { | |||
| 588 | if (comics_document->offset != NO_OFFSET0) { | |||
| 589 | if (g_utf8_strlen (cb_files[i],-1) > | |||
| 590 | comics_document->offset) { | |||
| 591 | cb_file = | |||
| 592 | g_utf8_offset_to_pointer (cb_files[i], | |||
| 593 | comics_document->offset); | |||
| 594 | } else { | |||
| 595 | continue; | |||
| 596 | } | |||
| 597 | } else { | |||
| 598 | cb_file = cb_files[i]; | |||
| 599 | } | |||
| 600 | gchar *suffix = g_strrstr (cb_file, "."); | |||
| 601 | if (!suffix) | |||
| 602 | continue; | |||
| 603 | suffix = g_ascii_strdown (suffix + 1, -1); | |||
| 604 | if (g_slist_find_custom (supported_extensions, suffix, | |||
| 605 | (GCompareFunc) strcmp) != NULL((void*)0)) { | |||
| 606 | g_ptr_array_add (comics_document->page_names, | |||
| 607 | g_strstrip (g_strdup (cb_file))g_strchomp (g_strchug (g_strdup_inline (cb_file)))); | |||
| 608 | } | |||
| 609 | g_free (suffix); | |||
| 610 | } | |||
| 611 | g_strfreev (cb_files); | |||
| 612 | g_slist_foreach (supported_extensions, (GFunc) g_free, NULL((void*)0)); | |||
| 613 | g_slist_free (supported_extensions); | |||
| 614 | ||||
| 615 | if (comics_document->page_names->len == 0) { | |||
| 616 | g_set_error (error, | |||
| 617 | EV_DOCUMENT_ERRORev_document_error_quark (), | |||
| 618 | EV_DOCUMENT_ERROR_INVALID, | |||
| 619 | _("No images found in archive %s")((char *) g_dgettext ("lector", "No images found in archive %s" )), | |||
| 620 | uri); | |||
| 621 | return FALSE(0); | |||
| 622 | } | |||
| 623 | ||||
| 624 | /* Now sort the pages */ | |||
| 625 | g_ptr_array_sort (comics_document->page_names, sort_page_names); | |||
| 626 | ||||
| 627 | return TRUE(!(0)); | |||
| 628 | } | |||
| 629 | ||||
| 630 | ||||
| 631 | static gboolean | |||
| 632 | comics_document_save (EvDocument *document, | |||
| 633 | const char *uri, | |||
| 634 | GError **error) | |||
| 635 | { | |||
| 636 | ComicsDocument *comics_document = COMICS_DOCUMENT (document)((((ComicsDocument*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((document)), ((comics_document_get_type ())))))); | |||
| 637 | ||||
| 638 | return ev_xfer_uri_simple (comics_document->archive, uri, error); | |||
| 639 | } | |||
| 640 | ||||
| 641 | static int | |||
| 642 | comics_document_get_n_pages (EvDocument *document) | |||
| 643 | { | |||
| 644 | ComicsDocument *comics_document = COMICS_DOCUMENT (document)((((ComicsDocument*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((document)), ((comics_document_get_type ())))))); | |||
| 645 | ||||
| 646 | if (comics_document->page_names == NULL((void*)0)) | |||
| 647 | return 0; | |||
| 648 | ||||
| 649 | return comics_document->page_names->len; | |||
| 650 | } | |||
| 651 | ||||
| 652 | static void | |||
| 653 | comics_document_get_page_size (EvDocument *document, | |||
| 654 | EvPage *page, | |||
| 655 | double *width, | |||
| 656 | double *height) | |||
| 657 | { | |||
| 658 | GdkPixbufLoader *loader; | |||
| 659 | char **argv; | |||
| 660 | guchar buf[1024]; | |||
| 661 | gboolean success, got_size = FALSE(0); | |||
| 662 | gint outpipe = -1; | |||
| 663 | GPid child_pid; | |||
| 664 | gssize bytes; | |||
| 665 | GdkPixbuf *pixbuf; | |||
| 666 | gchar *filename; | |||
| 667 | ComicsDocument *comics_document = COMICS_DOCUMENT (document)((((ComicsDocument*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((document)), ((comics_document_get_type ())))))); | |||
| 668 | ||||
| 669 | if (!comics_document->decompress_tmp) { | |||
| 670 | argv = extract_argv (document, page->index); | |||
| 671 | success = g_spawn_async_with_pipes (NULL((void*)0), argv, NULL((void*)0), | |||
| 672 | G_SPAWN_SEARCH_PATH | | |||
| 673 | G_SPAWN_STDERR_TO_DEV_NULL, | |||
| 674 | NULL((void*)0), NULL((void*)0), | |||
| 675 | &child_pid, | |||
| 676 | NULL((void*)0), &outpipe, NULL((void*)0), NULL((void*)0)); | |||
| 677 | g_strfreev (argv); | |||
| 678 | g_return_if_fail (success == TRUE)do { if ((success == (!(0)))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "success == TRUE" ); return; } } while (0); | |||
| 679 | ||||
| 680 | loader = gdk_pixbuf_loader_new (); | |||
| 681 | g_signal_connect (loader, "area-prepared",g_signal_connect_data ((loader), ("area-prepared"), (((GCallback ) (get_page_size_area_prepared_cb))), (&got_size), ((void *)0), (GConnectFlags) 0) | |||
| 682 | G_CALLBACK (get_page_size_area_prepared_cb),g_signal_connect_data ((loader), ("area-prepared"), (((GCallback ) (get_page_size_area_prepared_cb))), (&got_size), ((void *)0), (GConnectFlags) 0) | |||
| 683 | &got_size)g_signal_connect_data ((loader), ("area-prepared"), (((GCallback ) (get_page_size_area_prepared_cb))), (&got_size), ((void *)0), (GConnectFlags) 0); | |||
| 684 | ||||
| 685 | while (outpipe >= 0) { | |||
| 686 | bytes = read (outpipe, buf, 1024); | |||
| 687 | ||||
| 688 | if (bytes > 0) | |||
| 689 | gdk_pixbuf_loader_write (loader, buf, bytes, NULL((void*)0)); | |||
| 690 | if (bytes <= 0 || got_size) { | |||
| 691 | close (outpipe); | |||
| 692 | outpipe = -1; | |||
| 693 | gdk_pixbuf_loader_close (loader, NULL((void*)0)); | |||
| 694 | } | |||
| 695 | } | |||
| 696 | pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); | |||
| 697 | if (pixbuf) { | |||
| 698 | if (width) | |||
| 699 | *width = gdk_pixbuf_get_width (pixbuf); | |||
| 700 | if (height) | |||
| 701 | *height = gdk_pixbuf_get_height (pixbuf); | |||
| 702 | } | |||
| 703 | g_spawn_close_pid (child_pid); | |||
| 704 | g_object_unref (loader); | |||
| 705 | } else { | |||
| 706 | filename = g_build_filename (comics_document->dir, | |||
| 707 | (char *) comics_document->page_names->pdata[page->index], | |||
| 708 | NULL((void*)0)); | |||
| 709 | pixbuf = gdk_pixbuf_new_from_file (filename, NULL((void*)0)); | |||
| 710 | if (pixbuf) { | |||
| 711 | if (width) | |||
| 712 | *width = gdk_pixbuf_get_width (pixbuf); | |||
| 713 | if (height) | |||
| 714 | *height = gdk_pixbuf_get_height (pixbuf); | |||
| 715 | g_object_unref (pixbuf); | |||
| 716 | } | |||
| 717 | g_free (filename); | |||
| 718 | } | |||
| 719 | } | |||
| 720 | ||||
| 721 | static void | |||
| 722 | get_page_size_area_prepared_cb (GdkPixbufLoader *loader, | |||
| 723 | gpointer data) | |||
| 724 | { | |||
| 725 | gboolean *got_size = data; | |||
| 726 | *got_size = TRUE(!(0)); | |||
| 727 | } | |||
| 728 | ||||
| 729 | static GdkPixbuf * | |||
| 730 | comics_document_render_pixbuf (EvDocument *document, | |||
| 731 | EvRenderContext *rc) | |||
| 732 | { | |||
| 733 | GdkPixbufLoader *loader; | |||
| 734 | GdkPixbuf *rotated_pixbuf, *tmp_pixbuf; | |||
| 735 | char **argv; | |||
| 736 | guchar buf[4096]; | |||
| 737 | gboolean success; | |||
| 738 | gint outpipe = -1; | |||
| 739 | GPid child_pid; | |||
| 740 | gssize bytes; | |||
| 741 | gint width, height; | |||
| 742 | gchar *filename; | |||
| 743 | ComicsDocument *comics_document = COMICS_DOCUMENT (document)((((ComicsDocument*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((document)), ((comics_document_get_type ())))))); | |||
| 744 | ||||
| 745 | if (!comics_document->decompress_tmp) { | |||
| 746 | argv = extract_argv (document, rc->page->index); | |||
| 747 | success = g_spawn_async_with_pipes (NULL((void*)0), argv, NULL((void*)0), | |||
| 748 | G_SPAWN_SEARCH_PATH | | |||
| 749 | G_SPAWN_STDERR_TO_DEV_NULL, | |||
| 750 | NULL((void*)0), NULL((void*)0), | |||
| 751 | &child_pid, | |||
| 752 | NULL((void*)0), &outpipe, NULL((void*)0), NULL((void*)0)); | |||
| 753 | g_strfreev (argv); | |||
| 754 | g_return_val_if_fail (success == TRUE, NULL)do { if ((success == (!(0)))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "success == TRUE" ); return (((void*)0)); } } while (0); | |||
| 755 | ||||
| 756 | loader = gdk_pixbuf_loader_new (); | |||
| 757 | g_signal_connect (loader, "size-prepared",g_signal_connect_data ((loader), ("size-prepared"), (((GCallback ) (render_pixbuf_size_prepared_cb))), (&rc->scale), (( void*)0), (GConnectFlags) 0) | |||
| 758 | G_CALLBACK (render_pixbuf_size_prepared_cb),g_signal_connect_data ((loader), ("size-prepared"), (((GCallback ) (render_pixbuf_size_prepared_cb))), (&rc->scale), (( void*)0), (GConnectFlags) 0) | |||
| 759 | &rc->scale)g_signal_connect_data ((loader), ("size-prepared"), (((GCallback ) (render_pixbuf_size_prepared_cb))), (&rc->scale), (( void*)0), (GConnectFlags) 0); | |||
| 760 | ||||
| 761 | while (outpipe >= 0) { | |||
| 762 | bytes = read (outpipe, buf, 4096); | |||
| 763 | ||||
| 764 | if (bytes > 0) { | |||
| 765 | gdk_pixbuf_loader_write (loader, buf, bytes, | |||
| 766 | NULL((void*)0)); | |||
| 767 | } else if (bytes <= 0) { | |||
| 768 | close (outpipe); | |||
| 769 | gdk_pixbuf_loader_close (loader, NULL((void*)0)); | |||
| 770 | outpipe = -1; | |||
| 771 | } | |||
| 772 | } | |||
| 773 | tmp_pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); | |||
| 774 | rotated_pixbuf = | |||
| 775 | gdk_pixbuf_rotate_simple (tmp_pixbuf, | |||
| 776 | 360 - rc->rotation); | |||
| 777 | g_spawn_close_pid (child_pid); | |||
| 778 | g_object_unref (loader); | |||
| 779 | } else { | |||
| 780 | filename = | |||
| 781 | g_build_filename (comics_document->dir, | |||
| 782 | (char *) comics_document->page_names->pdata[rc->page->index], | |||
| 783 | NULL((void*)0)); | |||
| 784 | ||||
| 785 | gdk_pixbuf_get_file_info (filename, &width, &height); | |||
| 786 | ||||
| 787 | tmp_pixbuf = | |||
| 788 | gdk_pixbuf_new_from_file_at_size ( | |||
| 789 | filename, width * (rc->scale) + 0.5, | |||
| 790 | height * (rc->scale) + 0.5, NULL((void*)0)); | |||
| 791 | rotated_pixbuf = | |||
| 792 | gdk_pixbuf_rotate_simple (tmp_pixbuf, | |||
| 793 | 360 - rc->rotation); | |||
| 794 | g_free (filename); | |||
| 795 | g_object_unref (tmp_pixbuf); | |||
| 796 | } | |||
| 797 | return rotated_pixbuf; | |||
| 798 | } | |||
| 799 | ||||
| 800 | static cairo_surface_t * | |||
| 801 | comics_document_render (EvDocument *document, | |||
| 802 | EvRenderContext *rc) | |||
| 803 | { | |||
| 804 | GdkPixbuf *pixbuf; | |||
| 805 | cairo_surface_t *surface; | |||
| 806 | ||||
| 807 | pixbuf = comics_document_render_pixbuf (document, rc); | |||
| 808 | surface = ev_document_misc_surface_from_pixbuf (pixbuf); | |||
| 809 | g_object_unref (pixbuf); | |||
| 810 | ||||
| 811 | return surface; | |||
| 812 | } | |||
| 813 | ||||
| 814 | static void | |||
| 815 | render_pixbuf_size_prepared_cb (GdkPixbufLoader *loader, | |||
| 816 | gint width, | |||
| 817 | gint height, | |||
| 818 | gpointer data) | |||
| 819 | { | |||
| 820 | double *scale = data; | |||
| 821 | int w = (width * (*scale) + 0.5); | |||
| 822 | int h = (height * (*scale) + 0.5); | |||
| 823 | ||||
| 824 | gdk_pixbuf_loader_set_size (loader, w, h); | |||
| 825 | } | |||
| 826 | ||||
| 827 | /** | |||
| 828 | * comics_remove_dir: Removes a directory recursively. | |||
| 829 | * Returns: | |||
| 830 | * 0 if it was successfully deleted, | |||
| 831 | * -1 if an error occurred | |||
| 832 | */ | |||
| 833 | static int | |||
| 834 | comics_remove_dir (gchar *path_name) | |||
| 835 | { | |||
| 836 | GDir *content_dir; | |||
| 837 | const gchar *filename; | |||
| 838 | gchar *filename_with_path; | |||
| 839 | ||||
| 840 | if (g_file_test (path_name, G_FILE_TEST_IS_DIR)) { | |||
| 841 | content_dir = g_dir_open (path_name, 0, NULL((void*)0)); | |||
| 842 | filename = g_dir_read_name (content_dir); | |||
| 843 | while (filename) { | |||
| 844 | filename_with_path = | |||
| 845 | g_build_filename (path_name, | |||
| 846 | filename, NULL((void*)0)); | |||
| 847 | comics_remove_dir (filename_with_path); | |||
| 848 | g_free (filename_with_path); | |||
| 849 | filename = g_dir_read_name (content_dir); | |||
| 850 | } | |||
| 851 | g_dir_close (content_dir); | |||
| 852 | } | |||
| 853 | /* Note from g_remove() documentation: on Windows, it is in general not | |||
| 854 | * possible to remove a file that is open to some process, or mapped | |||
| 855 | * into memory.*/ | |||
| 856 | return (g_removeremove (path_name)); | |||
| 857 | } | |||
| 858 | ||||
| 859 | static void | |||
| 860 | comics_document_finalize (GObject *object) | |||
| 861 | { | |||
| 862 | ComicsDocument *comics_document = COMICS_DOCUMENT (object)((((ComicsDocument*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((object)), ((comics_document_get_type ())))))); | |||
| 863 | ||||
| 864 | if (comics_document->decompress_tmp) { | |||
| 865 | if (comics_remove_dir (comics_document->dir) == -1) | |||
| 866 | g_warning (_("There was an error deleting “%s”.")((char *) g_dgettext ("lector", "There was an error deleting “%s”." )), | |||
| 867 | comics_document->dir); | |||
| 868 | g_free (comics_document->dir); | |||
| 869 | } | |||
| 870 | ||||
| 871 | if (comics_document->page_names) { | |||
| 872 | g_ptr_array_foreach (comics_document->page_names, (GFunc) g_free, NULL((void*)0)); | |||
| 873 | g_ptr_array_free (comics_document->page_names, TRUE(!(0))); | |||
| 874 | } | |||
| 875 | ||||
| 876 | g_free (comics_document->archive); | |||
| 877 | g_free (comics_document->selected_command); | |||
| 878 | g_free (comics_document->alternative_command); | |||
| 879 | g_free (comics_document->extract_command); | |||
| 880 | g_free (comics_document->list_command); | |||
| 881 | ||||
| 882 | G_OBJECT_CLASS (comics_document_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass *) ((comics_document_parent_class)), (((GType) ((20) << (2))))))))->finalize (object); | |||
| 883 | } | |||
| 884 | ||||
| 885 | static void | |||
| 886 | comics_document_class_init (ComicsDocumentClass *klass) | |||
| 887 | { | |||
| 888 | GObjectClass *gobject_class = G_OBJECT_CLASS (klass)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass *) ((klass)), (((GType) ((20) << (2)))))))); | |||
| 889 | EvDocumentClass *ev_document_class = EV_DOCUMENT_CLASS (klass)((((EvDocumentClass*) (void *) g_type_check_class_cast ((GTypeClass *) ((klass)), ((ev_document_get_type ())))))); | |||
| 890 | ||||
| 891 | gobject_class->finalize = comics_document_finalize; | |||
| 892 | ||||
| 893 | ev_document_class->load = comics_document_load; | |||
| 894 | ev_document_class->save = comics_document_save; | |||
| 895 | ev_document_class->get_n_pages = comics_document_get_n_pages; | |||
| 896 | ev_document_class->get_page_size = comics_document_get_page_size; | |||
| 897 | ev_document_class->render = comics_document_render; | |||
| 898 | } | |||
| 899 | ||||
| 900 | static void | |||
| 901 | comics_document_init (ComicsDocument *comics_document) | |||
| 902 | { | |||
| 903 | comics_document->archive = NULL((void*)0); | |||
| 904 | comics_document->page_names = NULL((void*)0); | |||
| 905 | comics_document->extract_command = NULL((void*)0); | |||
| 906 | } | |||
| 907 | ||||
| 908 | /* Returns a list of file extensions supported by gdk-pixbuf */ | |||
| 909 | static GSList* | |||
| 910 | get_supported_image_extensions(void) | |||
| 911 | { | |||
| 912 | GSList *extensions = NULL((void*)0); | |||
| 913 | GSList *formats = gdk_pixbuf_get_formats (); | |||
| 914 | GSList *l; | |||
| 915 | ||||
| 916 | for (l = formats; l != NULL((void*)0); l = l->next) { | |||
| 917 | int i; | |||
| 918 | gchar **ext = gdk_pixbuf_format_get_extensions (l->data); | |||
| 919 | ||||
| 920 | for (i = 0; ext[i] != NULL((void*)0); i++) { | |||
| 921 | extensions = g_slist_append (extensions, | |||
| 922 | g_strdup (ext[i])g_strdup_inline (ext[i])); | |||
| 923 | } | |||
| 924 | ||||
| 925 | g_strfreev (ext); | |||
| 926 | } | |||
| 927 | ||||
| 928 | g_slist_free (formats); | |||
| 929 | return extensions; | |||
| 930 | } | |||
| 931 | ||||
| 932 | static GdkPixbuf * | |||
| 933 | comics_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document, | |||
| 934 | EvRenderContext *rc, | |||
| 935 | gboolean border) | |||
| 936 | { | |||
| 937 | GdkPixbuf *thumbnail; | |||
| 938 | ||||
| 939 | thumbnail = comics_document_render_pixbuf (EV_DOCUMENT (document)((((EvDocument*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((document)), ((ev_document_get_type ())))))), rc); | |||
| 940 | ||||
| 941 | if (border) { | |||
| 942 | GdkPixbuf *tmp_pixbuf = thumbnail; | |||
| 943 | ||||
| 944 | thumbnail = ev_document_misc_get_thumbnail_frame (-1, -1, tmp_pixbuf); | |||
| 945 | g_object_unref (tmp_pixbuf); | |||
| 946 | } | |||
| 947 | ||||
| 948 | return thumbnail; | |||
| 949 | } | |||
| 950 | ||||
| 951 | static void | |||
| 952 | comics_document_thumbnails_get_dimensions (EvDocumentThumbnails *document, | |||
| 953 | EvRenderContext *rc, | |||
| 954 | gint *width, | |||
| 955 | gint *height) | |||
| 956 | { | |||
| 957 | gdouble page_width, page_height; | |||
| ||||
| 958 | ||||
| 959 | comics_document_get_page_size (EV_DOCUMENT (document)((((EvDocument*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((document)), ((ev_document_get_type ())))))), rc->page, | |||
| 960 | &page_width, &page_height); | |||
| 961 | ||||
| 962 | if (rc->rotation == 90 || rc->rotation == 270) { | |||
| 963 | *width = (gint) (page_height * rc->scale); | |||
| 964 | *height = (gint) (page_width * rc->scale); | |||
| 965 | } else { | |||
| 966 | *width = (gint) (page_width * rc->scale); | |||
| ||||
| 967 | *height = (gint) (page_height * rc->scale); | |||
| 968 | } | |||
| 969 | } | |||
| 970 | ||||
| 971 | static void | |||
| 972 | comics_document_document_thumbnails_iface_init (EvDocumentThumbnailsInterface *iface) | |||
| 973 | { | |||
| 974 | iface->get_thumbnail = comics_document_thumbnails_get_thumbnail; | |||
| 975 | iface->get_dimensions = comics_document_thumbnails_get_dimensions; | |||
| 976 | } | |||
| 977 | ||||
| 978 | static char** | |||
| 979 | extract_argv (EvDocument *document, gint page) | |||
| 980 | { | |||
| 981 | ComicsDocument *comics_document = COMICS_DOCUMENT (document)((((ComicsDocument*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((document)), ((comics_document_get_type ())))))); | |||
| 982 | char **argv; | |||
| 983 | char *command_line, *quoted_archive, *quoted_filename; | |||
| 984 | GError *err = NULL((void*)0); | |||
| 985 | ||||
| 986 | if (g_strrstr (comics_document->page_names->pdata[page], "--checkpoint-action=")) | |||
| 987 | { | |||
| 988 | g_warning ("File unsupported\n"); | |||
| 989 | g_application_quit (g_application_get_default ()); | |||
| 990 | } | |||
| 991 | ||||
| 992 | if (page >= comics_document->page_names->len) | |||
| 993 | return NULL((void*)0); | |||
| 994 | ||||
| 995 | if (comics_document->regex_arg) { | |||
| 996 | quoted_archive = g_shell_quote (comics_document->archive); | |||
| 997 | quoted_filename = | |||
| 998 | comics_regex_quote (comics_document->page_names->pdata[page]); | |||
| 999 | } else { | |||
| 1000 | quoted_archive = g_shell_quote (comics_document->archive); | |||
| 1001 | quoted_filename = g_shell_quote (comics_document->page_names->pdata[page]); | |||
| 1002 | } | |||
| 1003 | ||||
| 1004 | command_line = g_strdup_printf ("%s %s %s", | |||
| 1005 | comics_document->extract_command, | |||
| 1006 | quoted_archive, | |||
| 1007 | quoted_filename); | |||
| 1008 | g_free (quoted_archive); | |||
| 1009 | g_free (quoted_filename); | |||
| 1010 | ||||
| 1011 | g_shell_parse_argv (command_line, NULL((void*)0), &argv, &err); | |||
| 1012 | g_free (command_line); | |||
| 1013 | ||||
| 1014 | if (err) { | |||
| 1015 | g_warning (_("Error %s")((char *) g_dgettext ("lector", "Error %s")), err->message); | |||
| 1016 | g_error_free (err); | |||
| 1017 | return NULL((void*)0); | |||
| 1018 | } | |||
| 1019 | ||||
| 1020 | return argv; | |||
| 1021 | } |