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, see <http://www.gnu.org/licenses/>.
18 * Author: Alexander Larsson <alexl@redhat.com>
23 #include "gzlibdecompressor.h"
29 #include "gfileinfo.h"
32 #include "gioenumtypes.h"
43 * SECTION:gzdecompressor
44 * @short_description: Zlib decompressor
47 * #GZlibDecompressor is an implementation of #GConverter that
48 * decompresses data compressed with zlib.
51 static void g_zlib_decompressor_iface_init (GConverterIface
*iface
);
64 struct _GZlibDecompressor
66 GObject parent_instance
;
68 GZlibCompressorFormat format
;
70 HeaderData
*header_data
;
74 g_zlib_decompressor_set_gzheader (GZlibDecompressor
*decompressor
)
76 /* On win32, these functions were not exported before 1.2.4 */
77 #if !defined (G_OS_WIN32) || ZLIB_VERNUM >= 0x1240
78 if (decompressor
->format
!= G_ZLIB_COMPRESSOR_FORMAT_GZIP
)
81 if (decompressor
->header_data
!= NULL
)
83 if (decompressor
->header_data
->file_info
)
84 g_object_unref (decompressor
->header_data
->file_info
);
86 memset (decompressor
->header_data
, 0, sizeof (HeaderData
));
90 decompressor
->header_data
= g_new0 (HeaderData
, 1);
93 decompressor
->header_data
->gzheader
.name
= (Bytef
*) &decompressor
->header_data
->filename
;
94 /* We keep one byte to guarantee the string is 0-terminated */
95 decompressor
->header_data
->gzheader
.name_max
= 256;
97 if (inflateGetHeader (&decompressor
->zstream
, &decompressor
->header_data
->gzheader
) != Z_OK
)
98 g_warning ("unexpected zlib error: %s\n", decompressor
->zstream
.msg
);
99 #endif /* !G_OS_WIN32 || ZLIB >= 1.2.4 */
102 G_DEFINE_TYPE_WITH_CODE (GZlibDecompressor
, g_zlib_decompressor
, G_TYPE_OBJECT
,
103 G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER
,
104 g_zlib_decompressor_iface_init
))
107 g_zlib_decompressor_finalize (GObject
*object
)
109 GZlibDecompressor
*decompressor
;
111 decompressor
= G_ZLIB_DECOMPRESSOR (object
);
113 inflateEnd (&decompressor
->zstream
);
115 if (decompressor
->header_data
!= NULL
)
117 if (decompressor
->header_data
->file_info
)
118 g_object_unref (decompressor
->header_data
->file_info
);
119 g_free (decompressor
->header_data
);
122 G_OBJECT_CLASS (g_zlib_decompressor_parent_class
)->finalize (object
);
127 g_zlib_decompressor_set_property (GObject
*object
,
132 GZlibDecompressor
*decompressor
;
134 decompressor
= G_ZLIB_DECOMPRESSOR (object
);
139 decompressor
->format
= g_value_get_enum (value
);
143 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
150 g_zlib_decompressor_get_property (GObject
*object
,
155 GZlibDecompressor
*decompressor
;
157 decompressor
= G_ZLIB_DECOMPRESSOR (object
);
162 g_value_set_enum (value
, decompressor
->format
);
166 if (decompressor
->header_data
)
167 g_value_set_object (value
, decompressor
->header_data
->file_info
);
169 g_value_set_object (value
, NULL
);
173 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
179 g_zlib_decompressor_init (GZlibDecompressor
*decompressor
)
184 g_zlib_decompressor_constructed (GObject
*object
)
186 GZlibDecompressor
*decompressor
;
189 decompressor
= G_ZLIB_DECOMPRESSOR (object
);
191 if (decompressor
->format
== G_ZLIB_COMPRESSOR_FORMAT_GZIP
)
194 res
= inflateInit2 (&decompressor
->zstream
, MAX_WBITS
+ 16);
196 else if (decompressor
->format
== G_ZLIB_COMPRESSOR_FORMAT_RAW
)
198 /* Negative for raw */
199 res
= inflateInit2 (&decompressor
->zstream
, -MAX_WBITS
);
202 res
= inflateInit (&decompressor
->zstream
);
204 if (res
== Z_MEM_ERROR
)
205 g_error ("GZlibDecompressor: Not enough memory for zlib use");
208 g_warning ("unexpected zlib error: %s\n", decompressor
->zstream
.msg
);
210 g_zlib_decompressor_set_gzheader (decompressor
);
214 g_zlib_decompressor_class_init (GZlibDecompressorClass
*klass
)
216 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
218 gobject_class
->finalize
= g_zlib_decompressor_finalize
;
219 gobject_class
->constructed
= g_zlib_decompressor_constructed
;
220 gobject_class
->get_property
= g_zlib_decompressor_get_property
;
221 gobject_class
->set_property
= g_zlib_decompressor_set_property
;
223 g_object_class_install_property (gobject_class
,
225 g_param_spec_enum ("format",
226 P_("compression format"),
227 P_("The format of the compressed data"),
228 G_TYPE_ZLIB_COMPRESSOR_FORMAT
,
229 G_ZLIB_COMPRESSOR_FORMAT_ZLIB
,
230 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
231 G_PARAM_STATIC_STRINGS
));
234 * GZlibDecompressor:file-info:
236 * A #GFileInfo containing the information found in the GZIP header
237 * of the data stream processed, or %NULL if the header was not yet
238 * fully processed, is not present at all, or the compressor's
239 * #GZlibDecompressor:format property is not %G_ZLIB_COMPRESSOR_FORMAT_GZIP.
243 g_object_class_install_property (gobject_class
,
245 g_param_spec_object ("file-info",
250 G_PARAM_STATIC_STRINGS
));
254 * g_zlib_decompressor_new:
255 * @format: The format to use for the compressed data
257 * Creates a new #GZlibDecompressor.
259 * Returns: a new #GZlibDecompressor
264 g_zlib_decompressor_new (GZlibCompressorFormat format
)
266 GZlibDecompressor
*decompressor
;
268 decompressor
= g_object_new (G_TYPE_ZLIB_DECOMPRESSOR
,
276 * g_zlib_decompressor_get_file_info:
277 * @decompressor: a #GZlibDecompressor
279 * Retrieves the #GFileInfo constructed from the GZIP header data
280 * of compressed data processed by @compressor, or %NULL if @decompressor's
281 * #GZlibDecompressor:format property is not %G_ZLIB_COMPRESSOR_FORMAT_GZIP,
282 * or the header data was not fully processed yet, or it not present in the
283 * data stream at all.
285 * Returns: (transfer none): a #GFileInfo, or %NULL
290 g_zlib_decompressor_get_file_info (GZlibDecompressor
*decompressor
)
292 g_return_val_if_fail (G_IS_ZLIB_DECOMPRESSOR (decompressor
), NULL
);
294 if (decompressor
->header_data
)
295 return decompressor
->header_data
->file_info
;
301 g_zlib_decompressor_reset (GConverter
*converter
)
303 GZlibDecompressor
*decompressor
= G_ZLIB_DECOMPRESSOR (converter
);
306 res
= inflateReset (&decompressor
->zstream
);
308 g_warning ("unexpected zlib error: %s\n", decompressor
->zstream
.msg
);
310 g_zlib_decompressor_set_gzheader (decompressor
);
313 static GConverterResult
314 g_zlib_decompressor_convert (GConverter
*converter
,
319 GConverterFlags flags
,
321 gsize
*bytes_written
,
324 GZlibDecompressor
*decompressor
;
327 decompressor
= G_ZLIB_DECOMPRESSOR (converter
);
329 decompressor
->zstream
.next_in
= (void *)inbuf
;
330 decompressor
->zstream
.avail_in
= inbuf_size
;
332 decompressor
->zstream
.next_out
= outbuf
;
333 decompressor
->zstream
.avail_out
= outbuf_size
;
335 res
= inflate (&decompressor
->zstream
, Z_NO_FLUSH
);
337 if (res
== Z_DATA_ERROR
|| res
== Z_NEED_DICT
)
339 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_INVALID_DATA
,
340 _("Invalid compressed data"));
341 return G_CONVERTER_ERROR
;
344 if (res
== Z_MEM_ERROR
)
346 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_FAILED
,
347 _("Not enough memory"));
348 return G_CONVERTER_ERROR
;
351 if (res
== Z_STREAM_ERROR
)
353 g_set_error (error
, G_IO_ERROR
, G_IO_ERROR_FAILED
,
354 _("Internal error: %s"), decompressor
->zstream
.msg
);
355 return G_CONVERTER_ERROR
;
358 if (res
== Z_BUF_ERROR
)
360 if (flags
& G_CONVERTER_FLUSH
)
361 return G_CONVERTER_FLUSHED
;
363 /* Z_FINISH not set, so this means no progress could be made */
364 /* We do have output space, so this should only happen if we
365 have no input but need some */
367 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_PARTIAL_INPUT
,
368 _("Need more input"));
369 return G_CONVERTER_ERROR
;
372 g_assert (res
== Z_OK
|| res
== Z_STREAM_END
);
374 *bytes_read
= inbuf_size
- decompressor
->zstream
.avail_in
;
375 *bytes_written
= outbuf_size
- decompressor
->zstream
.avail_out
;
377 #if !defined (G_OS_WIN32) || ZLIB_VERNUM >= 0x1240
378 if (decompressor
->header_data
!= NULL
&&
379 decompressor
->header_data
->gzheader
.done
== 1)
381 HeaderData
*data
= decompressor
->header_data
;
383 /* So we don't notify again */
384 data
->gzheader
.done
= 2;
386 data
->file_info
= g_file_info_new ();
387 g_file_info_set_attribute_uint64 (data
->file_info
,
388 G_FILE_ATTRIBUTE_TIME_MODIFIED
,
389 data
->gzheader
.time
);
390 g_file_info_set_attribute_uint32 (data
->file_info
,
391 G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC
,
394 if (data
->filename
[0] != '\0')
395 g_file_info_set_attribute_byte_string (data
->file_info
,
396 G_FILE_ATTRIBUTE_STANDARD_NAME
,
399 g_object_notify (G_OBJECT (decompressor
), "file-info");
401 #endif /* !G_OS_WIN32 || ZLIB >= 1.2.4 */
403 if (res
== Z_STREAM_END
)
404 return G_CONVERTER_FINISHED
;
405 return G_CONVERTER_CONVERTED
;
409 g_zlib_decompressor_iface_init (GConverterIface
*iface
)
411 iface
->convert
= g_zlib_decompressor_convert
;
412 iface
->reset
= g_zlib_decompressor_reset
;