1 /* poppler-media.cc: glib interface to MediaRendition
2 *
3 * Copyright (C) 2010 Carlos Garcia Campos <carlosgc@gnome.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20 #include "config.h"
21
22 #include <errno.h>
23 #include <glib/gstdio.h>
24
25 #include "poppler-media.h"
26 #include "poppler-private.h"
27
28 /**
29 * SECTION: poppler-media
30 * @short_description: Media
31 * @title: PopplerMedia
32 */
33
34 typedef struct _PopplerMediaClass PopplerMediaClass;
35
36 struct _PopplerMedia
37 {
38 GObject parent_instance;
39
40 gchar *filename;
41
42 gchar *mime_type;
43 Stream *stream;
44 };
45
46 struct _PopplerMediaClass
47 {
48 GObjectClass parent_class;
49 };
50
51 G_DEFINE_TYPE (PopplerMedia, poppler_media, G_TYPE_OBJECT);
52
53 static void
poppler_media_finalize(GObject * object)54 poppler_media_finalize (GObject *object)
55 {
56 PopplerMedia *media = POPPLER_MEDIA(object);
57
58 if (media->filename) {
59 g_free (media->filename);
60 media->filename = NULL;
61 }
62
63 if (media->mime_type) {
64 g_free (media->mime_type);
65 media->mime_type = NULL;
66 }
67
68 if (media->stream) {
69 media->stream->decRef();
70 media->stream = NULL;
71 }
72
73 G_OBJECT_CLASS (poppler_media_parent_class)->finalize (object);
74 }
75
76 static void
poppler_media_class_init(PopplerMediaClass * klass)77 poppler_media_class_init (PopplerMediaClass *klass)
78 {
79 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
80
81 gobject_class->finalize = poppler_media_finalize;
82 }
83
84 static void
poppler_media_init(PopplerMedia * media)85 poppler_media_init (PopplerMedia *media)
86 {
87 }
88
89 PopplerMedia *
_poppler_media_new(MediaRendition * poppler_media)90 _poppler_media_new (MediaRendition *poppler_media)
91 {
92 PopplerMedia *media;
93
94 g_assert (poppler_media != NULL);
95
96 media = POPPLER_MEDIA (g_object_new (POPPLER_TYPE_MEDIA, NULL));
97
98 if (poppler_media->getIsEmbedded()) {
99 GooString* mime_type;
100
101 media->stream = poppler_media->getEmbbededStream();
102 mime_type = poppler_media->getContentType();
103 if (mime_type)
104 media->mime_type = g_strdup (mime_type->getCString());
105 } else {
106 media->filename = g_strdup (poppler_media->getFileName()->getCString());
107 }
108
109 return media;
110 }
111
112 /**
113 * poppler_media_get_filename:
114 * @poppler_media: a #PopplerMedia
115 *
116 * Returns the media clip filename, in case of non-embedded media. filename might be
117 * a local relative or absolute path or a URI
118 *
119 * Return value: a filename, return value is owned by #PopplerMedia and should not be freed
120 *
121 * Since: 0.14
122 */
123 const gchar *
poppler_media_get_filename(PopplerMedia * poppler_media)124 poppler_media_get_filename (PopplerMedia *poppler_media)
125 {
126 g_return_val_if_fail (POPPLER_IS_MEDIA (poppler_media), NULL);
127 g_return_val_if_fail (poppler_media->stream == NULL, NULL);
128
129 return poppler_media->filename;
130 }
131
132 /**
133 * poppler_media_is_embedded:
134 * @poppler_media: a #PopplerMedia
135 *
136 * Whether the media clip is embedded in the PDF. If the result is %TRUE, the embedded stream
137 * can be saved with poppler_media_save() or poppler_media_save_to_callback() function.
138 * If the result is %FALSE, the media clip filename can be retrieved with
139 * poppler_media_get_file_name() function.
140 *
141 * Return value: %TRUE if media clip is embedded, %FALSE otherwise
142 *
143 * Since: 0.14
144 */
145 gboolean
poppler_media_is_embedded(PopplerMedia * poppler_media)146 poppler_media_is_embedded (PopplerMedia *poppler_media)
147 {
148 g_return_val_if_fail (POPPLER_IS_MEDIA (poppler_media), FALSE);
149
150 return poppler_media->stream != NULL;
151 }
152
153 /**
154 * poppler_media_get_mime_type:
155 * @poppler_media: a #PopplerMedia
156 *
157 * Returns the media clip mime-type
158 *
159 * Return value: the mime-type, return value is owned by #PopplerMedia and should not be freed
160 *
161 * Since: 0.14
162 */
163 const gchar *
poppler_media_get_mime_type(PopplerMedia * poppler_media)164 poppler_media_get_mime_type (PopplerMedia *poppler_media)
165 {
166 g_return_val_if_fail (POPPLER_IS_MEDIA (poppler_media), NULL);
167
168 return poppler_media->mime_type;
169 }
170
171 static gboolean
save_helper(const gchar * buf,gsize count,gpointer data,GError ** error)172 save_helper (const gchar *buf,
173 gsize count,
174 gpointer data,
175 GError **error)
176 {
177 FILE *f = (FILE *) data;
178 gsize n;
179
180 n = fwrite (buf, 1, count, f);
181 if (n != count)
182 {
183 g_set_error (error,
184 G_FILE_ERROR,
185 g_file_error_from_errno (errno),
186 "Error writing to media file: %s",
187 g_strerror (errno));
188 return FALSE;
189 }
190
191 return TRUE;
192 }
193
194 /**
195 * poppler_media_save:
196 * @poppler_media: a #PopplerMedia
197 * @filename: name of file to save
198 * @error: (allow-none): return location for error, or %NULL.
199 *
200 * Saves embedded stream of @poppler_media to a file indicated by @filename.
201 * If @error is set, %FALSE will be returned.
202 * Possible errors include those in the #G_FILE_ERROR domain
203 * and whatever the save function generates.
204 *
205 * Return value: %TRUE, if the file successfully saved
206 *
207 * Since: 0.14
208 */
209 gboolean
poppler_media_save(PopplerMedia * poppler_media,const char * filename,GError ** error)210 poppler_media_save (PopplerMedia *poppler_media,
211 const char *filename,
212 GError **error)
213 {
214 gboolean result;
215 FILE *f;
216
217 g_return_val_if_fail (POPPLER_IS_MEDIA (poppler_media), FALSE);
218 g_return_val_if_fail (poppler_media->stream != NULL, FALSE);
219
220 f = g_fopen (filename, "wb");
221
222 if (f == NULL)
223 {
224 gchar *display_name = g_filename_display_name (filename);
225 g_set_error (error,
226 G_FILE_ERROR,
227 g_file_error_from_errno (errno),
228 "Failed to open '%s' for writing: %s",
229 display_name,
230 g_strerror (errno));
231 g_free (display_name);
232 return FALSE;
233 }
234
235 result = poppler_media_save_to_callback (poppler_media, save_helper, f, error);
236
237 if (fclose (f) < 0)
238 {
239 gchar *display_name = g_filename_display_name (filename);
240 g_set_error (error,
241 G_FILE_ERROR,
242 g_file_error_from_errno (errno),
243 "Failed to close '%s', all data may not have been saved: %s",
244 display_name,
245 g_strerror (errno));
246 g_free (display_name);
247 return FALSE;
248 }
249
250 return result;
251 }
252
253 #define BUF_SIZE 1024
254
255 /**
256 * poppler_media_save_to_callback:
257 * @poppler_media: a #PopplerMedia
258 * @save_func: (scope call): a function that is called to save each block of data that the save routine generates.
259 * @user_data: user data to pass to the save function.
260 * @error: (allow-none): return location for error, or %NULL.
261 *
262 * Saves embedded stream of @poppler_media by feeding the produced data to @save_func. Can be used
263 * when you want to store the media clip stream to something other than a file, such as
264 * an in-memory buffer or a socket. If @error is set, %FALSE will be
265 * returned. Possible errors include those in the #G_FILE_ERROR domain and
266 * whatever the save function generates.
267 *
268 * Return value: %TRUE, if the save successfully completed
269 *
270 * Since: 0.14
271 */
272 gboolean
poppler_media_save_to_callback(PopplerMedia * poppler_media,PopplerMediaSaveFunc save_func,gpointer user_data,GError ** error)273 poppler_media_save_to_callback (PopplerMedia *poppler_media,
274 PopplerMediaSaveFunc save_func,
275 gpointer user_data,
276 GError **error)
277 {
278 Stream *stream;
279 gchar buf[BUF_SIZE];
280 int i;
281 gboolean eof_reached = FALSE;
282
283 g_return_val_if_fail (POPPLER_IS_MEDIA (poppler_media), FALSE);
284 g_return_val_if_fail (poppler_media->stream != NULL, FALSE);
285
286 stream = poppler_media->stream;
287 stream->reset();
288
289 do
290 {
291 int data;
292
293 for (i = 0; i < BUF_SIZE; i++)
294 {
295 data = stream->getChar ();
296 if (data == EOF)
297 {
298 eof_reached = TRUE;
299 break;
300 }
301 buf[i] = data;
302 }
303
304 if (i > 0)
305 {
306 if (! (save_func) (buf, i, user_data, error))
307 {
308 stream->close ();
309 return FALSE;
310 }
311 }
312 }
313 while (! eof_reached);
314
315 stream->close ();
316
317 return TRUE;
318 }
319