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-2004 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
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
#define Z_BUFSIZE 0x100
35
struct _GsfOutputGZip {
38
GsfOutput *sink; /* compressed data */
41
/* guint8 const *gzipped_data; */
42
uLong crc; /* crc32 of uncompressed data */
50
GsfOutputClass output_class;
54
#define GZIP_ORIGINAL_NAME 0x08 /* the original is stored */
57
init_gzip (GsfOutputGZip *gzip, GError **err)
61
ret = deflateInit2 (&gzip->stream, Z_DEFAULT_COMPRESSION,
62
Z_DEFLATED, -MAX_WBITS, MAX_MEM_LEVEL,
66
*err = g_error_new (gsf_output_error_id (), 0,
67
"Unable to initialize deflate");
71
gzip->buf_size = Z_BUFSIZE;
72
gzip->buf = g_new (guint8, gzip->buf_size);
74
gzip->stream.next_out = gzip->buf;
75
gzip->stream.avail_out = gzip->buf_size;
81
gzip_output_header (GsfOutputGZip *gzip)
83
guint8 buf[3 + 1 + 4 + 2];
84
static guint8 const gzip_signature[] = { 0x1f, 0x8b, 0x08 } ;
85
time_t mtime = time (NULL);
86
char const *name = gsf_output_name (gzip->sink);
87
/* FIXME: What to do about gz extension ... ? */
88
int nlen = 0; /* name ? strlen (name) : 0; */
91
memset (buf, 0, sizeof buf);
92
memcpy (buf, gzip_signature, 3);
94
buf[3] = GZIP_ORIGINAL_NAME;
95
GSF_LE_SET_GUINT32 (buf + 4, (guint32) mtime);
96
buf[9] = 3; /* UNIX */
97
ret = gsf_output_write (gzip->sink, sizeof buf, buf);
98
if (ret && name && nlen > 0)
99
ret = gsf_output_write (gzip->sink, nlen, name);
105
* gsf_output_gzip_new :
106
* @sink : The underlying data source.
107
* @err : optionally NULL.
109
* Adds a reference to @sink.
111
* Returns a new file or NULL.
114
gsf_output_gzip_new (GsfOutput *sink, GError **err)
118
g_return_val_if_fail (GSF_IS_OUTPUT (sink), NULL);
120
gzip = g_object_new (GSF_OUTPUT_GZIP_TYPE, NULL);
121
g_object_ref (G_OBJECT (sink));
124
if (!init_gzip (gzip, err)) {
125
g_object_unref (G_OBJECT (gzip));
129
if (!gzip_output_header (gzip)) {
130
g_object_unref (G_OBJECT (gzip));
138
gsf_output_gzip_finalize (GObject *obj)
140
GObjectClass *parent_class;
141
GsfOutputGZip *gzip = (GsfOutputGZip *)obj;
143
if (gzip->sink != NULL) {
144
g_object_unref (G_OBJECT (gzip->sink));
150
/* FIXME: check for error? */
151
deflateEnd (&gzip->stream);
153
parent_class = g_type_class_peek (GSF_OUTPUT_TYPE);
154
if (parent_class && parent_class->finalize)
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)) {
166
gzip->stream.next_out = gzip->buf;
167
gzip->stream.avail_out = gzip->buf_size;
173
gzip_flush (GsfOutputGZip *gzip)
178
zret = deflate (&gzip->stream, Z_FINISH);
180
/* In this case Z_OK means more buffer space
182
if (!gzip_output_block (gzip))
185
} while (zret == Z_OK);
186
if (zret != Z_STREAM_END) {
187
g_warning ("Unexpected error code %d from zlib during compression.",
191
if (!gzip_output_block (gzip))
198
gsf_output_gzip_write (GsfOutput *output,
199
size_t num_bytes, guint8 const *data)
201
GsfOutputGZip *gzip = GSF_OUTPUT_GZIP (output);
203
g_return_val_if_fail (data, FALSE);
205
gzip->stream.next_in = (unsigned char *) data;
206
gzip->stream.avail_in = num_bytes;
208
while (gzip->stream.avail_in > 0) {
210
if (gzip->stream.avail_out == 0) {
211
if (!gzip_output_block (gzip))
215
zret = deflate (&gzip->stream, Z_NO_FLUSH);
217
g_warning ("Unexpected error code %d from zlib during compression.",
223
gzip->crc = crc32 (gzip->crc, data, num_bytes);
224
gzip->isize += num_bytes;
226
if (gzip->stream.avail_out == 0) {
227
if (!gzip_output_block (gzip))
235
gsf_output_gzip_seek (GsfOutput *output, gsf_off_t offset, GSeekType whence)
245
gsf_output_gzip_close (GsfOutput *output)
247
GsfOutputGZip *gzip = GSF_OUTPUT_GZIP (output);
250
if (!gzip_flush (gzip))
253
/* TODO: CRC, ISIZE */
254
GSF_LE_SET_GUINT32 (buf, gzip->crc);
255
GSF_LE_SET_GUINT32 (buf + 4, gzip->isize);
257
return gsf_output_write (gzip->sink, 8, buf);
261
gsf_output_gzip_init (GObject *obj)
263
GsfOutputGZip *gzip = GSF_OUTPUT_GZIP (obj);
266
gzip->stream.zalloc = (alloc_func)0;
267
gzip->stream.zfree = (free_func)0;
268
gzip->stream.opaque = (voidpf)0;
269
gzip->stream.next_in = Z_NULL;
270
gzip->stream.next_out = Z_NULL;
271
gzip->stream.avail_in = gzip->stream.avail_out = 0;
272
gzip->crc = crc32 (0L, Z_NULL, 0);
279
gsf_output_gzip_class_init (GObjectClass *gobject_class)
281
GsfOutputClass *output_class = GSF_OUTPUT_CLASS (gobject_class);
283
gobject_class->finalize = gsf_output_gzip_finalize;
284
output_class->Write = gsf_output_gzip_write;
285
output_class->Seek = gsf_output_gzip_seek;
286
output_class->Close = gsf_output_gzip_close;
289
GSF_CLASS (GsfOutputGZip, gsf_output_gzip,
290
gsf_output_gzip_class_init, gsf_output_gzip_init, GSF_OUTPUT_TYPE)