From b346c5664d27a77e9068ea91eaf9a0c0d6210b0f Mon Sep 17 00:00:00 2001 From: Carlos Garcia Campos Date: Sat, 3 Feb 2007 19:02:28 +0000 Subject: [PATCH] Support for PDF, PS and EPS compressed files. Fixes bug #307087. 2007-02-03 Carlos Garcia Campos * configure.ac: * backend/ps/ps-document.c: (ps_document_init), (ps_document_dispose), (ps_interpreter_start), (document_load), (save_document), (save_page_list): * libdocument/ev-file-helpers.[ch]: (ev_file_uncompress): * libdocument/ev-document-factory.c: (ev_document_factory_get_from_mime), (get_document_from_uri), (free_uncompressed_uri), (ev_document_factory_get_document): * shell/ev-window.c: (ev_window_cmd_file_open_copy_at_dest): Support for PDF, PS and EPS compressed files. Fixes bug #307087. svn path=/trunk/; revision=2291 --- ChangeLog | 14 ++++ backend/ps/ps-document.c | 117 ++--------------------------- configure.ac | 4 +- libdocument/ev-document-factory.c | 119 +++++++++++++++++++++++------- libdocument/ev-file-helpers.c | 97 ++++++++++++++++++++++++ libdocument/ev-file-helpers.h | 18 ++++- shell/ev-window.c | 12 +-- 7 files changed, 232 insertions(+), 149 deletions(-) diff --git a/ChangeLog b/ChangeLog index bf1defbb..93575795 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2007-02-03 Carlos Garcia Campos + + * configure.ac: + * backend/ps/ps-document.c: (ps_document_init), (ps_document_dispose), + (ps_interpreter_start), (document_load), (save_document), + (save_page_list): + * libdocument/ev-file-helpers.[ch]: (ev_file_uncompress): + * libdocument/ev-document-factory.c: + (ev_document_factory_get_from_mime), (get_document_from_uri), + (free_uncompressed_uri), (ev_document_factory_get_document): + * shell/ev-window.c: (ev_window_cmd_file_open_copy_at_dest): + + Support for PDF, PS and EPS compressed files. Fixes bug #307087. + 2007-02-03 Carlos Garcia Campos * libdocument/ev-document.h: diff --git a/backend/ps/ps-document.c b/backend/ps/ps-document.c index 1e448e38..0ce2dfc6 100644 --- a/backend/ps/ps-document.c +++ b/backend/ps/ps-document.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include "ps-document.h" @@ -45,11 +44,6 @@ #define MAX_BUFSIZE 1024 -#define PS_DOCUMENT_IS_COMPRESSED(gs) (PS_DOCUMENT(gs)->gs_filename_unc != NULL) -#define PS_DOCUMENT_GET_PS_FILE(gs) (PS_DOCUMENT_IS_COMPRESSED(gs) ? \ - PS_DOCUMENT(gs)->gs_filename_unc : \ - PS_DOCUMENT(gs)->gs_filename) - /* structure to describe section of file to send to ghostscript */ typedef struct { FILE *fp; @@ -85,7 +79,6 @@ struct _PSDocument { FILE *gs_psfile; /* the currently loaded FILE */ gchar *gs_filename; /* the currently loaded filename */ - gchar *gs_filename_unc; /* Uncompressed file */ gchar *input_buffer; gboolean send_filename_to_gs; /* True if gs should read from file directly */ struct document *doc; @@ -148,8 +141,7 @@ ps_document_init (PSDocument *gs) gs->interpreter_pid = -1; gs->busy = FALSE; - gs->gs_filename = 0; - gs->gs_filename_unc = 0; + gs->gs_filename = NULL; gs->structured_doc = FALSE; gs->send_filename_to_gs = FALSE; @@ -195,12 +187,6 @@ ps_document_dispose (GObject *object) gs->doc = NULL; } - if (gs->gs_filename_unc) { - g_unlink(gs->gs_filename_unc); - g_free(gs->gs_filename_unc); - gs->gs_filename_unc = NULL; - } - if (gs->bpixmap) { g_object_unref (gs->bpixmap); gs->bpixmap = NULL; @@ -479,7 +465,7 @@ ps_interpreter_start (PSDocument *gs) argv[argc++] = "-dSAFER"; if (gs->send_filename_to_gs) { - argv[argc++] = PS_DOCUMENT_GET_PS_FILE (gs); + argv[argc++] = gs->gs_filename; argv[argc++] = "-c"; argv[argc++] = "quit"; } else { @@ -614,96 +600,9 @@ ps_interpreter_is_ready (PSDocument *gs) } /* EvDocumentIface */ -/* - * Decompress gs->gs_filename if necessary - * Set gs->filename_unc to the name of the uncompressed file or NULL. - * Error reporting via signal 'interpreter_message' - * Return name of input file to use or NULL on error.. - */ -static const gchar * -check_filecompressed (PSDocument * gs) -{ - FILE *file; - gchar buf[1024]; - gchar *filename, *filename_unc, *filename_err, *cmdline; - const gchar *cmd; - int fd; - - cmd = NULL; - - if ((file = fopen(gs->gs_filename, "r")) && - (fread (buf, sizeof(gchar), 3, file) == 3)) { - if ((buf[0] == '\037') && ((buf[1] == '\235') || (buf[1] == '\213'))) { - /* file is gzipped or compressed */ - cmd = gtk_gs_defaults_get_ungzip_cmd (); - } else if (strncmp (buf, "BZh", 3) == 0) { - /* file is compressed with bzip2 */ - cmd = gtk_gs_defaults_get_unbzip2_cmd (); - } - } - - if (NULL != file) - fclose(file); - - if (!cmd) - return gs->gs_filename; - - /* do the decompression */ - filename = g_shell_quote (gs->gs_filename); - filename_unc = g_strconcat (g_get_tmp_dir (), "/evinceXXXXXX", NULL); - if ((fd = g_mkstemp (filename_unc)) < 0) { - g_free (filename_unc); - g_free (filename); - return NULL; - } - close (fd); - - filename_err = g_strconcat (g_get_tmp_dir (), "/evinceXXXXXX", NULL); - if ((fd = g_mkstemp (filename_err)) < 0) { - g_free (filename_err); - g_free (filename_unc); - g_free (filename); - return NULL; - } - close (fd); - - cmdline = g_strdup_printf ("%s %s >%s 2>%s", cmd, - filename, filename_unc, filename_err); - - if (system (cmdline) == 0 && - g_file_test (filename_unc, G_FILE_TEST_IS_REGULAR)) { - /* sucessfully uncompressed file */ - gs->gs_filename_unc = filename_unc; - } else { - gchar *filename_dsp; - gchar *msg; - - /* report error */ - filename_dsp = g_filename_display_name (gs->gs_filename); - msg = g_strdup_printf (_("Error while decompressing file “%s”:\n"), - filename_dsp); - g_free (filename_dsp); - - ps_interpreter_failed (gs, msg); - g_free (msg); - g_unlink (filename_unc); - g_free (filename_unc); - filename_unc = NULL; - } - - g_unlink (filename_err); - g_free (filename_err); - g_free (cmdline); - g_free (filename); - - return filename_unc; -} - static gboolean document_load (PSDocument *gs, const gchar *fname) { - const gchar *filename; - if (fname == NULL) { gs->gs_status = ""; return FALSE; @@ -733,15 +632,13 @@ document_load (PSDocument *gs, const gchar *fname) return FALSE; } - filename = check_filecompressed (gs); - - if (!filename || (gs->gs_psfile = fopen (filename, "r")) == NULL) { + if (!gs->gs_filename || (gs->gs_psfile = fopen (gs->gs_filename, "r")) == NULL) { ps_interpreter_failed (gs, NULL); return FALSE; } /* we grab the vital statistics!!! */ - gs->doc = psscan (gs->gs_psfile, TRUE, filename); + gs->doc = psscan (gs->gs_psfile, TRUE, gs->gs_filename); if ((!gs->doc->epsf && gs->doc->numpages > 0) || (gs->doc->epsf && gs->doc->numpages > 1)) { @@ -809,11 +706,11 @@ save_document (PSDocument *document, const char *filename) FILE *f, *src_file; gchar *buf; - src_file = fopen (PS_DOCUMENT_GET_PS_FILE(document), "r"); + src_file = fopen (document->gs_filename, "r"); if (src_file) { struct stat stat_rec; - if (stat (PS_DOCUMENT_GET_PS_FILE(document), &stat_rec) == 0) { + if (stat (document->gs_filename, &stat_rec) == 0) { pscopy (src_file, sink, 0, stat_rec.st_size - 1); } @@ -848,7 +745,7 @@ save_page_list (PSDocument *document, int *page_list, const char *filename) FILE *f; gchar *buf; - pscopydoc (sink, PS_DOCUMENT_GET_PS_FILE(document), + pscopydoc (sink, document->gs_filename, document->doc, page_list); buf = gtk_gs_doc_sink_get_buffer (sink); diff --git a/configure.ac b/configure.ac index f13c52c9..360d51e4 100644 --- a/configure.ac +++ b/configure.ac @@ -381,10 +381,10 @@ dnl ================== End of impress book checks ============================== dnl =================== Mime types list ==================================================== if test "x$enable_pdf" = "xyes" ; then - EVINCE_MIME_TYPES="application/pdf" + EVINCE_MIME_TYPES="application/pdf;application/x-bzpdf;application/x-gzpdf" fi if test "x$enable_ps" = "xyes" ; then - EVINCE_MIME_TYPES="$EVINCE_MIME_TYPES;application/postscript;application/x-gzpostscript" + EVINCE_MIME_TYPES="$EVINCE_MIME_TYPES;application/postscript;application/x-gzpostscript;application/x-gzpostscript;image/x-eps;image/x-bzeps;image/x-gzeps" fi if test "x$enable_dvi" = "xyes"; then EVINCE_MIME_TYPES="$EVINCE_MIME_TYPES;application/x-dvi" diff --git a/libdocument/ev-document-factory.c b/libdocument/ev-document-factory.c index 348cb80b..4adec667 100644 --- a/libdocument/ev-document-factory.c +++ b/libdocument/ev-document-factory.c @@ -51,16 +51,19 @@ #endif #include +#include #include #include #include #include #include +#include "ev-file-helpers.h" + typedef struct _EvDocumentType EvDocumentType; -struct _EvDocumentType -{ +struct _EvDocumentType { const char *mime_type; + EvCompressionType compression; EvBackend backend; GType (*document_type_factory_callback)(); }; @@ -68,41 +71,46 @@ struct _EvDocumentType const EvDocumentType document_types[] = { #ifdef ENABLE_PDF /* PDF: */ - {"application/pdf", EV_BACKEND_PDF, pdf_document_get_type}, + {"application/pdf", EV_COMPRESSION_NONE, EV_BACKEND_PDF, pdf_document_get_type}, + {"application/x-bzpdf", EV_COMPRESSION_BZIP2, EV_BACKEND_PDF, pdf_document_get_type}, + {"application/x-gzpdf", EV_COMPRESSION_GZIP, EV_BACKEND_PDF, pdf_document_get_type}, #endif #ifdef ENABLE_PS /* Postscript: */ - {"application/postscript", EV_BACKEND_PS, ps_document_get_type}, - {"application/x-gzpostscript", EV_BACKEND_PS, ps_document_get_type}, - {"image/x-eps", EV_BACKEND_PS, ps_document_get_type}, + {"application/postscript", EV_COMPRESSION_NONE, EV_BACKEND_PS, ps_document_get_type}, + {"application/x-bzpostscript", EV_COMPRESSION_BZIP2, EV_BACKEND_PS, ps_document_get_type}, + {"application/x-gzpostscript", EV_COMPRESSION_GZIP, EV_BACKEND_PS, ps_document_get_type}, + {"image/x-eps", EV_COMPRESSION_NONE, EV_BACKEND_PS, ps_document_get_type}, + {"image/x-bzeps", EV_COMPRESSION_BZIP2, EV_BACKEND_PS, ps_document_get_type}, + {"image/x-gzeps", EV_COMPRESSION_GZIP, EV_BACKEND_PS, ps_document_get_type}, #endif #ifdef ENABLE_TIFF /* Tiff: */ - {"image/tiff", EV_BACKEND_TIFF, tiff_document_get_type}, + {"image/tiff", EV_COMPRESSION_NONE, EV_BACKEND_TIFF, tiff_document_get_type}, #endif #ifdef ENABLE_DJVU /* djvu: */ - {"image/vnd.djvu", EV_BACKEND_DJVU, djvu_document_get_type}, + {"image/vnd.djvu", EV_COMPRESSION_NONE, EV_BACKEND_DJVU, djvu_document_get_type}, #endif #ifdef ENABLE_DVI /* dvi: */ - {"application/x-dvi", EV_BACKEND_DVI, dvi_document_get_type}, + {"application/x-dvi", EV_COMPRESSION_NONE, EV_BACKEND_DVI, dvi_document_get_type}, #endif #ifdef ENABLE_COMICS /* cbr/cbz: */ - {"application/x-cbr", EV_BACKEND_COMICS, comics_document_get_type}, - {"application/x-cbz", EV_BACKEND_COMICS, comics_document_get_type}, + {"application/x-cbr", EV_COMPRESSION_NONE, EV_BACKEND_COMICS, comics_document_get_type}, + {"application/x-cbz", EV_COMPRESSION_NONE, EV_BACKEND_COMICS, comics_document_get_type}, #endif #ifdef ENABLE_IMPRESS /* Impress slides: */ - {"application/vnd.sun.xml.impress", EV_BACKEND_IMPRESS, impress_document_get_type}, - {"application/vnd.oasis.opendocument.presentation", EV_BACKEND_IMPRESS, impress_document_get_type}, + {"application/vnd.sun.xml.impress", EV_COMPRESSION_NONE, EV_BACKEND_IMPRESS, impress_document_get_type}, + {"application/vnd.oasis.opendocument.presentation", EV_COMPRESSION_NONE, EV_BACKEND_IMPRESS, impress_document_get_type}, #endif }; @@ -160,19 +168,21 @@ mime_type_supported_by_gdk_pixbuf (const gchar *mime_type) } #endif -static EvDocument* -ev_document_factory_get_from_mime (const char *mime_type) +static EvDocument * +ev_document_factory_get_from_mime (const gchar *mime_type, + EvCompressionType *compression) { int i; GType type = G_TYPE_INVALID; EvDocument *document = NULL; - - g_return_val_if_fail (mime_type, G_TYPE_INVALID); + *compression = EV_COMPRESSION_NONE; + for (i = 0; i < G_N_ELEMENTS (document_types); i++) { if (strcmp (mime_type, document_types[i].mime_type) == 0) { g_assert (document_types[i].document_type_factory_callback != NULL); - type = document_types[i].document_type_factory_callback(); + type = document_types[i].document_type_factory_callback (); + *compression = document_types[i].compression; break; } } @@ -181,6 +191,7 @@ ev_document_factory_get_from_mime (const char *mime_type) type = pixbuf_document_get_type (); } #endif + if (type != G_TYPE_INVALID) { document = g_object_new (type, NULL); } @@ -248,13 +259,17 @@ ev_document_factory_get_all_mime_types (void) } static EvDocument * -get_document_from_uri (const char *uri, gboolean slow, GError **error) +get_document_from_uri (const char *uri, + gboolean slow, + EvCompressionType *compression, + GError **error) { EvDocument *document = NULL; - GnomeVFSFileInfo *info; GnomeVFSResult result; + *compression = EV_COMPRESSION_NONE; + info = gnome_vfs_file_info_new (); result = gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE | @@ -278,7 +293,7 @@ get_document_from_uri (const char *uri, gboolean slow, GError **error) return NULL; } - document = ev_document_factory_get_from_mime (info->mime_type); + document = ev_document_factory_get_from_mime (info->mime_type, compression); if (document == NULL) { g_set_error (error, @@ -287,23 +302,56 @@ get_document_from_uri (const char *uri, gboolean slow, GError **error) _("Unhandled MIME type: “%s”"), info->mime_type); gnome_vfs_file_info_unref (info); return NULL; - } + } gnome_vfs_file_info_unref (info); return document; } +static void +free_uncompressed_uri (gchar *uri_unc) +{ + gchar *filename; + + if (!uri_unc) + return; + + filename = g_filename_from_uri (uri_unc, NULL, NULL); + if (!filename) + return; + + g_unlink (filename); + g_free (filename); + g_free (uri_unc); +} + EvDocument * ev_document_factory_get_document (const char *uri, GError **error) { EvDocument *document; int result; + EvCompressionType compression; + gchar *uri_unc = NULL; - document = get_document_from_uri (uri, FALSE, error); - + document = get_document_from_uri (uri, FALSE, &compression, error); if (*error == NULL) { - result = ev_document_load (document, uri, error); + uri_unc = ev_file_uncompress (uri, compression, error); + if (uri_unc) { + g_object_set_data_full (G_OBJECT (document), + "uri-uncompressed", + uri_unc, + (GDestroyNotify) free_uncompressed_uri); + } + + if (*error != NULL) { + /* Error uncompressing file */ + if (document) + g_object_unref (document); + return NULL; + } + + result = ev_document_load (document, uri_unc ? uri_unc : uri, error); if (result == FALSE || *error) { if (*error && @@ -324,13 +372,30 @@ ev_document_factory_get_document (const char *uri, GError **error) g_error_free (*error); *error = NULL; - document = get_document_from_uri (uri, TRUE, error); + uri_unc = NULL; + + document = get_document_from_uri (uri, TRUE, &compression, error); if (*error != NULL) { return NULL; } - result = ev_document_load (document, uri, error); + uri_unc = ev_file_uncompress (uri, compression, error); + if (uri_unc) { + g_object_set_data_full (G_OBJECT (document), + "uri-uncompressed", + uri_unc, + (GDestroyNotify) free_uncompressed_uri); + } + + if (*error != NULL) { + /* Error uncompressing file */ + if (document) + g_object_unref (document); + return NULL; + } + + result = ev_document_load (document, uri_unc ? uri_unc : uri, error); if (result == FALSE) { if (*error == NULL) { diff --git a/libdocument/ev-file-helpers.c b/libdocument/ev-file-helpers.c index b6a50b6f..9bf2e463 100644 --- a/libdocument/ev-file-helpers.c +++ b/libdocument/ev-file-helpers.c @@ -167,3 +167,100 @@ ev_xfer_uri_simple (const char *from, return (result == GNOME_VFS_OK); } + +/* Compressed files support */ +#define BZIPCOMMAND "bzip2" +#define GZIPCOMMAND "gzip" +#define N_ARGS 5 +#define BUFFER_SIZE 1024 + +gchar * +ev_file_uncompress (const gchar *uri, + EvCompressionType type, + GError **error) +{ + gchar *argv[N_ARGS]; + gchar *uri_unc = NULL; + gchar *filename, *filename_unc; + gchar *cmd; + gint fd, pout; + + g_return_val_if_fail (uri != NULL, NULL); + + if (type == EV_COMPRESSION_NONE) + return NULL; + + cmd = g_find_program_in_path ((type == EV_COMPRESSION_BZIP2) ? BZIPCOMMAND : GZIPCOMMAND); + if (!cmd) + return NULL; + + + filename = g_filename_from_uri (uri, NULL, NULL); + if (!filename) { + g_free (cmd); + return NULL; + } + + filename_unc = g_build_filename (ev_tmp_dir (), "evinceXXXXXX", NULL); + fd = g_mkstemp (filename_unc); + if (fd < 0) { + g_free (cmd); + g_free (filename); + g_free (filename_unc); + return NULL; + } + + argv[0] = cmd; + argv[1] = "-cd"; + argv[2] = filename; + argv[3] = filename_unc; + argv[4] = NULL; + + if (g_spawn_async_with_pipes (NULL, argv, NULL, + G_SPAWN_STDERR_TO_DEV_NULL, + NULL, NULL, NULL, + NULL, &pout, NULL, error)) { + GIOChannel *in, *out; + gchar buf[BUFFER_SIZE]; + GIOStatus read_st, write_st; + gsize bytes_read, bytes_written; + + in = g_io_channel_unix_new (pout); + g_io_channel_set_encoding (in, NULL, NULL); + out = g_io_channel_unix_new (fd); + g_io_channel_set_encoding (out, NULL, NULL); + + do { + read_st = g_io_channel_read_chars (in, buf, + BUFFER_SIZE, + &bytes_read, + error); + if (read_st == G_IO_STATUS_NORMAL) { + write_st = g_io_channel_write_chars (out, buf, + bytes_read, + &bytes_written, + error); + if (write_st == G_IO_STATUS_ERROR) + break; + } else if (read_st == G_IO_STATUS_ERROR) { + break; + } + } while (bytes_read > 0); + + g_io_channel_unref (in); + g_io_channel_unref (out); + } + + close (fd); + + if (*error == NULL) { + uri_unc = g_filename_to_uri (filename_unc, + NULL, NULL); + } + + g_free (cmd); + g_free (filename); + g_free (filename_unc); + + return uri_unc; +} diff --git a/libdocument/ev-file-helpers.h b/libdocument/ev-file-helpers.h index 4e75a14c..945573d5 100644 --- a/libdocument/ev-file-helpers.h +++ b/libdocument/ev-file-helpers.h @@ -25,6 +25,12 @@ G_BEGIN_DECLS +typedef enum { + EV_COMPRESSION_NONE, + EV_COMPRESSION_BZIP2, + EV_COMPRESSION_GZIP +} EvCompressionType; + const gchar *ev_dot_dir (void); const gchar *ev_tmp_dir (void); @@ -33,11 +39,15 @@ void ev_file_helpers_init (void); void ev_file_helpers_shutdown (void); -gchar* ev_tmp_filename (const char *prefix); +gchar *ev_tmp_filename (const char *prefix); + +gboolean ev_xfer_uri_simple (const char *from, + const char *to, + GError **error); +gchar *ev_file_uncompress (const gchar *uri, + EvCompressionType type, + GError **error); -gboolean ev_xfer_uri_simple (const char *from, - const char *to, - GError **error); G_END_DECLS diff --git a/shell/ev-window.c b/shell/ev-window.c index 7cd803d3..1a964f84 100644 --- a/shell/ev-window.c +++ b/shell/ev-window.c @@ -1502,8 +1502,12 @@ ev_window_cmd_file_open_copy_at_dest (EvWindow *window, EvLinkDest *dest) gchar *symlink_uri; gchar *old_filename; gchar *new_filename; + gchar *uri_unc; - old_filename = g_filename_from_uri (window->priv->uri, NULL, NULL); + uri_unc = g_object_get_data (G_OBJECT (window->priv->document), + "uri-uncompressed"); + old_filename = g_filename_from_uri (uri_unc ? uri_unc : window->priv->uri, + NULL, NULL); new_filename = ev_window_create_tmp_symlink (old_filename, &error); if (error) { @@ -3133,14 +3137,10 @@ ev_window_cmd_go_backward (GtkAction *action, EvWindow *ev_window) static void ev_window_cmd_view_reload (GtkAction *action, EvWindow *ev_window) { - char *uri; - - g_return_if_fail (EV_IS_WINDOW (ev_window)); + gchar *uri; uri = g_strdup (ev_window->priv->uri); - ev_window_open_uri (ev_window, uri, NULL, 0, FALSE); - g_free (uri); } -- 2.43.5