]> www.fi.muni.cz Git - evince.git/blobdiff - libdocument/ev-file-helpers.c
[printing] Fix multipage even/odd printing issues
[evince.git] / libdocument / ev-file-helpers.c
index 9bf2e463a9852872d92f61ecb8a777e451adfc2e..3da4a59832d5031bedac8c19a00c3ef62fc4686b 100644 (file)
 #include <glib.h>
 #include <glib/gstdio.h>
 #include <errno.h>
 #include <glib.h>
 #include <glib/gstdio.h>
 #include <errno.h>
-#include <libgnomevfs/gnome-vfs-uri.h>
-#include <libgnomevfs/gnome-vfs-utils.h>
-#include <libgnomevfs/gnome-vfs-ops.h>
-#include <libgnomevfs/gnome-vfs-xfer.h>
 
 #include "ev-file-helpers.h"
 
 
 #include "ev-file-helpers.h"
 
-static gchar *dot_dir = NULL;
 static gchar *tmp_dir = NULL;
 static gint   count = 0;
 
 static gchar *tmp_dir = NULL;
 static gint   count = 0;
 
-static gboolean
-ensure_dir_exists (const char *dir)
+gboolean
+ev_dir_ensure_exists (const gchar *dir,
+                      int          mode)
 {
 {
-       if (g_file_test (dir, G_FILE_TEST_IS_DIR))
-               return TRUE;
-       
-       if (g_mkdir (dir, 488) == 0)
+       if (g_mkdir_with_parents (dir, mode) == 0)
                return TRUE;
 
        if (errno == EEXIST)
                return g_file_test (dir, G_FILE_TEST_IS_DIR);
        
                return TRUE;
 
        if (errno == EEXIST)
                return g_file_test (dir, G_FILE_TEST_IS_DIR);
        
-       g_warning ("Failed to create directory %s: %s", dir, strerror (errno));
+       g_warning ("Failed to create directory %s: %s", dir, g_strerror (errno));
        return FALSE;
 }
 
        return FALSE;
 }
 
-const gchar *
-ev_dot_dir (void)
-{
-       if (dot_dir == NULL) {
-               gboolean exists;
-
-               dot_dir = g_build_filename (gnome_user_dir_get (),
-                                           "evince",
-                                           NULL);
-
-               exists = ensure_dir_exists (dot_dir);
-               if (!exists)
-                       exit (1);
-       }
-
-       return dot_dir;
-}
-
 const gchar *
 ev_tmp_dir (void)
 {
        if (tmp_dir == NULL) {
                gboolean exists;
 const gchar *
 ev_tmp_dir (void)
 {
        if (tmp_dir == NULL) {
                gboolean exists;
-               gchar   *dirname;
+               gchar   *dirname, *prgname;
 
 
-               dirname = g_strdup_printf ("evince-%u", getpid ());
+                prgname = g_get_prgname ();
+               dirname = g_strdup_printf ("%s-%u", prgname ? prgname : "unknown", getpid ());
                tmp_dir = g_build_filename (g_get_tmp_dir (),
                                            dirname,
                                            NULL);
                g_free (dirname);
 
                tmp_dir = g_build_filename (g_get_tmp_dir (),
                                            dirname,
                                            NULL);
                g_free (dirname);
 
-               exists = ensure_dir_exists (tmp_dir);
+               exists = ev_dir_ensure_exists (tmp_dir, 0700);
                g_assert (exists);
        }
 
                g_assert (exists);
        }
 
@@ -95,23 +71,34 @@ ev_tmp_dir (void)
 }
 
 void
 }
 
 void
-ev_file_helpers_init (void)
+_ev_file_helpers_init (void)
 {
 }
 
 void
 {
 }
 
 void
-ev_file_helpers_shutdown (void)
+_ev_file_helpers_shutdown (void)
 {      
        if (tmp_dir != NULL)    
                g_rmdir (tmp_dir);
 
        g_free (tmp_dir);
 {      
        if (tmp_dir != NULL)    
                g_rmdir (tmp_dir);
 
        g_free (tmp_dir);
-       g_free (dot_dir);
-
-       dot_dir = NULL;
        tmp_dir = NULL;
 }
 
        tmp_dir = NULL;
 }
 
