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

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): J.H.M. Dassen (Ray)
  • Date: 2006-11-06 22:45:03 UTC
  • mfrom: (1.2.1 upstream) (2.1.1 dapper)
  • Revision ID: james.westby@ubuntu.com-20061106224503-g6pmv1m82zy8jya9
Tags: 1.14.3-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
3
3
 * gsf-input-gzip.c: wrapper to uncompress gzipped input
4
4
 *
5
5
 * Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
 
6
 * Copyright (C) 2005 Morten Welinder (terra@gnome.org)
6
7
 *
7
8
 * This program is free software; you can redistribute it and/or
8
9
 * modify it under the terms of version 2.1 of the GNU Lesser General Public
15
16
 *
16
17
 * You should have received a copy of the GNU Lesser General Public License
17
18
 * along with this program; if not, write to the Free Software
18
 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 
19
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
19
20
 * USA
20
21
 */
21
22
 
31
32
 
32
33
#define Z_BUFSIZE 0x100
33
34
 
 
35
static GObjectClass *parent_class;
 
36
 
34
37
struct _GsfInputGZip {
35
38
        GsfInput input;
36
39
 
37
40
        GsfInput *source; /* compressed data */
 
41
        gboolean raw; /* No header and no trailer.  */
 
42
        GError *err;
 
43
        gsf_off_t uncompressed_size;
 
44
        gboolean stop_byte_added;
38
45
 
39
46
        z_stream  stream;
40
47
        guint8 const *gzipped_data;
43
50
        guint8   *buf;
44
51
        size_t    buf_size;
45
52
 
46
 
        size_t    header_size;
 
53
        size_t    header_size, trailer_size;
47
54
        gsf_off_t seek_skipped;
48
55
};
49
56
 
51
58
        GsfInputClass input_class;
52
59
} GsfInputGZipClass;
53
60
 
 
61
enum {
 
62
        PROP_0,
 
63
        PROP_RAW,
 
64
        PROP_SOURCE,
 
65
        PROP_UNCOMPRESSED_SIZE
 
66
};
 
67
 
