1
0
mirror of https://gitlab.gnome.org/GNOME/evince synced 2024-06-30 22:54:23 +00:00
evince/libdocument/ev-attachment.c
Pablo Correa Gómez 273511ac39
libdocument: simplify freeing memory by better exploiting glib functions
Mostly g_clear_object and g_clear_pointer. But also some small
simplifications depending on the context.
2023-03-24 09:58:48 +01:00

459 lines
11 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* this file is part of evince, a gnome document viewer
*
* Copyright (C) 2006 Carlos Garcia Campos <carlosgc@gnome.org>
*
* Evince is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Evince is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <config.h>
#include <glib/gi18n-lib.h>
#include <glib/gstdio.h>
#include <gtk/gtk.h>
#include "ev-file-helpers.h"
#include "ev-attachment.h"
enum
{
PROP_0,
PROP_NAME,
PROP_DESCRIPTION,
PROP_MTIME,
PROP_CTIME,
PROP_SIZE,
PROP_DATA
};
typedef struct {
gchar *name;
gchar *description;
GTime mtime;
GTime ctime;
gsize size;
gchar *data;
gchar *mime_type;
GAppInfo *app;
GFile *tmp_file;
} EvAttachmentPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (EvAttachment, ev_attachment, G_TYPE_OBJECT)
#define GET_PRIVATE(o) ev_attachment_get_instance_private (o);
GQuark
ev_attachment_error_quark (void)
{
static GQuark error_quark = 0;
if (error_quark == 0)
error_quark =
g_quark_from_static_string ("ev-attachment-error-quark");
return error_quark;
}
static void
ev_attachment_finalize (GObject *object)
{
EvAttachment *attachment = EV_ATTACHMENT (object);
EvAttachmentPrivate *priv = GET_PRIVATE (attachment);
g_clear_pointer (&priv->name, g_free);
g_clear_pointer (&priv->description, g_free);
g_clear_pointer (&priv->data, g_free);
g_clear_pointer (&priv->mime_type, g_free);
g_clear_object (&priv->app);
if (priv->tmp_file) {
ev_tmp_file_unlink (priv->tmp_file);
g_clear_object (&priv->tmp_file);
}
G_OBJECT_CLASS (ev_attachment_parent_class)->finalize (object);
}
static void
ev_attachment_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *param_spec)
{
EvAttachment *attachment = EV_ATTACHMENT (object);
EvAttachmentPrivate *priv = GET_PRIVATE (attachment);
switch (prop_id) {
case PROP_NAME:
priv->name = g_value_dup_string (value);
break;
case PROP_DESCRIPTION:
priv->description = g_value_dup_string (value);
break;
case PROP_MTIME:
priv->mtime = g_value_get_ulong (value);
break;
case PROP_CTIME:
priv->ctime = g_value_get_ulong (value);
break;
case PROP_SIZE:
priv->size = g_value_get_uint (value);
break;
case PROP_DATA:
priv->data = g_value_get_pointer (value);
priv->mime_type = g_content_type_guess (priv->name,
(guchar *) priv->data,
priv->size,
NULL);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object,
prop_id,
param_spec);
break;
}
}
static void
ev_attachment_class_init (EvAttachmentClass *klass)
{
GObjectClass *g_object_class;
g_object_class = G_OBJECT_CLASS (klass);
g_object_class->set_property = ev_attachment_set_property;
/* Properties */
g_object_class_install_property (g_object_class,
PROP_NAME,
g_param_spec_string ("name",
"Name",
"The attachment name",
NULL,
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (g_object_class,
PROP_DESCRIPTION,
g_param_spec_string ("description",
"Description",
"The attachment description",
NULL,
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (g_object_class,
PROP_MTIME,
g_param_spec_ulong ("mtime",
"ModifiedTime",
"The attachment modification date",
0, G_MAXULONG, 0,
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (g_object_class,
PROP_CTIME,
g_param_spec_ulong ("ctime",
"CreationTime",
"The attachment creation date",
0, G_MAXULONG, 0,
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (g_object_class,
PROP_SIZE,
g_param_spec_uint ("size",
"Size",
"The attachment size",
0, G_MAXUINT, 0,
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (g_object_class,
PROP_DATA,
g_param_spec_pointer ("data",
"Data",
"The attachment data",
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class->finalize = ev_attachment_finalize;
}
static void
ev_attachment_init (EvAttachment *attachment)
{
EvAttachmentPrivate *priv = GET_PRIVATE (attachment);
priv->name = NULL;
priv->description = NULL;
priv->data = NULL;
priv->mime_type = NULL;
priv->tmp_file = NULL;
}
EvAttachment *
ev_attachment_new (const gchar *name,
const gchar *description,
GTime mtime,
GTime ctime,
gsize size,
gpointer data)
{
EvAttachment *attachment;
attachment = g_object_new (EV_TYPE_ATTACHMENT,
"name", name,
"description", description,
"mtime", mtime,
"ctime", ctime,
"size", size,
"data", data,
NULL);
return attachment;
}
const gchar *
ev_attachment_get_name (EvAttachment *attachment)
{
EvAttachmentPrivate *priv;
g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), NULL);
priv = GET_PRIVATE (attachment);
return priv->name;
}
const gchar *
ev_attachment_get_description (EvAttachment *attachment)
{
EvAttachmentPrivate *priv;
g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), NULL);
priv = GET_PRIVATE (attachment);
return priv->description;
}
GTime
ev_attachment_get_modification_date (EvAttachment *attachment)
{
EvAttachmentPrivate *priv;
g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), 0);
priv = GET_PRIVATE (attachment);
return priv->mtime;
}
GTime
ev_attachment_get_creation_date (EvAttachment *attachment)
{
EvAttachmentPrivate *priv;
g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), 0);
priv = GET_PRIVATE (attachment);
return priv->ctime;
}
const gchar *
ev_attachment_get_mime_type (EvAttachment *attachment)
{
EvAttachmentPrivate *priv;
g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), NULL);
priv = GET_PRIVATE (attachment);
return priv->mime_type;
}
gboolean
ev_attachment_save (EvAttachment *attachment,
GFile *file,
GError **error)
{
GFileOutputStream *output_stream;
GError *ioerror = NULL;
gssize written_bytes;
EvAttachmentPrivate *priv = GET_PRIVATE (attachment);
g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), FALSE);
g_return_val_if_fail (G_IS_FILE (file), FALSE);
output_stream = g_file_replace (file, NULL, FALSE, 0, NULL, &ioerror);
if (output_stream == NULL) {
char *uri;
uri = g_file_get_uri (file);
g_set_error (error,
EV_ATTACHMENT_ERROR,
ioerror->code,
_("Couldnt save attachment “%s”: %s"),
uri,
ioerror->message);
g_error_free (ioerror);
g_free (uri);
return FALSE;
}
written_bytes = g_output_stream_write (G_OUTPUT_STREAM (output_stream),
priv->data,
priv->size,
NULL, &ioerror);
if (written_bytes == -1) {
char *uri;
uri = g_file_get_uri (file);
g_set_error (error,
EV_ATTACHMENT_ERROR,
ioerror->code,
_("Couldnt save attachment “%s”: %s"),
uri,
ioerror->message);
g_output_stream_close (G_OUTPUT_STREAM (output_stream), NULL, NULL);
g_error_free (ioerror);
g_free (uri);
return FALSE;
}
g_output_stream_close (G_OUTPUT_STREAM (output_stream), NULL, NULL);
return TRUE;
}
static gboolean
ev_attachment_launch_app (EvAttachment *attachment,
GdkDisplay *display,
guint32 timestamp,
GError **error)
{
gboolean result;
GList *files = NULL;
GdkAppLaunchContext *context;
GError *ioerror = NULL;
EvAttachmentPrivate *priv = GET_PRIVATE (attachment);
g_assert (G_IS_FILE (priv->tmp_file));
g_assert (G_IS_APP_INFO (priv->app));
files = g_list_prepend (files, priv->tmp_file);
display = display ?: gdk_display_get_default ();
context = gdk_display_get_app_launch_context (display);
gdk_app_launch_context_set_timestamp (context, timestamp);
result = g_app_info_launch (priv->app, files,
G_APP_LAUNCH_CONTEXT (context),
&ioerror);
g_object_unref (context);
if (!result) {
g_set_error (error,
EV_ATTACHMENT_ERROR,
(gint) result,
_("Couldnt open attachment “%s”: %s"),
priv->name,
ioerror->message);
g_list_free (files);
g_error_free (ioerror);
return FALSE;
}
g_list_free (files);
return TRUE;
}
gboolean
ev_attachment_open (EvAttachment *attachment,
GdkScreen *screen,
guint32 timestamp,
GError **error)
{
GAppInfo *app_info;
gboolean retval = FALSE;
EvAttachmentPrivate *priv;
GdkDisplay *display = gdk_screen_get_display (screen);
g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), FALSE);
priv = GET_PRIVATE (attachment);
if (!priv->app) {
app_info = g_app_info_get_default_for_type (priv->mime_type, FALSE);
priv->app = app_info;
}
if (!priv->app) {
g_set_error (error,
EV_ATTACHMENT_ERROR,
0,
_("Couldnt open attachment “%s”"),
priv->name);
return FALSE;
}
if (priv->tmp_file) {
retval = ev_attachment_launch_app (attachment, display,
timestamp, error);
} else {
char *basename;
char *temp_dir;
char *file_path;
GFile *file;
/* FIXMEchpe: convert to filename encoding first!
* Store the file inside a temporary XXXXXX subdirectory to
* keep the filename "as is".
*/
basename = g_path_get_basename (ev_attachment_get_name (attachment));
temp_dir = g_dir_make_tmp ("evince.XXXXXX", error);
file_path = g_build_filename (temp_dir, basename, NULL);
file = g_file_new_for_path (file_path);
g_free (temp_dir);
g_free (file_path);
g_free (basename);
if (file != NULL && ev_attachment_save (attachment, file, error)) {
if (priv->tmp_file)
g_object_unref (priv->tmp_file);
priv->tmp_file = g_object_ref (file);
retval = ev_attachment_launch_app (attachment, display,
timestamp, error);
}
g_object_unref (file);
}
return retval;
}