+GFile *
+ev_tmp_file_get (const gchar *prefix)
+{
+       gchar *path;
+       GFile *file;
+
+       path = ev_tmp_filename (prefix);
+       file = g_file_new_for_path (path);
+       
+       g_free (path);
+       
+       return file;
+}
+
 gchar * 
 ev_tmp_filename (const gchar *prefix)
 {
 gchar * 
 ev_tmp_filename (const gchar *prefix)
 {
@@ -135,91 +122,259 @@ ev_tmp_filename (const gchar *prefix)
        return filename;
 }
 
        return filename;
 }
 
+gchar * 
+ev_tmp_directory (const gchar *prefix) 
+{
+       return ev_tmp_filename (prefix ? prefix : "directory");
+}
+
+/* Remove a local temp file created by evince */
+void
+ev_tmp_filename_unlink (const gchar *filename)
+{
+       const gchar *tempdir;
+       
+       if (!filename)
+               return;
+
+       tempdir = g_get_tmp_dir ();
+       if (g_ascii_strncasecmp (filename, tempdir, strlen (tempdir)) == 0) {
+               g_unlink (filename);
+       }
+}
+
+void
+ev_tmp_file_unlink (GFile *file)
+{
+       gboolean res;
+       GError  *error = NULL;
+
+       if (!file)
+               return;
+       
+       res = g_file_delete (file, NULL, &error);
+       if (!res) {
+               char *uri;
+               
+               uri = g_file_get_uri (file);
+               g_warning ("Unable to delete temp file %s: %s\n", uri, error->message);
+               g_free (uri);
+               g_error_free (error);
+       }
+}
+
+void
+ev_tmp_uri_unlink (const gchar *uri)
+{
+       GFile *file;
+       
+       if (!uri)
+               return;
+       
+       file = g_file_new_for_uri (uri);
+       if (!g_file_is_native (file)) {
+               g_warning ("Attempting to delete non native uri: %s\n", uri);
+               g_object_unref (file);
+               return;
+       }
+       
+       ev_tmp_file_unlink (file);
+       g_object_unref (file);
+}
+
+/**
+ * ev_xfer_uri_simple:
+ * @from: the source URI
+ * @to: the target URI
+ * @error: a #GError location to store an error, or %NULL
+ *
+ * Performs a g_file_copy() from @from to @to.
+ *
+ * Returns: %TRUE on success, or %FALSE on error with @error filled in
+ */
 gboolean
 ev_xfer_uri_simple (const char *from,
                    const char *to,
                    GError     **error)
 {
 gboolean
 ev_xfer_uri_simple (const char *from,
                    const char *to,
                    GError     **error)
 {
-       GnomeVFSResult result;
-       GnomeVFSURI *source_uri;
-       GnomeVFSURI *target_uri;
+       GFile *source_file;
+       GFile *target_file;
+       gboolean result;
        
        if (!from)
        
        if (!from)
-               return FALSE;
+               return TRUE;
+
+        g_return_val_if_fail (to != NULL, TRUE);
+
+       source_file = g_file_new_for_uri (from);
+       target_file = g_file_new_for_uri (to);
        
        
-       source_uri = gnome_vfs_uri_new (from);
-       target_uri = gnome_vfs_uri_new (to);
-
-       result = gnome_vfs_xfer_uri (source_uri, target_uri, 
-                                    GNOME_VFS_XFER_DEFAULT | GNOME_VFS_XFER_FOLLOW_LINKS,
-                                    GNOME_VFS_XFER_ERROR_MODE_ABORT,
-                                    GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE,
-                                    NULL,
-                                    NULL);
-       gnome_vfs_uri_unref (target_uri);
-       gnome_vfs_uri_unref (source_uri);
+       result = g_file_copy (source_file, target_file,
+#if GLIB_CHECK_VERSION(2,19,0)
+                             G_FILE_COPY_TARGET_DEFAULT_PERMS |
+#endif
+                             G_FILE_COPY_OVERWRITE,
+                             NULL, NULL, NULL, error);
+
+       g_object_unref (target_file);
+       g_object_unref (source_file);
     
     
-       if (result != GNOME_VFS_OK)
-               g_set_error (error,
-                            G_FILE_ERROR,
-                            G_FILE_ERROR_FAILED,
-                            gnome_vfs_result_to_string (result));
-       return (result == GNOME_VFS_OK);
+       return result;
+}
+
+static gchar *
+get_mime_type_from_uri (const gchar *uri, GError **error)
+{
+       GFile       *file;
+       GFileInfo   *file_info;
+       const gchar *content_type;
+        gchar       *mime_type = NULL;
+
+       file = g_file_new_for_uri (uri);
+       file_info = g_file_query_info (file,
+                                      G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+                                      0, NULL, error);
+       g_object_unref (file);
+
+       if (file_info == NULL)
+               return NULL;
+
+       content_type = g_file_info_get_content_type (file_info);
+       if (content_type) {
+                mime_type = g_content_type_get_mime_type (content_type);
+        }
+
+       g_object_unref (file_info);
+       return mime_type;
+}
+
+static gchar *
+get_mime_type_from_data (const gchar *uri, GError **error)
+{
+       GFile            *file;
+       GFileInputStream *input_stream;
+       gssize            size_read;
+       guchar            buffer[1024];
+       gboolean          retval;
+       gchar            *content_type, *mime_type;
+
+       file = g_file_new_for_uri (uri);
+       
+       input_stream = g_file_read (file, NULL, error);
+       if (!input_stream) {
+               g_object_unref (file);
+               return NULL;
+       }
+
+       size_read = g_input_stream_read (G_INPUT_STREAM (input_stream),
+                                        buffer, sizeof (buffer), NULL, error);
+       if (size_read == -1) {
+               g_object_unref (input_stream);
+               g_object_unref (file);
+               return NULL;
+       }
+
+       retval = g_input_stream_close (G_INPUT_STREAM (input_stream), NULL, error);
+
+       g_object_unref (input_stream);
+       g_object_unref (file);
+       if (!retval)
+               return NULL;
 
 
+       content_type = g_content_type_guess (NULL, /* no filename */
+                                            buffer, size_read,
+                                            NULL);
+       if (!content_type)
+               return NULL;
+
+       mime_type = g_content_type_get_mime_type (content_type);
+       g_free (content_type);
+       return mime_type;
+}
+
+/**
+ * ev_file_get_mime_type:
+ * @uri: the URI
+ * @fast: whether to use fast MIME type detection
+ * @error: a #GError location to store an error, or %NULL
+ *
+ * Note: on unknown MIME types, this may return NULL without @error
+ * being filled in.
+ * 
+ * Returns: a newly allocated string with the MIME type of the file at
+ *   @uri, or %NULL on error or if the MIME type could not be determined
+ */
+gchar *
+ev_file_get_mime_type (const gchar *uri,
+                      gboolean     fast,
+                      GError     **error)
+{
+       return fast ? get_mime_type_from_uri (uri, error) : get_mime_type_from_data (uri, error);
 }
 
 /* Compressed files support */
 #define BZIPCOMMAND "bzip2"
 #define GZIPCOMMAND "gzip"
 }
 
 /* Compressed files support */
 #define BZIPCOMMAND "bzip2"
 #define GZIPCOMMAND "gzip"
