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 | } |