+2007-02-03 Carlos Garcia Campos <carlosgc@gnome.org>
+
+ * 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 <carlosgc@gnome.org>
* libdocument/ev-document.h:
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
-#include <unistd.h>
#include <errno.h>
#include "ps-document.h"
#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;
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;
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;
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;
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 {
}
/* 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;
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)) {
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);
}
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);
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"
#endif
#include <string.h>
+#include <glib/gstdio.h>
#include <glib/gi18n.h>
#include <libgnomevfs/gnome-vfs-mime-utils.h>
#include <libgnomevfs/gnome-vfs-file-info.h>
#include <libgnomevfs/gnome-vfs-ops.h>
#include <gtk/gtkfilechooserdialog.h>
+#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)();
};
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
};
}
#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;
}
}
type = pixbuf_document_get_type ();
}
#endif
+
if (type != G_TYPE_INVALID) {
document = g_object_new (type, NULL);
}
}
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 |
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,
_("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 &&
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) {
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;
+}
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);
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
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) {
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);
}