-#define N_ARGS      5
+#define N_ARGS      4
 #define BUFFER_SIZE 1024
 
 #define BUFFER_SIZE 1024
 
-gchar *
-ev_file_uncompress (const gchar       *uri,
-                   EvCompressionType  type,
-                   GError           **error)
+static gchar *
+compression_run (const gchar       *uri,
+                EvCompressionType  type,
+                gboolean           compress, 
+                GError           **error)
 {
        gchar *argv[N_ARGS];
 {
        gchar *argv[N_ARGS];
-       gchar *uri_unc = NULL;
-       gchar *filename, *filename_unc;
+       gchar *uri_dst = NULL;
+       gchar *filename, *filename_dst;
        gchar *cmd;
        gint   fd, pout;
        gchar *cmd;
        gint   fd, pout;
-
-       g_return_val_if_fail (uri != NULL, NULL);
+       GError *err = NULL;
 
        if (type == EV_COMPRESSION_NONE)
                return NULL;
 
        cmd = g_find_program_in_path ((type == EV_COMPRESSION_BZIP2) ? BZIPCOMMAND : GZIPCOMMAND);
 
        if (type == EV_COMPRESSION_NONE)
                return NULL;
 
        cmd = g_find_program_in_path ((type == EV_COMPRESSION_BZIP2) ? BZIPCOMMAND : GZIPCOMMAND);
-       if (!cmd)
+       if (!cmd) {
+               /* FIXME: better error codes! */
+               /* FIXME: i18n later */
+               g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+                            "Failed to find the \"%s\" command in the search path.",
+                            type == EV_COMPRESSION_BZIP2 ? BZIPCOMMAND : GZIPCOMMAND);
                return NULL;
                return NULL;
+       }
 
 
-
-       filename = g_filename_from_uri (uri, NULL, NULL);
+       filename = g_filename_from_uri (uri, NULL, error);
        if (!filename) {
                g_free (cmd);
                return NULL;
        }
        
        if (!filename) {
                g_free (cmd);
                return NULL;
        }
        
-       filename_unc = g_build_filename (ev_tmp_dir (), "evinceXXXXXX", NULL);
-       fd = g_mkstemp (filename_unc);
+       filename_dst = g_build_filename (ev_tmp_dir (), "evinceXXXXXX", NULL);
+       fd = g_mkstemp (filename_dst);
        if (fd < 0) {
        if (fd < 0) {
+               int errsv = errno;
+
                g_free (cmd);
                g_free (filename);
                g_free (cmd);
                g_free (filename);
-               g_free (filename_unc);
+               g_free (filename_dst);
+
+               g_set_error (error, G_IO_ERROR,
+                            g_io_error_from_errno (errsv),
+                            "Error creating a temporary file: %s",
+                            g_strerror (errsv));
                return NULL;
        }
                return NULL;
        }
-       
+
        argv[0] = cmd;
        argv[0] = cmd;
-       argv[1] = "-cd";
+       argv[1] = compress ? "-c" : "-cd";
        argv[2] = filename;
        argv[2] = filename;
-       argv[3] = filename_unc;
-       argv[4] = NULL;
+       argv[3] = NULL;
 
        if (g_spawn_async_with_pipes (NULL, argv, NULL,
                                      G_SPAWN_STDERR_TO_DEV_NULL,
                                      NULL, NULL, NULL,
 
        if (g_spawn_async_with_pipes (NULL, argv, NULL,
                                      G_SPAWN_STDERR_TO_DEV_NULL,
                                      NULL, NULL, NULL,
-                                     NULL, &pout, NULL, error)) {
+                                     NULL, &pout, NULL, &err)) {
                GIOChannel *in, *out;
                gchar buf[BUFFER_SIZE];
                GIOStatus read_st, write_st;
                GIOChannel *in, *out;
                gchar buf[BUFFER_SIZE];
                GIOStatus read_st, write_st;
@@ -246,21 +401,79 @@ ev_file_uncompress (const gchar       *uri,
                                break;
                        }
                } while (bytes_read > 0);
                                break;
                        }
                } while (bytes_read > 0);
