]> www.fi.muni.cz Git - evince.git/blob - libdocument/ev-document-factory.c
a920be60bcfe06e2a051866700212b29160a7639
[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
27 #include <gio/gio.h>
28 #include <glib/gstdio.h>
29 #include <glib/gi18n.h>
30 #include <gtk/gtkfilechooserdialog.h>
31
32 #include "ev-backends-manager.h"
33 #include "ev-document-factory.h"
34 #include "ev-file-helpers.h"
35
36 #ifdef ENABLE_PIXBUF
37 static GList*
38 gdk_pixbuf_mime_type_list ()
39 {
40         GSList *formats, *list;
41         GList *result = NULL;
42
43         formats = gdk_pixbuf_get_formats ();
44         for (list = formats; list != NULL; list = list->next) {
45                 GdkPixbufFormat *format = list->data;
46                 gchar          **mime_types;
47
48                 if (gdk_pixbuf_format_is_disabled (format))
49                         continue;
50
51                 mime_types = gdk_pixbuf_format_get_mime_types (format);
52                 result = g_list_prepend (result, mime_types); 
53         }
54         g_slist_free (formats);
55
56         return result;
57 }
58
59 /* Would be nice to have this in gdk-pixbuf */
60 static gboolean
61 mime_type_supported_by_gdk_pixbuf (const gchar *mime_type)
62 {
63         GList *mime_types;
64         GList *list;
65         gboolean retval = FALSE;
66
67         mime_types = gdk_pixbuf_mime_type_list ();
68         for (list = mime_types; list; list = list->next) {
69                 gchar      **mtypes = (gchar **)list->data;
70                 const gchar *mtype;
71                 gint         i = 0;
72
73                 while ((mtype = mtypes[i++])) {
74                         if (strcmp (mtype, mime_type) == 0) {
75                                 retval = TRUE;
76                                 break;
77                         }
78                 }
79         }
80
81         g_list_foreach (mime_types, (GFunc)g_strfreev, NULL);
82         g_list_free (mime_types);
83
84         return retval;
85 }
86 #endif /* ENABLE_PIXBUF */
87
88 static EvCompressionType
89 get_compression_from_mime_type (const gchar *mime_type)
90 {
91         gchar type[3];
92         gchar *p;
93
94         if (!(p = g_strrstr (mime_type, "/")))
95                 return EV_COMPRESSION_NONE;
96
97         if (sscanf (++p, "x-%2s%*s", type) == 1) {
98                 if (g_ascii_strcasecmp (type, "gz") == 0)
99                         return EV_COMPRESSION_GZIP;
100                 else if (g_ascii_strcasecmp (type, "bz") == 0)
101                         return EV_COMPRESSION_BZIP2;
102         }
103
104         return EV_COMPRESSION_NONE;
105 }
106
107 static gchar *
108 get_mime_type_from_uri (const gchar *uri, GError **error)
109 {
110         GFile     *file;
111         GFileInfo *file_info;
112         gchar     *mime_type;
113
114         file = g_file_new_for_uri (uri);
115         file_info = g_file_query_info (file,
116                                        G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
117                                        0, NULL, error);
118         g_object_unref (file);
119
120         if (file_info == NULL)
121                 return NULL;
122
123         mime_type = g_strdup (g_file_info_get_content_type (file_info));
124         g_object_unref (file_info);
125
126         return mime_type;
127 }
128
129 static gchar *
130 get_mime_type_from_data (const gchar *uri, GError **error)
131 {
132         GFile            *file;
133         GFileInputStream *input_stream;
134         gssize            size_read;
135         guchar            buffer[1024];
136
137         file = g_file_new_for_uri (uri);
138         
139         input_stream = g_file_read (file, NULL, error);
140         if (!input_stream) {
141                 g_object_unref (file);
142                 return NULL;
143         }
144
145         size_read = g_input_stream_read (G_INPUT_STREAM (input_stream),
146                                          buffer, 1024, NULL, NULL);
147         g_input_stream_close (G_INPUT_STREAM (input_stream), NULL, error);
148
149         g_object_unref (file);
150
151         if (size_read == -1)
152                 return NULL;
153
154         return g_content_type_guess (NULL, /* no filename */
155                                      buffer, 1024,
156                                      NULL);
157 }
158
159 static EvDocument *
160 get_document_from_uri (const char        *uri,
161                        gboolean           slow,
162                        EvCompressionType *compression,
163                        GError           **error)
164 {
165         EvDocument *document = NULL;
166         gchar      *mime_type = NULL;
167
168         *compression = EV_COMPRESSION_NONE;
169
170         mime_type = slow ?
171                 get_mime_type_from_data (uri, error) :
172                 get_mime_type_from_uri (uri, error);
173
174         if (mime_type == NULL) {
175                 g_free (mime_type);
176
177                 if (*error == NULL) {
178                         g_set_error (error,
179                                      EV_DOCUMENT_ERROR,
180                                      0,
181                                      _("Unknown MIME Type"));
182                 }
183                 
184                 return NULL;
185         }
186
187         document = ev_backends_manager_get_document (mime_type);
188         
189 #ifdef ENABLE_PIXBUF
190         if (!document && mime_type_supported_by_gdk_pixbuf (mime_type))
191                 document = ev_backends_manager_get_document ("image/*");
192 #endif /* ENABLE_PIXBUF */
193
194         if (document == NULL) {
195                 gchar *mime_desc;
196
197                 mime_desc = g_content_type_get_description (mime_type);
198                 g_set_error (error,
199                              EV_DOCUMENT_ERROR, 
200                              0,
201                              _("File type %s (%s) is not supported"),
202                              mime_desc, mime_type);
203                 g_free (mime_desc);
204                 g_free (mime_type);
205
206                 return NULL;
207         }
208
209         *compression = get_compression_from_mime_type (mime_type);
210
211         g_free (mime_type);
212         
213         return document;
214 }
215
216 static void
217 free_uncompressed_uri (gchar *uri_unc)
218 {
219         if (!uri_unc)
220                 return;
221
222         ev_tmp_uri_unlink (uri_unc);
223         g_free (uri_unc);
224 }
225
226 EvDocument *
227 ev_document_factory_get_document (const char *uri, GError **error)
228 {
229         EvDocument *document;
230         int result;
231         EvCompressionType compression;
232         gchar *uri_unc = NULL;
233
234         document = get_document_from_uri (uri, FALSE, &compression, error);
235         if (*error == NULL) {
236                 uri_unc = ev_file_uncompress (uri, compression, error);
237                 if (uri_unc) {
238                         g_object_set_data_full (G_OBJECT (document),
239                                                 "uri-uncompressed",
240                                                 uri_unc,
241                                                 (GDestroyNotify) free_uncompressed_uri);
242                 }
243
244                 if (*error != NULL) {
245                         /* Error uncompressing file */
246                         if (document)
247                                 g_object_unref (document);
248                         return NULL;
249                 }
250
251                 result = ev_document_load (document, uri_unc ? uri_unc : uri, error);
252
253                 if (result == FALSE || *error) {
254                         if (*error &&
255                             (*error)->domain == EV_DOCUMENT_ERROR &&
256                             (*error)->code == EV_DOCUMENT_ERROR_ENCRYPTED)
257                                 return document;
258                 } else {
259                         return document;
260                 }
261         }
262         
263         /* Try again with slow mime detection */
264         if (document)
265                 g_object_unref (document);
266         document = NULL;
267
268         if (*error)
269                 g_error_free (*error);
270         *error = NULL;
271
272         uri_unc = NULL;
273
274         document = get_document_from_uri (uri, TRUE, &compression, error);
275
276         if (*error != NULL) {
277                 return NULL;
278         }
279
280         uri_unc = ev_file_uncompress (uri, compression, error);
281         if (uri_unc) {
282                 g_object_set_data_full (G_OBJECT (document),
283                                         "uri-uncompressed",
284                                         uri_unc,
285                                         (GDestroyNotify) free_uncompressed_uri);
286         }
287
288         if (*error != NULL) {
289                 /* Error uncompressing file */
290                 if (document)
291                         g_object_unref (document);
292                 return NULL;
293         }
294         
295         result = ev_document_load (document, uri_unc ? uri_unc : uri, error);
296
297         if (result == FALSE) {
298                 if (*error == NULL) {
299                         g_set_error (error,
300                                      EV_DOCUMENT_ERROR,
301                                      0,
302                                      _("Unknown MIME Type"));
303                 } else if ((*error)->domain == EV_DOCUMENT_ERROR &&
304                            (*error)->code == EV_DOCUMENT_ERROR_ENCRYPTED) {
305                         return document;
306                 }
307
308                 if (document)
309                         g_object_unref (document);
310                 document = NULL;
311         }
312         
313         return document;
314 }
315
316 static void
317 file_filter_add_mime_types (EvTypeInfo *info, GtkFileFilter *filter)
318 {
319         const gchar *mime_type;
320         gint         i = 0;
321
322 #ifdef ENABLE_PIXBUF
323         if (g_ascii_strcasecmp (info->mime_types[0], "image/*") == 0) {
324                 GList *pixbuf_types, *l;
325
326                 pixbuf_types = gdk_pixbuf_mime_type_list ();
327                 for (l = pixbuf_types; l; l = g_list_next (l)) {
328                         gchar **mime_types = (gchar **)l->data;
329                         gint    j = 0;
330                         
331                         while ((mime_type = mime_types[j++]))
332                                 gtk_file_filter_add_mime_type (filter, mime_type);
333                         
334                         g_strfreev (mime_types);
335                 }
336                 g_list_free (pixbuf_types);
337
338                 return;
339         }
340 #endif /* ENABLE_PIXBUF */
341         
342         while ((mime_type = info->mime_types[i++]))
343                 gtk_file_filter_add_mime_type (filter, mime_type);
344 }
345
346 void 
347 ev_document_factory_add_filters (GtkWidget *chooser, EvDocument *document)
348 {
349         GList         *all_types;
350         GtkFileFilter *filter;
351         GtkFileFilter *default_filter;
352         GtkFileFilter *document_filter;
353
354         all_types = ev_backends_manager_get_all_types_info ();
355         
356         default_filter = document_filter = filter = gtk_file_filter_new ();
357         gtk_file_filter_set_name (filter, _("All Documents"));
358         g_list_foreach (all_types, (GFunc)file_filter_add_mime_types, filter);
359         gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
360
361         if (document) {
362                 EvTypeInfo *info;
363
364                 info = ev_backends_manager_get_document_type_info (document);
365                 default_filter = filter = gtk_file_filter_new ();
366                 gtk_file_filter_set_name (filter, info->desc);
367                 file_filter_add_mime_types (info, filter);
368                 g_free (info);
369                 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
370         } else {
371                 GList *l;
372
373                 for (l = all_types; l; l = g_list_next (l)){
374                         EvTypeInfo *info;
375
376                         info = (EvTypeInfo *)l->data;
377
378                         default_filter = filter = gtk_file_filter_new ();
379                         gtk_file_filter_set_name (filter, info->desc);
380                         file_filter_add_mime_types (info, filter);
381                         gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
382                 }
383         }
384
385         g_list_foreach (all_types, (GFunc)g_free, NULL);
386         g_list_free (all_types);
387
388         filter = gtk_file_filter_new ();
389         gtk_file_filter_set_name (filter, _("All Files"));
390         gtk_file_filter_add_pattern (filter, "*");
391         gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
392
393         gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (chooser),
394                                      document == NULL ? document_filter : default_filter);
395 }