1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * gsf-output-gzip.c: wrapper to compress to gzipped output. See rfc1952.
5 * Copyright (C) 2002-2006 Jon K Hellan (hellan@acm.org)
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of version 2.1 of the GNU Lesser General Public
9 * License as published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
22 #include <gsf-config.h>
23 #include <gsf/gsf-output-gzip.h>
24 #include <gsf/gsf-output-impl.h>
25 #include <gsf/gsf-impl-utils.h>
26 #include <gsf/gsf-utils.h>
33 static GObjectClass *parent_class;
35 struct _GsfOutputGZip {
38 GsfOutput *sink; /* compressed data */
39 gboolean raw; /* No header and no trailer. */
42 uLong crc; /* crc32 of uncompressed data */
50 GsfOutputClass output_class;
61 #define GZIP_ORIGINAL_NAME 0x08 /* the original is stored */
64 init_gzip (GsfOutputGZip *gzip)
68 ret = deflateInit2 (&gzip->stream, Z_DEFAULT_COMPRESSION,
69 Z_DEFLATED, -MAX_WBITS, MAX_MEM_LEVEL,
75 gzip->buf_size = 0x100;
76 gzip->buf = g_new (guint8, gzip->buf_size);
78 gzip->stream.next_out = gzip->buf;
79 gzip->stream.avail_out = gzip->buf_size;
85 gzip_output_header (GsfOutputGZip *gzip)
87 guint8 buf[3 + 1 + 4 + 2];
88 static guint8 const gzip_signature[] = { 0x1f, 0x8b, 0x08 } ;
89 time_t mtime = time (NULL);
90 char const *name = gsf_output_name (gzip->sink);
91 /* FIXME: What to do about gz extension ... ? */
92 int nlen = 0; /* name ? strlen (name) : 0; */
95 memset (buf, 0, sizeof buf);
96 memcpy (buf, gzip_signature, 3);
98 buf[3] = GZIP_ORIGINAL_NAME;
99 GSF_LE_SET_GUINT32 (buf + 4, (guint32) mtime);
100 buf[9] = 3; /* UNIX */
101 ret = gsf_output_write (gzip->sink, sizeof buf, buf);
102 if (ret && name && nlen > 0)
103 ret = gsf_output_write (gzip->sink, nlen, name);
109 * gsf_output_gzip_new :
110 * @sink : The underlying data source.
111 * @err : optionally %NULL.
113 * Adds a reference to @sink.
115 * Returns: a new file or %NULL.
118 gsf_output_gzip_new (GsfOutput *sink, GError **err)
121 GError const *con_err;
123 g_return_val_if_fail (GSF_IS_OUTPUT (sink), NULL);
125 output = g_object_new (GSF_OUTPUT_GZIP_TYPE, "sink", sink, NULL);
126 if (G_UNLIKELY (NULL == output)) return NULL;
128 con_err = gsf_output_error (output);
132 *err = g_error_copy (con_err);
133 g_object_unref (output);
141 gsf_output_gzip_finalize (GObject *obj)
143 GsfOutputGZip *gzip = (GsfOutputGZip *)obj;
145 if (gzip->sink != NULL) {
146 g_object_unref (G_OBJECT (gzip->sink));
152 /* FIXME: check for error? */
153 deflateEnd (&gzip->stream);
155 parent_class->finalize (obj);
159 gzip_output_block (GsfOutputGZip *gzip)
161 size_t num_bytes = gzip->buf_size - gzip->stream.avail_out;
163 if (!gsf_output_write (gzip->sink, num_bytes, gzip->buf)) {
164 gsf_output_set_error (GSF_OUTPUT (gzip), 0,
168 gzip->stream.next_out = gzip->buf;
169 gzip->stream.avail_out = gzip->buf_size;
175 gzip_flush (GsfOutputGZip *gzip)
180 zret = deflate (&gzip->stream, Z_FINISH);
182 /* In this case Z_OK means more buffer space
184 if (!gzip_output_block (gzip))
187 } while (zret == Z_OK);
188 if (zret != Z_STREAM_END) {
189 gsf_output_set_error (GSF_OUTPUT (gzip), 0,
190 "Unexpected compression failure");
191 g_warning ("Unexpected error code %d from zlib during compression.",
195 if (!gzip_output_block (gzip))
202 gsf_output_gzip_write (GsfOutput *output,
203 size_t num_bytes, guint8 const *data)
205 GsfOutputGZip *gzip = GSF_OUTPUT_GZIP (output);
207 g_return_val_if_fail (data, FALSE);
209 gzip->stream.next_in = (unsigned char *) data;
210 gzip->stream.avail_in = num_bytes;
212 while (gzip->stream.avail_in > 0) {
214 if (gzip->stream.avail_out == 0) {
215 if (!gzip_output_block (gzip))
219 zret = deflate (&gzip->stream, Z_NO_FLUSH);
221 gsf_output_set_error (output, 0,
222 "Unexpected compression failure");
223 g_warning ("Unexpected error code %d from zlib during compression.",
229 gzip->crc = crc32 (gzip->crc, data, num_bytes);
230 gzip->isize += num_bytes;
232 if (gzip->stream.avail_out == 0) {
233 if (!gzip_output_block (gzip))
241 gsf_output_gzip_seek (G_GNUC_UNUSED GsfOutput *output,
242 G_GNUC_UNUSED gsf_off_t offset,
243 G_GNUC_UNUSED GSeekType whence)
249 gsf_output_gzip_close (GsfOutput *output)
251 if (!gsf_output_error (output)) {
252 GsfOutputGZip *gzip = GSF_OUTPUT_GZIP (output);
254 if (!gzip_flush (gzip))
260 GSF_LE_SET_GUINT32 (buf, gzip->crc);
261 GSF_LE_SET_GUINT32 (buf + 4, gzip->isize);
262 if (!gsf_output_write (gzip->sink, 8, buf))
271 gsf_output_gzip_init (GObject *obj)
273 GsfOutputGZip *gzip = GSF_OUTPUT_GZIP (obj);
276 gzip->stream.zalloc = (alloc_func)0;
277 gzip->stream.zfree = (free_func)0;
278 gzip->stream.opaque = (voidpf)0;
279 gzip->stream.next_in = Z_NULL;
280 gzip->stream.next_out = Z_NULL;
281 gzip->stream.avail_in = gzip->stream.avail_out = 0;
282 gzip->crc = crc32 (0L, Z_NULL, 0);
289 gsf_output_gzip_get_property (GObject *object,
294 GsfOutputGZip *gzip = (GsfOutputGZip *)object;
296 switch (property_id) {
298 g_value_set_boolean (value, gzip->raw);
301 g_value_set_object (value, gzip->sink);
304 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
310 gsf_output_gzip_set_sink (GsfOutputGZip *gzip, GsfOutput *sink)
313 g_object_ref (GSF_OUTPUT (sink));
315 g_object_unref (gzip->sink);
320 gsf_output_gzip_set_property (GObject *object,
325 GsfOutputGZip *gzip = (GsfOutputGZip *)object;
327 switch (property_id) {
329 gzip->raw = g_value_get_boolean (value);
332 gsf_output_gzip_set_sink (gzip, g_value_get_object (value));
335 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
341 gsf_output_gzip_constructor (GType type,
342 guint n_construct_properties,
343 GObjectConstructParam *construct_params)
347 gzip = (GsfOutputGZip *)(parent_class->constructor (type,
348 n_construct_properties,
352 gsf_output_set_error (GSF_OUTPUT (gzip),
355 else if (!init_gzip (gzip))
356 gsf_output_set_error (GSF_OUTPUT (gzip),
358 "Failed to initialize zlib structure");
359 else if (!gzip->raw && !gzip_output_header (gzip))
360 gsf_output_set_error (GSF_OUTPUT (gzip),
362 "Failed to write gzip header");
364 return (GObject *)gzip;
368 gsf_output_gzip_class_init (GObjectClass *gobject_class)
370 GsfOutputClass *output_class = GSF_OUTPUT_CLASS (gobject_class);
372 gobject_class->constructor = gsf_output_gzip_constructor;
373 gobject_class->finalize = gsf_output_gzip_finalize;
374 gobject_class->set_property = gsf_output_gzip_set_property;
375 gobject_class->get_property = gsf_output_gzip_get_property;
376 output_class->Write = gsf_output_gzip_write;
377 output_class->Seek = gsf_output_gzip_seek;
378 output_class->Close = gsf_output_gzip_close;
380 g_object_class_install_property
383 g_param_spec_boolean ("raw", "Raw",
384 "Whether to write compressed data with no header/tailer.",
388 G_PARAM_CONSTRUCT_ONLY));
389 g_object_class_install_property
392 g_param_spec_object ("sink", "Sink",
393 "Where the compressed data is written.",
397 G_PARAM_CONSTRUCT_ONLY));
399 parent_class = g_type_class_peek_parent (gobject_class);
402 GSF_CLASS (GsfOutputGZip, gsf_output_gzip,
403 gsf_output_gzip_class_init, gsf_output_gzip_init,