54
68
/* gzip flag byte */
55
69
#define GZIP_IS_ASCII           0x01 /* file contains text ? */
56
70
#define GZIP_HEADER_CRC         0x02 /* there is a CRC in the header */
62
76
static gboolean
63
77
check_header (GsfInputGZip *input)
64
78
{
65
 
        static guint8 const signature [2] = {0x1f, 0x8b};
66
 
 
67
 
        guint8 const *data;
68
 
        unsigned flags, len;
69
 
 
70
 
        /* Check signature */
71
 
        if (gsf_input_seek (input->source, (gsf_off_t) 0, G_SEEK_SET) ||
72
 
            NULL == (data = gsf_input_read (input->source, 2 + 1 + 1 + 6, NULL)) ||
73
 
            0 != memcmp (data, signature, sizeof (signature)))
74
 
                return TRUE;
75
 
 
76
 
        /* verify flags and compression type */
77
 
        flags  = data [3];
78
 
        if (data [2] != Z_DEFLATED || (flags & ~GZIP_HEADER_FLAGS) != 0)
79
 
                return TRUE;
80
 
 
81
 
        /* Get the uncompressed size */
82
 
        if (gsf_input_seek (input->source, (gsf_off_t) -4, G_SEEK_END) ||
83
 
            NULL == (data = gsf_input_read (input->source, 4, NULL)))
84
 
                return TRUE;
85
 
        /* FIXME, but how?  The size read here is modulo 2^32.  */
86
 
        gsf_input_set_size (GSF_INPUT (input),
87
 
                            (gsf_off_t) GSF_LE_GET_GUINT32 (data));
88
 
 
89
 
        if (gsf_input_seek (input->source, (gsf_off_t) 2 + 1 + 1 + 6,
90
 
                            G_SEEK_SET))
91
 
                return TRUE;
92
 
 
93
 
        if (flags & GZIP_EXTRA_FIELD) {
94
 
                if (NULL == (data = gsf_input_read (input->source, 2, NULL)))
95
 
                        return TRUE;
96
 
                len = data [0] | (data [1] << 8);
97
 
                if (NULL == gsf_input_read (input->source, len, NULL))
98
 
                        return TRUE;
99
 
        }
100
 
        if (flags & GZIP_ORIGINAL_NAME) {
101
 
                /* Skip over the filename (which is in ISO 8859-1 encoding).  */
102
 
                do {
103
 
                        if (NULL == (data = gsf_input_read (input->source, 1, NULL)))
104
 
                                return TRUE;
105
 
                } while (*data != 0);
106
 
        }
107
 
 
108
 
        if (flags & GZIP_HAS_COMMENT) {
109
 
                /* Skip over the comment (which is in ISO 8859-1 encoding).  */
110
 
                do {
111
 
                        if (NULL == (data = gsf_input_read (input->source, 1, NULL)))
112
 
                                return TRUE;
113
 
                } while (*data != 0);
114
 
        }
115
 
 
116
 
        if (flags & GZIP_HEADER_CRC &&
117
 
            NULL == (data = gsf_input_read (input->source, 2, NULL)))
118
 
                return TRUE;
119
 
 
120
 
        input->header_size = input->source->cur_offset;
121
 
 
122
 
        if (gsf_input_remaining (input->source) < 9)
 
79
        if (input->raw) {
 
80
                input->header_size = 0;
 
81
                input->trailer_size = 0;
 
82
        } else {
 
83
                static guint8 const signature[2] = {0x1f, 0x8b};
 
84
                guint8 const *data;
 
85
                unsigned flags, len;
 
86
 
 
87
                /* Check signature */
 
88
                if (NULL == (data = gsf_input_read (input->source, 2 + 1 + 1 + 6, NULL)) ||
 
89
                    0 != memcmp (data, signature, sizeof (signature)))
 
90
                        return TRUE;
 
91
 
 
92
                /* verify flags and compression type */
 
93
                flags  = data[3];
 
94
                if (data[2] != Z_DEFLATED || (flags & ~GZIP_HEADER_FLAGS) != 0)
 
95
                        return TRUE;
 
96
 
 
97
                /* If we have the size, don't bother seeking to the end.  */
 
98
                if (input->uncompressed_size < 0) {
 
99
                        /* Get the uncompressed size */
 
100
                        if (gsf_input_seek (input->source, (gsf_off_t) -4, G_SEEK_END) ||
 
101
                            NULL == (data = gsf_input_read (input->source, 4, NULL)))
 
102
                                return TRUE;
 
103
                        /* FIXME, but how?  The size read here is modulo 2^32.  */
 
104
                        input->uncompressed_size = GSF_LE_GET_GUINT32 (data);
 
105
 
 
106
                        if (input->uncompressed_size / 1000 > gsf_input_size (input->source)) {
 
107
                                g_warning ("Suspiciously well compressed file with better than 1000:1 ratio.\n"
 
108
                                           "It is probably truncated or corrupt");
 
109
                        }
 
110
                }
 
111
 
 
112
                if (gsf_input_seek (input->source, 2 + 1 + 1 + 6, G_SEEK_SET))
 
113
                        return TRUE;
 
114
 
 
115
                if (flags & GZIP_EXTRA_FIELD) {
 
116
                        if (NULL == (data = gsf_input_read (input->source, 2, NULL)))
 
117
                                return TRUE;
 
118
                        len = GSF_LE_GET_GUINT16 (data);
 
119
                        if (NULL == gsf_input_read (input->source, len, NULL))
 
120
                                return TRUE;
 
121
                }
 
122
                if (flags & GZIP_ORIGINAL_NAME) {
 
123
                        /* Skip over the filename (which is in ISO 8859-1 encoding).  */
 
124
                        do {
 
125
                                if (NULL == (data = gsf_input_read (input->source, 1, NULL)))
 
126
                                        return TRUE;
 
127
                        } while (*data != 0);
 
128
                }
 
129
 
 
130
                if (flags & GZIP_HAS_COMMENT) {
 
131
                        /* Skip over the comment (which is in ISO 8859-1 encoding).  */
 
132
                        do {
 
133
                                if (NULL == (data = gsf_input_read (input->source, 1, NULL)))
 
134
                                        return TRUE;
 
135
                        } while (*data != 0);
 
136
                }
 
137
 
 
138
                if (flags & GZIP_HEADER_CRC &&
 
139
                    NULL == (data = gsf_input_read (input->source, 2, NULL)))
 
140
                        return TRUE;
 
141
 
 
142
                input->header_size = input->source->cur_offset;
 
143
                /* the last 8 bytes are the crc and size.  */
 
144
                input->trailer_size = 8;
 
145
        }
 
146
 
 
147
        gsf_input_set_size (GSF_INPUT (input), input->uncompressed_size);
 
148
 
 
149
        if (gsf_input_remaining (input->source) < input->trailer_size)
123
150
                return TRUE;    /* No room for payload */
124
151
 
125
152
        return FALSE;
129
156
init_zip (GsfInputGZip *gzip, GError **err)
130
157
{
131
158
        gsf_off_t cur_pos;
132
 
        
 
159
 
133
160
        if (Z_OK != inflateInit2 (&(gzip->stream), -MAX_WBITS)) {
134
161
                if (err != NULL)
135
 
                        *err = g_error_new (gsf_input_error (), 0,
 
162
                        *err = g_error_new (gsf_input_error_id (), 0,
136
163
                                "Unable to initialize zlib");
137
164
                return TRUE;
138
165
        }
139
166
 
140
167
        cur_pos = gsf_input_tell (gzip->source);
 
168
        if (gsf_input_seek (gzip->source, 0, G_SEEK_SET)) {
 
169
                if (err)
 
170
                        *err = g_error_new (gsf_input_error_id (), 0,
 
171
                                            "Failed to rewind source");
 
172
                return TRUE;
 
173
        }
141
174
 
142
175
        if (check_header (gzip) != FALSE) {
143
176
                if (err != NULL)
144
 
                        *err = g_error_new (gsf_input_error (), 0,
 
177
                        *err = g_error_new (gsf_input_error_id (), 0,
145
178
                                "Invalid gzip header");
146
179
                if (gsf_input_seek (gzip->source, cur_pos, G_SEEK_SET)) {
147
180
                        g_warning ("attempt to restore position failed ??");
161
194
 *
162
195
 * Returns a new file or NULL.
163
196
 **/
164
 
GsfInputGZip *
 
197
GsfInput *
165
198
gsf_input_gzip_new (GsfInput *source, GError **err)
166
199
{
167
200
        GsfInputGZip *gzip;
168
201
 
169
202
        g_return_val_if_fail (GSF_IS_INPUT (source), NULL);
170
203
 
171
 
        gzip = g_object_new (GSF_INPUT_GZIP_TYPE, NULL);
172
 
        g_object_ref (G_OBJECT (source));
173
 
        gzip->source = source;
174
 
        gzip->seek_skipped = 0;
175
 
 
176
 
        if (init_zip (gzip, err) != FALSE) {
177
 
                g_object_unref (G_OBJECT (gzip));
 
204
        gzip = g_object_new (GSF_INPUT_GZIP_TYPE,
 
205
                             "source", source,
 
206
                             NULL);
 
207
        if (gzip->err) {
 
208
                if (err)
 
209
                        *err = g_error_copy (gzip->err);
 
210
                g_object_unref (gzip);
178
211
                return NULL;
179
212
        }
180
213
 
181
 
        return gzip;
 
214
        return GSF_INPUT (gzip);
182
215
}
183
216
 
184
217
static void
185
218
gsf_input_gzip_finalize (GObject *obj)
186
219
{
187
 
        GObjectClass *parent_class;
188
220
        GsfInputGZip *gzip = (GsfInputGZip *)obj;
189
221
 
190
222
        if (gzip->source != NULL) {
197
229
        if (gzip->stream.state != NULL)
198
230
                inflateEnd (&(gzip->stream));
199
231
 
200
 
        parent_class = g_type_class_peek (GSF_INPUT_TYPE);
201
 
        if (parent_class && parent_class->finalize)
202
 
                parent_class->finalize (obj);
 
232
        g_clear_error (&gzip->err);
 
233
 
 
234
        parent_class->finalize (obj);
203
235
}
204
236
 
205
237
static GsfInput *
206
238
gsf_input_gzip_dup (GsfInput *src_input, GError **err)
207
239
{
208
240
        GsfInputGZip const *src = (GsfInputGZip *)src_input;
209
 
        GsfInputGZip *dst = g_object_new (GSF_INPUT_GZIP_TYPE, NULL);
210
 
 
211
 
        dst->source = gsf_input_dup(src->source, NULL);
212
 
 
213
 
        if (init_zip (dst, err) != FALSE) {
214
 
                g_object_unref (G_OBJECT (dst));
 
241
        GsfInputGZip *dst;
 
242
        GsfInput *src_source_copy;
 
243
 
 
244
        if (src->source) {
 
245
                src_source_copy = gsf_input_dup (src->source, err);
 
246
                if (err)
 
247
                        return NULL;
 
248
        } else
 
249
                src_source_copy = NULL;
 
250
 
 
251
        dst = g_object_new (GSF_INPUT_GZIP_TYPE,
 
252
                            "source", src_source_copy,
 
253
                            "raw", src->raw,
 
254
                            NULL);
 
255
        if (src_source_copy)
 
256
                g_object_unref (src_source_copy);
 
257
 
 
258
        if (src->err) {
 
259
                g_clear_error (&dst->err);
 
260
                dst->err = g_error_copy (src->err);
 
261
        } else if (dst->err) {
 
262
                if (err)
 
263
                        *err = g_error_copy (dst->err);
 
264
                g_object_unref (dst);
215
265
                return NULL;
216
266
        }
217
267
 
226
276
        if (buffer == NULL) {
227
277
                if (gzip->buf_size < num_bytes) {
228
278
                        gzip->buf_size = MAX (num_bytes, 256);
229
 
                        if (gzip->buf != NULL)
230
 
                                g_free (gzip->buf);
 
279
                        g_free (gzip->buf);
231
280
                        gzip->buf = g_new (guint8, gzip->buf_size);
232
281
                }
233
282
                buffer = gzip->buf;
238
287
        while (gzip->stream.avail_out != 0) {
239
288
                int zerr;
240
289
                if (gzip->stream.avail_in == 0) {
241
 
                        /* the last 8 bytes are the crc and size, but we need 1
242
 
                         * byte to flush the decompresion.
243
 
                         */
244
290
                        gsf_off_t remain = gsf_input_remaining (gzip->source);
245
 
                        size_t n;
246
 
                        if (remain < 8)
247
 
                                return NULL;
248
 
                        n = MIN (remain - 7, Z_BUFSIZE);
 
291
                        if (remain <= gzip->trailer_size) {
 
292
                                if (remain < gzip->trailer_size || gzip->stop_byte_added) {
 
293
                                        g_clear_error (&gzip->err);
 
294
                                        gzip->err = g_error_new
 
295
                                                (gsf_input_error_id (), 0,
 
296
                                                 "truncated source");
 
297
                                        return NULL;
 
298
                                }
 
299
                                /* zlib requires an extra byte.  */
 
300
                                gzip->stream.avail_in = 1;
 
301
                                gzip->gzipped_data = "";
 
302
                                gzip->stop_byte_added = TRUE;
 
303
                        } else {
 
304
                                size_t n = MIN (remain - gzip->trailer_size,
 
305
                                                Z_BUFSIZE);
249
306
 
250
 
                        if (NULL == (gzip->gzipped_data = gsf_input_read (gzip->source, n, NULL)))
251
 
                                return NULL;
252
 
                        gzip->stream.avail_in = n;
 
307
                                gzip->gzipped_data =
 
308
                                        gsf_input_read (gzip->source, n, NULL);
 
309
                                if (!gzip->gzipped_data) {
 
310
                                        g_clear_error (&gzip->err);
 
311
                                        gzip->err = g_error_new
 
312
                                                (gsf_input_error_id (), 0,
 
313
                                                 "Failed to read from source");
 
314
                                        return NULL;
 
315
                                }
 
316
                                gzip->stream.avail_in = n;
 
317
                        }
253
318
                        gzip->stream.next_in = (Byte *)gzip->gzipped_data;
254
319
                }
255
320
                zerr = inflate (&(gzip->stream), Z_NO_FLUSH);
314
379
        GsfInputGZip *gzip = GSF_INPUT_GZIP (obj);
315
380
 
316
381
        gzip->source = NULL;
 
382
        gzip->raw = FALSE;
 
383
        gzip->uncompressed_size = -1;
 
384
        gzip->err = NULL;
317
385
        gzip->stream.zalloc     = (alloc_func)0;
318
386
        gzip->stream.zfree      = (free_func)0;
319
387
        gzip->stream.opaque     = (voidpf)0;
323
391
        gzip->crc               = crc32 (0L, Z_NULL, 0);
324
392
        gzip->buf               = NULL;
325
393
        gzip->buf_size          = 0;
 
394
        gzip->seek_skipped = 0;
 
395
}
 
396
 
 
397
static void
 
398
gsf_input_gzip_get_property (GObject     *object,
 
399
                             guint        property_id,
 
400
                             GValue      *value,
 
401
                             GParamSpec  *pspec)
 
402
{
 
403
        GsfInputGZip *gzip = (GsfInputGZip *)object;
 
404
 
 
405
        switch (property_id) {
 
406
        case PROP_RAW:
 
407
                g_value_set_boolean (value, gzip->raw);
 
408
                break;
 
409
        case PROP_SOURCE:
 
410
                g_value_set_object (value, gzip->source);
 
411
                break;
 
412
        case PROP_UNCOMPRESSED_SIZE:
 
413
                g_value_set_int64 (value, gzip->uncompressed_size);
 
414
                break;
 
415
        default:
 
416
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 
417
                break;
 
418
        }
 
419
}
 
420
 
 
421
static void
 
422
gsf_input_gzip_set_source (GsfInputGZip *gzip, GsfInput *source)
 
423
{
 
424
        if (source)
 
425
                g_object_ref (GSF_INPUT (source));
 
426
        if (gzip->source)
 
427
                g_object_unref (gzip->source);
 
428
        gzip->source = source;
 
429
}
 
430
 
 
431
static void
 
432
gsf_input_gzip_set_property (GObject      *object,
 
433
                             guint         property_id,
 
434
                             GValue const *value,
 
435
                             GParamSpec   *pspec)
 
436
{
 
437
        GsfInputGZip *gzip = (GsfInputGZip *)object;
 
438
 
 
439
        switch (property_id) {
 
440
        case PROP_RAW:
 
441
                gzip->raw = g_value_get_boolean (value);
 
442
                break;
 
443
        case PROP_SOURCE:
 
444
                gsf_input_gzip_set_source (gzip, g_value_get_object (value));
 
445
                break;
 
446
        case PROP_UNCOMPRESSED_SIZE:
 
447
                gzip->uncompressed_size = g_value_get_int64 (value);
 
448
                break;
 
449
        default:
 
450
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 
451
                break;
 
452
        }
 
453
}
 
454
 
 
455
static GObject*
 
456
gsf_input_gzip_constructor (GType                  type,
 
457
                            guint                  n_construct_properties,
 
458
                            GObjectConstructParam *construct_params)
 
459
{
 
460
  GsfInputGZip *gzip;
 
461
 
 
462
  gzip = (GsfInputGZip *)(parent_class->constructor (type,
 
463
                                                     n_construct_properties,
 
464
                                                     construct_params));
 
465
 
 
466
  if (!gzip->source) {
 
467
          g_clear_error (&gzip->err);
 
468
          gzip->err = g_error_new (gsf_input_error_id (), 0,
 
469
                                   "NULL source");
 
470
  } else if (gzip->raw && gzip->uncompressed_size < 0) {
 
471
          g_clear_error (&gzip->err);
 
472
          gzip->err = g_error_new (gsf_input_error_id (), 0,
 
473
                                   "Uncompressed size not set");
 
474
  } else if (init_zip (gzip, &gzip->err) != FALSE) {
 
475
          /* Nothing more.  */
 
476
  }
 
477
 
 
478
  return (GObject *)gzip;
326
479
}
327
480
 
328
481
static void
330
483
{
331
484
        GsfInputClass *input_class = GSF_INPUT_CLASS (gobject_class);
332
485
 
333
 
        gobject_class->finalize = gsf_input_gzip_finalize;
334
 
        input_class->Dup        = gsf_input_gzip_dup;
335
 
        input_class->Read       = gsf_input_gzip_read;
336
 
        input_class->Seek       = gsf_input_gzip_seek;
 
486
        gobject_class->constructor  = gsf_input_gzip_constructor;
 
487
        gobject_class->finalize     = gsf_input_gzip_finalize;
 
488
        gobject_class->set_property = gsf_input_gzip_set_property;
 
489
        gobject_class->get_property = gsf_input_gzip_get_property;
 
490
        input_class->Dup            = gsf_input_gzip_dup;
 
491
        input_class->Read           = gsf_input_gzip_read;
 
492
        input_class->Seek           = gsf_input_gzip_seek;
 
493
 
 
494
        g_object_class_install_property
 
495
                (gobject_class,
 
496
                 PROP_RAW,
 
497
                 g_param_spec_boolean ("raw", "Raw",
 
498
                                       "Whether to read compressed data with no header and no trailer.",
 
499
                                       FALSE,
 
500
                                       GSF_PARAM_STATIC |
 
501
                                       G_PARAM_READWRITE |
 
502
                                       G_PARAM_CONSTRUCT_ONLY));
 
503
        g_object_class_install_property
 
504
                (gobject_class,
 
505
                 PROP_SOURCE,
 
506
                 g_param_spec_object ("source", "Source",
 
507
                                      "Where the compressed data comes from.",
 
508
                                      GSF_INPUT_TYPE,
 
509
                                      GSF_PARAM_STATIC |
 
510
                                      G_PARAM_READWRITE |
 
511
                                      G_PARAM_CONSTRUCT_ONLY));
 
512
        /**
 
513
         * GsfInputGzip:uncompressed_size:
 
514
         *
 
515
         * The size that the data will have after uncompression.
 
516
         * The is mandatory for raw streams and if the uncompressed size is
 
517
         * larger than 4GB.
 
518
         */  
 
519
        g_object_class_install_property
 
520
                (gobject_class,
 
521
                 PROP_UNCOMPRESSED_SIZE,
 
522
                 g_param_spec_int64 ("uncompressed-size", "Size after decompression",
 
523
                                     "The source's uncompressed size",
 
524
                                     -1, G_MAXINT64, -1,
 
525
                                     GSF_PARAM_STATIC |
 
526
                                     G_PARAM_READWRITE |
 
527
                                     G_PARAM_CONSTRUCT_ONLY));
 
528
 
 
529
        parent_class = g_type_class_peek_parent (gobject_class);
337
530
}
338
531
 
339
532
GSF_CLASS (GsfInputGZip, gsf_input_gzip,
340
533
           gsf_input_gzip_class_init, gsf_input_gzip_init, GSF_INPUT_TYPE)
341