~ubuntu-branches/debian/lenny/libgsf/lenny

« back to all changes in this revision

Viewing changes to gsf/gsf-output-gzip.c

  • Committer: Bazaar Package Importer
  • Author(s): J.H.M. Dassen (Ray)
  • Date: 2004-06-13 13:57:29 UTC
  • Revision ID: james.westby@ubuntu.com-20040613135729-3rn08f4l9in3kfzw
Tags: upstream-1.9.1
ImportĀ upstreamĀ versionĀ 1.9.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 
2
/*
 
3
 * gsf-output-gzip.c: wrapper to compress to gzipped output. See rfc1952.
 
4
 *
 
5
 * Copyright (C) 2002-2004 Jon K Hellan (hellan@acm.org)
 
6
 *
 
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.
 
10
 *
 
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.
 
15
 *
 
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
 
19
 * USA
 
20
 */
 
21
 
 
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>
 
27
 
 
28
#include <zlib.h>
 
29
#include <stdio.h>
 
30
#include <time.h>
 
31
#include <string.h>
 
32
 
 
33
#define Z_BUFSIZE 0x100
 
34
 
 
35
struct _GsfOutputGZip {
 
36
        GsfOutput output;
 
37
 
 
38
        GsfOutput *sink; /* compressed data */
 
39
 
 
40
        z_stream  stream;
 
41
/*      guint8 const *gzipped_data; */
 
42
        uLong     crc;     /* crc32 of uncompressed data */
 
43
        size_t    isize;
 
44
        
 
45
        guint8   *buf;
 
46
        size_t    buf_size;
 
47
};
 
48
 
 
49
typedef struct {
 
50
        GsfOutputClass output_class;
 
51
} GsfOutputGZipClass;
 
52
 
 
53
/* gzip flag byte */
 
54
#define GZIP_ORIGINAL_NAME      0x08 /* the original is stored */
 
55
 
 
56
static gboolean
 
57
init_gzip (GsfOutputGZip *gzip, GError **err)
 
58
{
 
59
        int ret;
 
60
        
 
61
        ret = deflateInit2 (&gzip->stream, Z_DEFAULT_COMPRESSION,
 
62
                            Z_DEFLATED, -MAX_WBITS, MAX_MEM_LEVEL,
 
63
                            Z_DEFAULT_STRATEGY);
 
64
        if (ret != Z_OK) {
 
65
                if (err != NULL)
 
66
                        *err = g_error_new (gsf_output_error_id (), 0,
 
67
                                            "Unable to initialize deflate");
 
68
                return FALSE;
 
69
        }
 
70
        if (!gzip->buf) {
 
71
                gzip->buf_size = Z_BUFSIZE; 
 
72
                gzip->buf = g_new (guint8, gzip->buf_size);
 
73
        }
 
74
        gzip->stream.next_out  = gzip->buf;
 
75
        gzip->stream.avail_out = gzip->buf_size;
 
76
 
 
77
        return TRUE;
 
78
}
 
79
 
 
80
static gboolean
 
81
gzip_output_header (GsfOutputGZip *gzip)
 
82
{
 
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; */
 
89
        gboolean ret;
 
90
        
 
91
        memset (buf, 0, sizeof buf);
 
92
        memcpy (buf, gzip_signature, 3);
 
93
        if (nlen > 0)
 
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);
 
100
 
 
101
        return ret;
 
102
}
 
103
        
 
104
/**
 
105
 * gsf_output_gzip_new :
 
106
 * @sink : The underlying data source.
 
107
 * @err    : optionally NULL.
 
108
 *
 
109
 * Adds a reference to @sink.
 
110
 *
 
111
 * Returns a new file or NULL.
 
112
 **/
 
113
GsfOutputGZip *
 
114
gsf_output_gzip_new (GsfOutput *sink, GError **err)
 
115
{
 
116
        GsfOutputGZip *gzip;
 
117
 
 
118
        g_return_val_if_fail (GSF_IS_OUTPUT (sink), NULL);
 
119
 
 
120
        gzip = g_object_new (GSF_OUTPUT_GZIP_TYPE, NULL);
 
121
        g_object_ref (G_OBJECT (sink));
 
122
        gzip->sink = sink;
 
123
 
 
124
        if (!init_gzip (gzip, err)) {
 
125
                g_object_unref (G_OBJECT (gzip));
 
126
                return NULL;
 
127
        }
 
128
 
 
129
        if (!gzip_output_header (gzip)) {
 
130
                g_object_unref (G_OBJECT (gzip));
 
131
                return NULL;
 
132
        }
 
133
 
 
134
        return gzip;
 
135
}
 
136
 
 
137
static void
 
138
gsf_output_gzip_finalize (GObject *obj)
 
139
{
 
140
        GObjectClass *parent_class;
 
141
        GsfOutputGZip *gzip = (GsfOutputGZip *)obj;
 
142
 
 
143
        if (gzip->sink != NULL) {
 
144
                g_object_unref (G_OBJECT (gzip->sink));
 
145
                gzip->sink = NULL;
 
146
        }
 
147
 
 
148
        g_free (gzip->buf);
 
149
 
 
150
        /* FIXME: check for error?  */
 
151
        deflateEnd (&gzip->stream);
 
152
 
 
153
        parent_class = g_type_class_peek (GSF_OUTPUT_TYPE);
 
154
        if (parent_class && parent_class->finalize)
 
155
                parent_class->finalize (obj);
 
156
}
 
