1 /* GIO - GLib Input, Output and Streaming Library
3 * Copyright (C) 2009 Red Hat, Inc.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library 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 GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18 * Boston, MA 02111-1307, USA.
20 * Author: Alexander Larsson <alexl@redhat.com>
25 #include "gzlibdecompressor.h"
31 #include "gfileinfo.h"
34 #include "gioenumtypes.h"
45 * SECTION:gzdecompressor
46 * @short_description: Zlib decompressor
49 * #GZlibDecompressor is an implementation of #GConverter that
50 * decompresses data compressed with zlib.
53 static void g_zlib_decompressor_iface_init (GConverterIface
*iface
);
66 struct _GZlibDecompressor
68 GObject parent_instance
;
70 GZlibCompressorFormat format
;
72 HeaderData
*header_data
;
76 g_zlib_decompressor_set_gzheader (GZlibDecompressor
*decompressor
)
78 /* On win32, these functions were not exported before 1.2.4 */
79 #if !defined (G_OS_WIN32) || ZLIB_VERNUM >= 0x1240
80 if (decompressor
->format
!= G_ZLIB_COMPRESSOR_FORMAT_GZIP
)
83 if (decompressor
->header_data
!= NULL
)
85 if (decompressor
->header_data
->file_info
)
86 g_object_unref (decompressor
->header_data
->file_info
);
88 memset (decompressor
->header_data
, 0, sizeof (HeaderData
));
92 decompressor
->header_data
= g_new0 (HeaderData
, 1);
95 decompressor
->header_data
->gzheader
.name
= (Bytef
*) &decompressor
->header_data
->filename
;
96 /* We keep one byte to guarantee the string is 0-terminated */
97 decompressor
->header_data
->gzheader
.name_max
= 256;
99 if (inflateGetHeader (&decompressor
->zstream
, &decompressor
->header_data
->gzheader
) != Z_OK
)
100 g_warning ("unexpected zlib error: %s\n", decompressor
->zstream
.msg
);
101 #endif /* !G_OS_WIN32 || ZLIB >= 1.2.4 */
104 G_DEFINE_TYPE_WITH_CODE (GZlibDecompressor
, g_zlib_decompressor
, G_TYPE_OBJECT
,
105 G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER
,
106 g_zlib_decompressor_iface_init
))
109 g_zlib_decompressor_finalize (GObject
*object
)
111 GZlibDecompressor
*decompressor
;
113 decompressor
= G_ZLIB_DECOMPRESSOR (object
);
115 inflateEnd (&decompressor
->zstream
);
117 if (decompressor
->header_data
!= NULL
)
119 if (decompressor
->header_data
->file_info
)
120 g_object_unref (decompressor
->header_data
->file_info
);
121 g_free (decompressor
->header_data
);
124 G_OBJECT_CLASS (g_zlib_decompressor_parent_class
)->finalize (object
);
129 g_zlib_decompressor_set_property (GObject
*object
,
134 GZlibDecompressor
*decompressor
;
136 decompressor
= G_ZLIB_DECOMPRESSOR (object
);
141 decompressor
->format
= g_value_get_enum (value
);
145 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
152 g_zlib_decompressor_get_property (GObject
*object
,
157 GZlibDecompressor
*decompressor
;
159 decompressor
= G_ZLIB_DECOMPRESSOR (object
);
164 g_value_set_enum (value
, decompressor
->format
);
168 if (decompressor
->header_data
)
169 g_value_set_object (value
, decompressor
->header_data
->file_info
);
171 g_value_set_object (value
, NULL
);
175 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
181 g_zlib_decompressor_init (GZlibDecompressor
*decompressor
)
186 g_zlib_decompressor_constructed (GObject
*object
)
188 GZlibDecompressor
*decompressor
;
191 decompressor
= G_ZLIB_DECOMPRESSOR (object
);
193 if (decompressor
->format
== G_ZLIB_COMPRESSOR_FORMAT_GZIP
)
196 res
= inflateInit2 (&decompressor
->zstream
, MAX_WBITS
+ 16);
198 else if (decompressor
->format
== G_ZLIB_COMPRESSOR_FORMAT_RAW
)
200 /* Negative for raw */
201 res
= inflateInit2 (&decompressor
->zstream
, -MAX_WBITS
);
204 res
= inflateInit (&decompressor
->zstream
);
206 if (res
== Z_MEM_ERROR
)
207 g_error ("GZlibDecompressor: Not enough memory for zlib use");
210 g_warning ("unexpected zlib error: %s\n", decompressor
->zstream
.msg
);
212 g_zlib_decompressor_set_gzheader (decompressor
);
216 g_zlib_decompressor_class_init (GZlibDecompressorClass
*klass
)
218 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
220 gobject_class
->finalize
= g_zlib_decompressor_finalize
;
221 gobject_class
->constructed
= g_zlib_decompressor_constructed
;
222 gobject_class
->get_property
= g_zlib_decompressor_get_property
;
223 gobject_class
->set_property
= g_zlib_decompressor_set_property
;
225 g_object_class_install_property (gobject_class
,
227 g_param_spec_enum ("format",
228 P_("compression format"),
229 P_("The format of the compressed data"),
230 G_TYPE_ZLIB_COMPRESSOR_FORMAT
,
231 G_ZLIB_COMPRESSOR_FORMAT_ZLIB
,
232 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
233 G_PARAM_STATIC_STRINGS
));
236 * GZlibDecompressor:file-info:
238 * A #GFileInfo containing the information found in the GZIP header
239 * of the data stream processed, or %NULL if the header was not yet
240 * fully processed, is not present at all, or the compressor's
241 * #GZlibDecompressor:format property is not %G_ZLIB_COMPRESSOR_FORMAT_GZIP.
245 g_object_class_install_property (gobject_class
,
247 g_param_spec_object ("file-info",
252 G_PARAM_STATIC_STRINGS
));
256 * g_zlib_decompressor_new:
257 * @format: The format to use for the compressed data
259 * Creates a new #GZlibDecompressor.
261 * Returns: a new #GZlibDecompressor
266 g_zlib_decompressor_new (GZlibCompressorFormat format
)
268 GZlibDecompressor
*decompressor
;
270 decompressor
= g_object_new (G_TYPE_ZLIB_DECOMPRESSOR
,
278 * g_zlib_decompressor_get_file_info:
279 * @decompressor: a #GZlibDecompressor
281 * Retrieves the #GFileInfo constructed from the GZIP header data
282 * of compressed data processed by @compressor, or %NULL if @decompressor's
283 * #GZlibDecompressor:format property is not %G_ZLIB_COMPRESSOR_FORMAT_GZIP,
284 * or the header data was not fully processed yet, or it not present in the
285 * data stream at all.
287 * Returns: (transfer none): a #GFileInfo, or %NULL
292 g_zlib_decompressor_get_file_info (GZlibDecompressor
*decompressor
)
294 g_return_val_if_fail (G_IS_ZLIB_DECOMPRESSOR (decompressor
), NULL
);
296 if (decompressor
->header_data
)
297 return decompressor
->header_data
->file_info
;
303 g_zlib_decompressor_reset (GConverter
*converter
)
305 GZlibDecompressor
*decompressor
= G_ZLIB_DECOMPRESSOR (converter
);
308 res
= inflateReset (&decompressor
->zstream
);
310 g_warning ("unexpected zlib error: %s\n", decompressor
->zstream
.msg
);
312 g_zlib_decompressor_set_gzheader (decompressor
);
315 static GConverterResult
316 g_zlib_decompressor_convert (GConverter
*converter
,
321 GConverterFlags flags
,
323 gsize
*bytes_written
,
326 GZlibDecompressor
*decompressor
;
329 decompressor
= G_ZLIB_DECOMPRESSOR (converter
);
331 decompressor
->zstream
.next_in
= (void *)inbuf
;
332 decompressor
->zstream
.avail_in
= inbuf_size
;
334 decompressor
->zstream
.next_out
= outbuf
;
335 decompressor
->zstream
.avail_out
= outbuf_size
;
337 res
= inflate (&decompressor
->zstream
, Z_NO_FLUSH
);
339 if (res
== Z_DATA_ERROR
|| res
== Z_NEED_DICT
)
341 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_INVALID_DATA
,
342 _("Invalid compressed data"));
343 return G_CONVERTER_ERROR
;
346 if (res
== Z_MEM_ERROR
)
348 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_FAILED
,
349 _("Not enough memory"));
350 return G_CONVERTER_ERROR
;
353 if (res
== Z_STREAM_ERROR
)
355 g_set_error (error
, G_IO_ERROR
, G_IO_ERROR_FAILED
,
356 _("Internal error: %s"), decompressor
->zstream
.msg
);
357 return G_CONVERTER_ERROR
;
360 if (res
== Z_BUF_ERROR
)
362 if (flags
& G_CONVERTER_FLUSH
)
363 return G_CONVERTER_FLUSHED
;
365 /* Z_FINISH not set, so this means no progress could be made */
366 /* We do have output space, so this should only happen if we
367 have no input but need some */
369 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_PARTIAL_INPUT
,
370 _("Need more input"));
371 return G_CONVERTER_ERROR
;
374 g_assert (res
== Z_OK
|| res
== Z_STREAM_END
);
376 *bytes_read
= inbuf_size
- decompressor
->zstream
.avail_in
;
377 *bytes_written
= outbuf_size
- decompressor
->zstream
.avail_out
;
379 #if !defined (G_OS_WIN32) || ZLIB_VERNUM >= 0x1240
380 if (decompressor
->header_data
!= NULL
&&
381 decompressor
->header_data
->gzheader
.done
== 1)
383 HeaderData
*data
= decompressor
->header_data
;
385 /* So we don't notify again */
386 data
->gzheader
.done
= 2;
388 data
->file_info
= g_file_info_new ();
389 g_file_info_set_attribute_uint64 (data
->file_info
,
390 G_FILE_ATTRIBUTE_TIME_MODIFIED
,
391 data
->gzheader
.time
);
392 g_file_info_set_attribute_uint32 (data
->file_info
,
393 G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC
,
396 if (data
->filename
[0] != '\0')
397 g_file_info_set_attribute_byte_string (data
->file_info
,
398 G_FILE_ATTRIBUTE_STANDARD_NAME
,
401 g_object_notify (G_OBJECT (decompressor
), "file-info");
403 #endif /* !G_OS_WIN32 || ZLIB >= 1.2.4 */
405 if (res
== Z_STREAM_END
)
406 return G_CONVERTER_FINISHED
;
407 return G_CONVERTER_CONVERTED
;
411 g_zlib_decompressor_iface_init (GConverterIface
*iface
)
413 iface
->convert
= g_zlib_decompressor_convert
;
414 iface
->reset
= g_zlib_decompressor_reset
;