-               
+
                g_io_channel_unref (in);
                g_io_channel_unref (out);
        }
 
        close (fd);
 
                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);
+       if (err) {
+               g_propagate_error (error, err);
+       } else {
+               uri_dst = g_filename_to_uri (filename_dst, NULL, error);
        }
 
        g_free (cmd);
        g_free (filename);
        }
 
        g_free (cmd);
        g_free (filename);
-       g_free (filename_unc);
+       g_free (filename_dst);
+
+       return uri_dst;
+}
+
+/**
+ * ev_file_uncompress:
+ * @uri: a file URI
+ * @type: the compression type
+ * @error: a #GError location to store an error, or %NULL
+ *
+ * Uncompresses the file at @uri.
+ *
+ * If @type is %EV_COMPRESSION_NONE, it does nothing and returns %NULL.
+ *
+ * Otherwise, it returns the filename of a
+ * temporary file containing the decompressed data from the file at @uri.
+ * On error it returns %NULL and fills in @error.
+ *
+ * It is the caller's responsibility to unlink the temp file after use.
+ *
+ * Returns: a newly allocated string URI, or %NULL on error
+ */
+gchar *
+ev_file_uncompress (const gchar       *uri,
+                   EvCompressionType  type,
+                   GError           **error)
+{
+       g_return_val_if_fail (uri != NULL, NULL);
+
+       return compression_run (uri, type, FALSE, error);
+}
+
+/**
+ * ev_file_compress:
+ * @uri: a file URI
+ * @type: the compression type
+ * @error: a #GError location to store an error, or %NULL
+ *
+ * Compresses the file at @uri.
+ * If @type is %EV_COMPRESSION_NONE, it does nothing and returns %NULL.
+ *
+ * Otherwise, it returns the filename of a
+ * temporary file containing the compressed data from the file at @uri.
+ *
+ * On error it returns %NULL and fills in @error.
+ *
+ * It is the caller's responsibility to unlink the temp file after use.
+ *
+ * Returns: a newly allocated string URI, or %NULL on error
+ */
+gchar *
+ev_file_compress (const gchar       *uri,
+                 EvCompressionType  type,
+                 GError           **error)
+{
+       g_return_val_if_fail (uri != NULL, NULL);
 
 
-       return uri_unc;
+       return compression_run (uri, type, TRUE, error);
 }
 }