157
 
 
158
static gboolean
 
159
gzip_output_block (GsfOutputGZip *gzip)
 
160
{
 
161
        size_t num_bytes = gzip->buf_size - gzip->stream.avail_out;
 
162
        
 
163
        if (!gsf_output_write (gzip->sink, num_bytes, gzip->buf)) {
 
164
                return FALSE;
 
165
        }
 
166
        gzip->stream.next_out  = gzip->buf;
 
167
        gzip->stream.avail_out = gzip->buf_size;
 
168
 
 
169
        return TRUE;
 
170
}
 
171
 
 
172
static gboolean
 
173
gzip_flush (GsfOutputGZip *gzip)
 
174
{
 
175
        int zret;
 
176
 
 
177
        do {
 
178
                zret = deflate (&gzip->stream, Z_FINISH);
 
179
                if (zret == Z_OK) {
 
180
                        /*  In this case Z_OK means more buffer space
 
181
                            needed  */
 
182
                        if (!gzip_output_block (gzip))
 
183
                                return FALSE;
 
184
                }
 
185
        } while (zret == Z_OK);
 
186
        if (zret != Z_STREAM_END) {
 
187
                g_warning ("Unexpected error code %d from zlib during compression.",
 
188
                           zret);
 
189
                return FALSE;
 
190
        }
 
191
        if (!gzip_output_block (gzip))
 
192
                return FALSE;
 
193
 
 
194
        return TRUE;
 
195
}
 
196
 
 
197
static gboolean
 
198
gsf_output_gzip_write (GsfOutput *output,
 
199
                       size_t num_bytes, guint8 const *data)
 
200
{
 
201
        GsfOutputGZip *gzip = GSF_OUTPUT_GZIP (output);
 
202
 
 
203
        g_return_val_if_fail (data, FALSE);
 
204
 
 
205
        gzip->stream.next_in  = (unsigned char *) data;
 
206
        gzip->stream.avail_in = num_bytes;
 
207
        
 
208
        while (gzip->stream.avail_in > 0) {
 
209
                int zret;
 
210
                if (gzip->stream.avail_out == 0) {
 
211
                        if (!gzip_output_block (gzip))
 
212
                                return FALSE;
 
213
                }
 
214
 
 
215
                zret = deflate (&gzip->stream, Z_NO_FLUSH);
 
216
                if (zret != Z_OK) {
 
217
                        g_warning ("Unexpected error code %d from zlib during compression.",
 
218
                                   zret);
 
219
                        return FALSE;
 
220
                }
 
221
        }
 
222
 
 
223
        gzip->crc = crc32 (gzip->crc, data, num_bytes);
 
224
        gzip->isize += num_bytes;
 
225
 
 
226
        if (gzip->stream.avail_out == 0) {
 
227
                if (!gzip_output_block (gzip))
 
228
                        return FALSE;
 
229
        }
 
230
 
 
231
        return TRUE;
 
232
}
 
233
 
 
234
static gboolean
 
235
gsf_output_gzip_seek (GsfOutput *output, gsf_off_t offset, GSeekType whence)
 
236
{
 
237
        (void) output;
 
238
        (void) offset;
 
239
        (void) whence;
 
240
        
 
241
        return FALSE;
 
242
}
 
243
 
 
244
static gboolean
 
245
gsf_output_gzip_close (GsfOutput *output)
 
246
{
 
247
        GsfOutputGZip *gzip = GSF_OUTPUT_GZIP (output);
 
248
        guint8 buf[8];
 
249
 
 
250
        if (!gzip_flush (gzip))
 
251
                return FALSE;
 
252
        
 
253
        /* TODO: CRC, ISIZE */
 
254
        GSF_LE_SET_GUINT32 (buf,     gzip->crc);
 
255
        GSF_LE_SET_GUINT32 (buf + 4, gzip->isize);
 
256
 
 
257
        return gsf_output_write (gzip->sink, 8, buf);
 
258
}
 
259
 
 
260
static void
 
261
gsf_output_gzip_init (GObject *obj)
 
262
{
 
263
        GsfOutputGZip *gzip = GSF_OUTPUT_GZIP (obj);
 
264
 
 
265
        gzip->sink = NULL;
 
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);
 
273
        gzip->isize             = 0;
 
274
        gzip->buf               = NULL;
 
275
        gzip->buf_size          = 0;
 
276
}
 
277
 
 
278
static void
 
279
gsf_output_gzip_class_init (GObjectClass *gobject_class)
 
280
{
 
281
        GsfOutputClass *output_class = GSF_OUTPUT_CLASS (gobject_class);
 
282
 
 
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;
 
287
}
 
288
 
 
289
GSF_CLASS (GsfOutputGZip, gsf_output_gzip,
 
290
           gsf_output_gzip_class_init, gsf_output_gzip_init, GSF_OUTPUT_TYPE)
 
291