1 /* poppler-attachment.cc: glib wrapper for poppler
2 * Copyright (C) 2006, Red Hat, Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 #include "config.h"
20 #include <errno.h>
21 #include <glib/gstdio.h>
22
23 #include "poppler.h"
24 #include "poppler-private.h"
25
26 /**
27 * SECTION:poppler-attachment
28 * @short_description: Attachments
29 * @title: PopplerAttachment
30 */
31
32 /* FIXME: We need to add gettext support sometime */
33 #define _(x) (x)
34
35 typedef struct _PopplerAttachmentPrivate PopplerAttachmentPrivate;
36 struct _PopplerAttachmentPrivate
37 {
38 Object *obj_stream;
39 };
40
41 #define POPPLER_ATTACHMENT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), POPPLER_TYPE_ATTACHMENT, PopplerAttachmentPrivate))
42
43 static void poppler_attachment_dispose (GObject *obj);
44 static void poppler_attachment_finalize (GObject *obj);
45
G_DEFINE_TYPE(PopplerAttachment,poppler_attachment,G_TYPE_OBJECT)46 G_DEFINE_TYPE (PopplerAttachment, poppler_attachment, G_TYPE_OBJECT)
47
48 static void
49 poppler_attachment_init (PopplerAttachment *attachment)
50 {
51 }
52
53 static void
poppler_attachment_class_init(PopplerAttachmentClass * klass)54 poppler_attachment_class_init (PopplerAttachmentClass *klass)
55 {
56 G_OBJECT_CLASS (klass)->dispose = poppler_attachment_dispose;
57 G_OBJECT_CLASS (klass)->finalize = poppler_attachment_finalize;
58 g_type_class_add_private (klass, sizeof (PopplerAttachmentPrivate));
59 }
60
61 static void
poppler_attachment_dispose(GObject * obj)62 poppler_attachment_dispose (GObject *obj)
63 {
64 PopplerAttachmentPrivate *priv;
65
66 priv = POPPLER_ATTACHMENT_GET_PRIVATE (obj);
67
68 if (priv->obj_stream)
69 {
70 priv->obj_stream->free();
71 delete priv->obj_stream;
72 priv->obj_stream = NULL;
73 }
74
75 G_OBJECT_CLASS (poppler_attachment_parent_class)->dispose (obj);
76 }
77
78 static void
poppler_attachment_finalize(GObject * obj)79 poppler_attachment_finalize (GObject *obj)
80 {
81 PopplerAttachment *attachment;
82
83 attachment = (PopplerAttachment *) obj;
84
85 if (attachment->name)
86 g_free (attachment->name);
87 attachment->name = NULL;
88
89 if (attachment->description)
90 g_free (attachment->description);
91 attachment->description = NULL;
92
93 if (attachment->checksum)
94 g_string_free (attachment->checksum, TRUE);
95 attachment->checksum = NULL;
96
97 G_OBJECT_CLASS (poppler_attachment_parent_class)->finalize (obj);
98 }
99
100 /* Public functions */
101
102 PopplerAttachment *
_poppler_attachment_new(EmbFile * emb_file)103 _poppler_attachment_new (EmbFile *emb_file)
104 {
105 PopplerAttachment *attachment;
106 PopplerAttachmentPrivate *priv;
107
108 g_assert (emb_file != NULL);
109
110 attachment = (PopplerAttachment *) g_object_new (POPPLER_TYPE_ATTACHMENT, NULL);
111 priv = POPPLER_ATTACHMENT_GET_PRIVATE (attachment);
112
113 if (emb_file->name ())
114 attachment->name = _poppler_goo_string_to_utf8 (emb_file->name ());
115 if (emb_file->description ())
116 attachment->description = _poppler_goo_string_to_utf8 (emb_file->description ());
117
118 attachment->size = emb_file->size ();
119
120 _poppler_convert_pdf_date_to_gtime (emb_file->createDate (), (time_t *)&attachment->ctime);
121 _poppler_convert_pdf_date_to_gtime (emb_file->modDate (), (time_t *)&attachment->mtime);
122
123 if (emb_file->checksum ()->getLength () > 0)
124 attachment->checksum = g_string_new_len (emb_file->checksum ()->getCString (),
125 emb_file->checksum ()->getLength ());
126
127 priv->obj_stream = new Object();
128 emb_file->streamObject().copy(priv->obj_stream);
129
130 return attachment;
131 }
132
133 static gboolean
save_helper(const gchar * buf,gsize count,gpointer data,GError ** error)134 save_helper (const gchar *buf,
135 gsize count,
136 gpointer data,
137 GError **error)
138 {
139 FILE *f = (FILE *) data;
140 gsize n;
141
142 n = fwrite (buf, 1, count, f);
143 if (n != count)
144 {
145 g_set_error (error,
146 G_FILE_ERROR,
147 g_file_error_from_errno (errno),
148 _("Error writing to image file: %s"),
149 g_strerror (errno));
150 return FALSE;
151 }
152
153 return TRUE;
154 }
155
156 /**
157 * poppler_attachment_save:
158 * @attachment: A #PopplerAttachment.
159 * @filename: name of file to save
160 * @error: (allow-none): return location for error, or %NULL.
161 *
162 * Saves @attachment to a file indicated by @filename. If @error is set, %FALSE
163 * will be returned. Possible errors include those in the #G_FILE_ERROR domain
164 * and whatever the save function generates.
165 *
166 * Return value: %TRUE, if the file successfully saved
167 **/
168 gboolean
poppler_attachment_save(PopplerAttachment * attachment,const char * filename,GError ** error)169 poppler_attachment_save (PopplerAttachment *attachment,
170 const char *filename,
171 GError **error)
172 {
173 gboolean result;
174 FILE *f;
175
176 g_return_val_if_fail (POPPLER_IS_ATTACHMENT (attachment), FALSE);
177
178 f = g_fopen (filename, "wb");
179
180 if (f == NULL)
181 {
182 gchar *display_name = g_filename_display_name (filename);
183 g_set_error (error,
184 G_FILE_ERROR,
185 g_file_error_from_errno (errno),
186 _("Failed to open '%s' for writing: %s"),
187 display_name,
188 g_strerror (errno));
189 g_free (display_name);
190 return FALSE;
191 }
192
193 result = poppler_attachment_save_to_callback (attachment, save_helper, f, error);
194
195 if (fclose (f) < 0)
196 {
197 gchar *display_name = g_filename_display_name (filename);
198 g_set_error (error,
199 G_FILE_ERROR,
200 g_file_error_from_errno (errno),
201 _("Failed to close '%s', all data may not have been saved: %s"),
202 display_name,
203 g_strerror (errno));
204 g_free (display_name);
205 return FALSE;
206 }
207
208 return TRUE;
209 }
210
211 #define BUF_SIZE 1024
212
213 /**
214 * poppler_attachment_save_to_callback:
215 * @attachment: A #PopplerAttachment.
216 * @save_func: (scope call): a function that is called to save each block of data that the save routine generates.
217 * @user_data: user data to pass to the save function.
218 * @error: (allow-none): return location for error, or %NULL.
219 *
220 * Saves @attachment by feeding the produced data to @save_func. Can be used
221 * when you want to store the attachment to something other than a file, such as
222 * an in-memory buffer or a socket. If @error is set, %FALSE will be
223 * returned. Possible errors include those in the #G_FILE_ERROR domain and
224 * whatever the save function generates.
225 *
226 * Return value: %TRUE, if the save successfully completed
227 **/
228 gboolean
poppler_attachment_save_to_callback(PopplerAttachment * attachment,PopplerAttachmentSaveFunc save_func,gpointer user_data,GError ** error)229 poppler_attachment_save_to_callback (PopplerAttachment *attachment,
230 PopplerAttachmentSaveFunc save_func,
231 gpointer user_data,
232 GError **error)
233 {
234 Stream *stream;
235 gchar buf[BUF_SIZE];
236 int i;
237 gboolean eof_reached = FALSE;
238
239 g_return_val_if_fail (POPPLER_IS_ATTACHMENT (attachment), FALSE);
240
241 stream = POPPLER_ATTACHMENT_GET_PRIVATE (attachment)->obj_stream->getStream();
242 stream->reset();
243
244 do
245 {
246 int data;
247
248 for (i = 0; i < BUF_SIZE; i++)
249 {
250 data = stream->getChar ();
251 if (data == EOF)
252 {
253 eof_reached = TRUE;
254 break;
255 }
256 buf[i] = data;
257 }
258
259 if (i > 0)
260 {
261 if (! (save_func) (buf, i, user_data, error))
262 return FALSE;
263 }
264 }
265 while (! eof_reached);
266
267
268 return TRUE;
269 }
270