]> www.fi.muni.cz Git - evince.git/blob - libdocument/ev-document-factory.c
21e0b4a9a8f29401d6fbc655c1ea87eac44f4a4e
[evince.git] / libdocument / ev-document-factory.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
2 /*
3  *  Copyright (C) 2005, Red Hat, Inc. 
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  *
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <string.h>
26 #include <glib/gstdio.h>
27 #include <glib/gi18n.h>
28 #include <libgnomevfs/gnome-vfs-mime-utils.h>
29 #include <libgnomevfs/gnome-vfs-file-info.h>
30 #include <libgnomevfs/gnome-vfs-ops.h>
31 #include <gtk/gtkfilechooserdialog.h>
32
33 #include "ev-backends-manager.h"
34 #include "ev-document-factory.h"
35 #include "ev-file-helpers.h"
36
37 #ifdef ENABLE_PIXBUF
38 static GList*
39 gdk_pixbuf_mime_type_list ()
40 {
41         GSList *formats, *list;
42         GList *result = NULL;
43
44         formats = gdk_pixbuf_get_formats ();
45         for (list = formats; list != NULL; list = list->next) {
46                 GdkPixbufFormat *format = list->data;
47                 gchar          **mime_types;
48
49                 if (gdk_pixbuf_format_is_disabled (format))
50                         continue;
51
52                 mime_types = gdk_pixbuf_format_get_mime_types (format);
53                 result = g_list_prepend (result, mime_types); 
54         }
55         g_slist_free (formats);
56
57         return result;
58 }
59
60 /* Would be nice to have this in gdk-pixbuf */
61 static gboolean
62 mime_type_supported_by_gdk_pixbuf (const gchar *mime_type)
63 {
64         GList *mime_types;
65         GList *list;
66         gboolean retval = FALSE;
67
68         mime_types = gdk_pixbuf_mime_type_list ();
69         for (list = mime_types; list; list = list->next) {
70                 gchar      **mtypes = (gchar **)list->data;
71                 const gchar *mtype;
72                 gint         i = 0;
73
74                 while ((mtype = mtypes[i++])) {
75                         if (strcmp (mtype, mime_type) == 0) {
76                                 retval = TRUE;
77                                 break;
78                         }
79                 }
80         }
81
82         g_list_foreach (mime_types, (GFunc)g_strfreev, NULL);
83         g_list_free (mime_types);
84
85         return retval;
86 }
87 #endif /* ENABLE_PIXBUF */
88
89 static EvCompressionType
90 get_compression_from_mime_type (const gchar *mime_type)
91 {
92         gchar type[3];
93         gchar *p;
94
95         if (!(p = g_strrstr (mime_type, "/")))
96                 return EV_COMPRESSION_NONE;
97
98         if (sscanf (++p, "x-%2s%*s", type) == 1) {
99                 if (g_ascii_strcasecmp (type, "gz") == 0)
100                         return EV_COMPRESSION_GZIP;
101                 else if (g_ascii_strcasecmp (type, "bz") == 0)
102                         return EV_COMPRESSION_BZIP2;
103         }
104
105         return EV_COMPRESSION_NONE;
106 }
107
108 static EvDocument *
109 get_document_from_uri (const char        *uri,
110                        gboolean           slow,
111                        EvCompressionType *compression,
112                        GError           **error)
113 {
114         EvDocument *document = NULL;
115         GnomeVFSFileInfo *info;
116         GnomeVFSResult result;
117
118         *compression = EV_COMPRESSION_NONE;
119
120         info = gnome_vfs_file_info_new ();
121         result = gnome_vfs_get_file_info (uri, info,
122                                           GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
123                                           GNOME_VFS_FILE_INFO_FOLLOW_LINKS | 
124                                           (slow ? GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE : 0));
125         if (result != GNOME_VFS_OK) {
126                 g_set_error (error,
127                              EV_DOCUMENT_ERROR,
128                              0,
129                              gnome_vfs_result_to_string (result));                      
130                 gnome_vfs_file_info_unref (info);
131                 return NULL;
132         } 
133         
134         if (info->mime_type == NULL) {
135                 g_set_error (error,
136                              EV_DOCUMENT_ERROR, 
137                              0,
138                              _("Unknown MIME Type"));
139                 gnome_vfs_file_info_unref (info);
140                 return NULL;
141         }
142
143 #ifdef ENABLE_PIXBUF
144         if (mime_type_supported_by_gdk_pixbuf (info->mime_type)) {
145                 document = ev_backends_manager_get_document ("image/*");
146         } else
147                 document = ev_backends_manager_get_document (info->mime_type);
148 #else
149         document = ev_backends_manager_get_document (info->mime_type);
150 #endif /* ENABLE_PIXBUF */
151
152         if (document == NULL) {
153                 g_set_error (error,
154                              EV_DOCUMENT_ERROR, 
155                              0,
156                              _("Unhandled MIME type: ā€œ%sā€"), info->mime_type);
157                 gnome_vfs_file_info_unref (info);
158                 return NULL;
159         }
160
161         *compression = get_compression_from_mime_type (info->mime_type);
162
163         gnome_vfs_file_info_unref (info);
164         
165         return document;
166 }
167
168 static void
169 free_uncompressed_uri (gchar *uri_unc)
170 {
171         if (!uri_unc)
172                 return;
173
174         ev_tmp_uri_unlink (uri_unc);
175         g_free (uri_unc);
176 }
177
178 EvDocument *
179 ev_document_factory_get_document (const char *uri, GError **error)
180 {
181         EvDocument *document;
182         int result;
183         EvCompressionType compression;
184         gchar *uri_unc = NULL;
185
186         document = get_document_from_uri (uri, FALSE, &compression, error);
187         if (*error == NULL) {
188                 uri_unc = ev_file_uncompress (uri, compression, error);
189                 if (uri_unc) {
190                         g_object_set_data_full (G_OBJECT (document),
191                                                 "uri-uncompressed",
192                                                 uri_unc,
193                                                 (GDestroyNotify) free_uncompressed_uri);
194                 }
195
196                 if (*error != NULL) {
197                         /* Error uncompressing file */
198                         if (document)
199                                 g_object_unref (document);
200                         return NULL;
201                 }
202
203                 result = ev_document_load (document, uri_unc ? uri_unc : uri, error);
204
205                 if (result == FALSE || *error) {
206                         if (*error &&
207                             (*error)->domain == EV_DOCUMENT_ERROR &&
208                             (*error)->code == EV_DOCUMENT_ERROR_ENCRYPTED)
209                                 return document;
210                 } else {
211                         return document;
212                 }
213         }
214         
215         /* Try again with slow mime detection */
216         if (document)
217                 g_object_unref (document);
218         document = NULL;
219
220         if (*error)
221                 g_error_free (*error);
222         *error = NULL;
223
224         uri_unc = NULL;
225
226         document = get_document_from_uri (uri, TRUE, &compression, error);
227
228         if (*error != NULL) {
229                 return NULL;
230         }
231
232         uri_unc = ev_file_uncompress (uri, compression, error);
233         if (uri_unc) {
234                 g_object_set_data_full (G_OBJECT (document),
235                                         "uri-uncompressed",
236                                         uri_unc,
237                                         (GDestroyNotify) free_uncompressed_uri);
238         }
239
240         if (*error != NULL) {
241                 /* Error uncompressing file */
242                 if (document)
243                         g_object_unref (document);
244                 return NULL;
245         }
246         
247         result = ev_document_load (document, uri_unc ? uri_unc : uri, error);
248
249         if (result == FALSE) {
250                 if (*error == NULL) {
251                         g_set_error (error,
252                                      EV_DOCUMENT_ERROR,
253                                      0,
254                                      _("Unknown MIME Type"));
255                 } else if ((*error)->domain == EV_DOCUMENT_ERROR &&
256                            (*error)->code == EV_DOCUMENT_ERROR_ENCRYPTED) {
257                         return document;
258                 }
259
260                 if (document)
261                         g_object_unref (document);
262                 document = NULL;
263         }
264         
265         return document;
266 }
267
268 static void
269 file_filter_add_mime_types (EvTypeInfo *info, GtkFileFilter *filter)
270 {
271         const gchar *mime_type;
272         gint         i = 0;
273
274 #ifdef ENABLE_PIXBUF
275         if (g_ascii_strcasecmp (info->mime_types[0], "image/*") == 0) {
276                 GList *pixbuf_types, *l;
277
278                 pixbuf_types = gdk_pixbuf_mime_type_list ();
279                 for (l = pixbuf_types; l; l = g_list_next (l)) {
280                         gchar **mime_types = (gchar **)l->data;
281                         gint    j = 0;
282                         
283                         while ((mime_type = mime_types[j++]))
284                                 gtk_file_filter_add_mime_type (filter, mime_type);
285                         
286                         g_strfreev (mime_types);
287                 }
288                 g_list_free (pixbuf_types);
289
290                 return;
291         }
292 #endif /* ENABLE_PIXBUF */
293         
294         while ((mime_type = info->mime_types[i++]))
295                 gtk_file_filter_add_mime_type (filter, mime_type);
296 }
297
298 void 
299 ev_document_factory_add_filters (GtkWidget *chooser, EvDocument *document)
300 {
301         GList         *all_types;
302         GtkFileFilter *filter;
303         GtkFileFilter *default_filter;
304         GtkFileFilter *document_filter;
305
306         all_types = ev_backends_manager_get_all_types_info ();
307         
308         default_filter = document_filter = filter = gtk_file_filter_new ();
309         gtk_file_filter_set_name (filter, _("All Documents"));
310         g_list_foreach (all_types, (GFunc)file_filter_add_mime_types, filter);
311         gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
312
313         if (document) {
314                 EvTypeInfo *info;
315
316                 info = ev_backends_manager_get_document_type_info (document);
317                 default_filter = filter = gtk_file_filter_new ();
318                 gtk_file_filter_set_name (filter, info->desc);
319                 file_filter_add_mime_types (info, filter);
320                 g_free (info);
321                 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
322         } else {
323                 GList *l;
324
325                 for (l = all_types; l; l = g_list_next (l)){
326                         EvTypeInfo *info;
327
328                         info = (EvTypeInfo *)l->data;
329
330                         default_filter = filter = gtk_file_filter_new ();
331                         gtk_file_filter_set_name (filter, info->desc);
332                         file_filter_add_mime_types (info, filter);
333                         gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
334                 }
335         }
336
337         g_list_foreach (all_types, (GFunc)g_free, NULL);
338         g_list_free (all_types);
339
340         filter = gtk_file_filter_new ();
341         gtk_file_filter_set_name (filter, _("All Files"));
342         gtk_file_filter_add_pattern (filter, "*");
343         gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
344
345         gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (chooser),
346                                      document == NULL ? document_filter : default_filter);
347 }