blob: 874bffb7abc8c740296526a8b3c5e191a6f31134 [file] [log] [blame]
/* poppler-attachment.cc: glib wrapper for poppler
* Copyright (C) 2006, Red Hat, Inc.
*
* This program 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, or (at your option)
* any later version.
*
* This program 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 <errno.h>
#include <glib/gstdio.h>
#include "poppler.h"
#include "poppler-private.h"
/**
* SECTION:poppler-attachment
* @short_description: Attachments
* @title: PopplerAttachment
*/
/* FIXME: We need to add gettext support sometime */
#define _(x) (x)
typedef struct _PopplerAttachmentPrivate PopplerAttachmentPrivate;
struct _PopplerAttachmentPrivate
{
Object *obj_stream;
};
#define POPPLER_ATTACHMENT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), POPPLER_TYPE_ATTACHMENT, PopplerAttachmentPrivate))
static void poppler_attachment_dispose (GObject *obj);
static void poppler_attachment_finalize (GObject *obj);
G_DEFINE_TYPE (PopplerAttachment, poppler_attachment, G_TYPE_OBJECT)
static void
poppler_attachment_init (PopplerAttachment *attachment)
{
}
static void
poppler_attachment_class_init (PopplerAttachmentClass *klass)
{
G_OBJECT_CLASS (klass)->dispose = poppler_attachment_dispose;
G_OBJECT_CLASS (klass)->finalize = poppler_attachment_finalize;
g_type_class_add_private (klass, sizeof (PopplerAttachmentPrivate));
}
static void
poppler_attachment_dispose (GObject *obj)
{
PopplerAttachmentPrivate *priv;
priv = POPPLER_ATTACHMENT_GET_PRIVATE (obj);
if (priv->obj_stream)
{
priv->obj_stream->free();
delete priv->obj_stream;
priv->obj_stream = NULL;
}
G_OBJECT_CLASS (poppler_attachment_parent_class)->dispose (obj);
}
static void
poppler_attachment_finalize (GObject *obj)
{
PopplerAttachment *attachment;
attachment = (PopplerAttachment *) obj;
if (attachment->name)
g_free (attachment->name);
attachment->name = NULL;
if (attachment->description)
g_free (attachment->description);
attachment->description = NULL;
if (attachment->checksum)
g_string_free (attachment->checksum, TRUE);
attachment->checksum = NULL;
G_OBJECT_CLASS (poppler_attachment_parent_class)->finalize (obj);
}
/* Public functions */
PopplerAttachment *
_poppler_attachment_new (FileSpec *emb_file)
{
PopplerAttachment *attachment;
PopplerAttachmentPrivate *priv;
EmbFile *embFile;
g_assert (emb_file != NULL);
attachment = (PopplerAttachment *) g_object_new (POPPLER_TYPE_ATTACHMENT, NULL);
priv = POPPLER_ATTACHMENT_GET_PRIVATE (attachment);
if (emb_file->getFileName ())
attachment->name = _poppler_goo_string_to_utf8 (emb_file->getFileName ());
if (emb_file->getDescription ())
attachment->description = _poppler_goo_string_to_utf8 (emb_file->getDescription ());
embFile = emb_file->getEmbeddedFile();
attachment->size = embFile->size ();
if (embFile->createDate ())
_poppler_convert_pdf_date_to_gtime (embFile->createDate (), (time_t *)&attachment->ctime);
if (embFile->modDate ())
_poppler_convert_pdf_date_to_gtime (embFile->modDate (), (time_t *)&attachment->mtime);
if (embFile->checksum () && embFile->checksum ()->getLength () > 0)
attachment->checksum = g_string_new_len (embFile->checksum ()->getCString (),
embFile->checksum ()->getLength ());
priv->obj_stream = new Object();
priv->obj_stream->initStream(embFile->stream());
// Copy the stream
embFile->stream()->incRef();
return attachment;
}
static gboolean
save_helper (const gchar *buf,
gsize count,
gpointer data,
GError **error)
{
FILE *f = (FILE *) data;
gsize n;
n = fwrite (buf, 1, count, f);
if (n != count)
{
g_set_error (error,
G_FILE_ERROR,
g_file_error_from_errno (errno),
_("Error writing to image file: %s"),
g_strerror (errno));
return FALSE;
}
return TRUE;
}
/**
* poppler_attachment_save:
* @attachment: A #PopplerAttachment.
* @filename: name of file to save
* @error: (allow-none): return location for error, or %NULL.
*
* Saves @attachment to a file indicated by @filename. If @error is set, %FALSE
* will be returned. Possible errors include those in the #G_FILE_ERROR domain
* and whatever the save function generates.
*
* Return value: %TRUE, if the file successfully saved
**/
gboolean
poppler_attachment_save (PopplerAttachment *attachment,
const char *filename,
GError **error)
{
gboolean result;
FILE *f;
g_return_val_if_fail (POPPLER_IS_ATTACHMENT (attachment), FALSE);
f = g_fopen (filename, "wb");
if (f == NULL)
{
gchar *display_name = g_filename_display_name (filename);
g_set_error (error,
G_FILE_ERROR,
g_file_error_from_errno (errno),
_("Failed to open '%s' for writing: %s"),
display_name,
g_strerror (errno));
g_free (display_name);
return FALSE;
}
result = poppler_attachment_save_to_callback (attachment, save_helper, f, error);
if (fclose (f) < 0)
{
gchar *display_name = g_filename_display_name (filename);
g_set_error (error,
G_FILE_ERROR,
g_file_error_from_errno (errno),
_("Failed to close '%s', all data may not have been saved: %s"),
display_name,
g_strerror (errno));
g_free (display_name);
return FALSE;
}
return result;
}
#define BUF_SIZE 1024
/**
* poppler_attachment_save_to_callback:
* @attachment: A #PopplerAttachment.
* @save_func: (scope call): a function that is called to save each block of data that the save routine generates.
* @user_data: user data to pass to the save function.
* @error: (allow-none): return location for error, or %NULL.
*
* Saves @attachment by feeding the produced data to @save_func. Can be used
* when you want to store the attachment to something other than a file, such as
* an in-memory buffer or a socket. If @error is set, %FALSE will be
* returned. Possible errors include those in the #G_FILE_ERROR domain and
* whatever the save function generates.
*
* Return value: %TRUE, if the save successfully completed
**/
gboolean
poppler_attachment_save_to_callback (PopplerAttachment *attachment,
PopplerAttachmentSaveFunc save_func,
gpointer user_data,
GError **error)
{
Stream *stream;
gchar buf[BUF_SIZE];
int i;
gboolean eof_reached = FALSE;
g_return_val_if_fail (POPPLER_IS_ATTACHMENT (attachment), FALSE);
stream = POPPLER_ATTACHMENT_GET_PRIVATE (attachment)->obj_stream->getStream();
stream->reset();
do
{
int data;
for (i = 0; i < BUF_SIZE; i++)
{
data = stream->getChar ();
if (data == EOF)
{
eof_reached = TRUE;
break;
}
buf[i] = data;
}
if (i > 0)
{
if (! (save_func) (buf, i, user_data, error))
return FALSE;
}
}
while (! eof_reached);
return TRUE;
}