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