Add GZlibDecompressor for zlib decompression
[platform/upstream/glib.git] / gio / gzlibdecompressor.c
1 /* GIO - GLib Input, Output and Streaming Library
2  *
3  * Copyright (C) 2009 Red Hat, Inc.
4  *
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.
9  *
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.
14  *
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.
19  *
20  * Author: Alexander Larsson <alexl@redhat.com>
21  */
22
23 #include "config.h"
24
25 #include <errno.h>
26 #include <zlib.h>
27 #include <string.h>
28
29 #include "gzlibdecompressor.h"
30 #include "glib.h"
31 #include "gioerror.h"
32 #include "glibintl.h"
33 #include "gioenums.h"
34 #include "gioenumtypes.h"
35
36 #include "gioalias.h"
37
38 enum {
39   PROP_0,
40   PROP_FORMAT
41 };
42
43 /**
44  * SECTION:gzdecompressor
45  * @short_description: Zlib decompressor
46  * @include: gio/gio.h
47  *
48  * #GZlibDecompressor is an implementation of #GDecompressor that
49  * decompresses data compressed with zlib.
50  */
51
52 static void g_zlib_decompressor_iface_init          (GConverterIface *iface);
53
54 /**
55  * GZlibDecompressor:
56  *
57  * Zlib decompression
58  */
59 struct _GZlibDecompressor
60 {
61   GObject parent_instance;
62
63   GZlibCompressorFormat format;
64   z_stream zstream;
65 };
66
67 G_DEFINE_TYPE_WITH_CODE (GZlibDecompressor, g_zlib_decompressor, G_TYPE_OBJECT,
68                          G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER,
69                                                 g_zlib_decompressor_iface_init))
70
71 static void
72 g_zlib_decompressor_finalize (GObject *object)
73 {
74   GZlibDecompressor *decompressor;
75
76   decompressor = G_ZLIB_DECOMPRESSOR (object);
77
78   inflateEnd (&decompressor->zstream);
79
80   G_OBJECT_CLASS (g_zlib_decompressor_parent_class)->finalize (object);
81 }
82
83
84 static void
85 g_zlib_decompressor_set_property (GObject      *object,
86                                   guint         prop_id,
87                                   const GValue *value,
88                                   GParamSpec   *pspec)
89 {
90   GZlibDecompressor *decompressor;
91
92   decompressor = G_ZLIB_DECOMPRESSOR (object);
93
94   switch (prop_id)
95     {
96     case PROP_FORMAT:
97       decompressor->format = g_value_get_enum (value);
98       break;
99
100     default:
101       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
102       break;
103     }
104
105 }
106
107 static void
108 g_zlib_decompressor_get_property (GObject    *object,
109                                   guint       prop_id,
110                                   GValue     *value,
111                                   GParamSpec *pspec)
112 {
113   GZlibDecompressor *decompressor;
114
115   decompressor = G_ZLIB_DECOMPRESSOR (object);
116
117   switch (prop_id)
118     {
119     case PROP_FORMAT:
120       g_value_set_enum (value, decompressor->format);
121       break;
122
123     default:
124       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
125       break;
126     }
127 }
128
129 static void
130 g_zlib_decompressor_init (GZlibDecompressor *decompressor)
131 {
132 }
133
134 static void
135 g_zlib_decompressor_constructed (GObject *object)
136 {
137   GZlibDecompressor *decompressor;
138   int res;
139
140   decompressor = G_ZLIB_DECOMPRESSOR (object);
141
142   if (decompressor->format == G_ZLIB_COMPRESSOR_FORMAT_GZIP)
143     {
144       /* + 16 for gzip */
145       res = inflateInit2 (&decompressor->zstream, MAX_WBITS + 16);
146     }
147   else
148     res = inflateInit (&decompressor->zstream);
149
150   if (res == Z_MEM_ERROR )
151     g_error ("GZlibDecompressor: Not enough memory for zlib use");
152
153   if (res != Z_OK)
154     g_warning ("unexpected zlib error: %s\n", decompressor->zstream.msg);
155 }
156
157 static void
158 g_zlib_decompressor_class_init (GZlibDecompressorClass *klass)
159 {
160   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
161
162   gobject_class->finalize = g_zlib_decompressor_finalize;
163   gobject_class->constructed = g_zlib_decompressor_constructed;
164   gobject_class->get_property = g_zlib_decompressor_get_property;
165   gobject_class->set_property = g_zlib_decompressor_set_property;
166
167   g_object_class_install_property (gobject_class,
168                                    PROP_FORMAT,
169                                    g_param_spec_enum ("format",
170                                                       P_("compression format"),
171                                                       P_("The format of the compressed data"),
172                                                       G_TYPE_ZLIB_COMPRESSOR_FORMAT,
173                                                       G_ZLIB_COMPRESSOR_FORMAT_RAW,
174                                                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
175                                                       G_PARAM_STATIC_STRINGS));
176 }
177
178 /**
179  * g_zlib_decompressor_new:
180  * @format: The format to use for the compressed data
181  *
182  * Creates a new #GZlibDecompressor.
183  *
184  * Returns: a new #GZlibDecompressor
185  *
186  * Since: 2.24
187  **/
188 GZlibDecompressor *
189 g_zlib_decompressor_new (GZlibCompressorFormat format)
190 {
191   GZlibDecompressor *decompressor;
192
193   decompressor = g_object_new (G_TYPE_ZLIB_DECOMPRESSOR,
194                                "format", format,
195                                NULL);
196
197   return decompressor;
198 }
199
200 static void
201 g_zlib_decompressor_reset (GConverter *converter)
202 {
203   GZlibDecompressor *decompressor = G_ZLIB_DECOMPRESSOR (converter);
204   int res;
205
206   res = inflateReset (&decompressor->zstream);
207   if (res != Z_OK)
208     g_warning ("unexpected zlib error: %s\n", decompressor->zstream.msg);
209 }
210
211 static GConverterResult
212 g_zlib_decompressor_convert (GConverter *converter,
213                              const void *inbuf,
214                              gsize       inbuf_size,
215                              void       *outbuf,
216                              gsize       outbuf_size,
217                              GConverterFlags flags,
218                              gsize      *bytes_read,
219                              gsize      *bytes_written,
220                              GError    **error)
221 {
222   GZlibDecompressor *decompressor;
223   gsize header_size;
224   int res;
225
226   decompressor = G_ZLIB_DECOMPRESSOR (converter);
227
228   decompressor->zstream.next_in = (void *)inbuf;
229   decompressor->zstream.avail_in = inbuf_size;
230
231   decompressor->zstream.next_out = outbuf;
232   decompressor->zstream.avail_out = outbuf_size;
233
234   res = inflate (&decompressor->zstream, Z_NO_FLUSH);
235
236   if (res == Z_DATA_ERROR || res == Z_NEED_DICT)
237     {
238       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
239                            _("Invalid compressed data"));
240       return G_CONVERTER_ERROR;
241     }
242
243   if (res == Z_MEM_ERROR)
244     {
245       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
246                            _("Not enough memory"));
247       return G_CONVERTER_ERROR;
248     }
249
250     if (res == Z_STREAM_ERROR)
251     {
252       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
253                    _("Internal error: %s"), decompressor->zstream.msg);
254       return G_CONVERTER_ERROR;
255     }
256
257     if (res == Z_BUF_ERROR)
258       {
259         if (flags & G_CONVERTER_FLUSH)
260           return G_CONVERTER_FLUSHED;
261
262         /* Z_FINISH not set, so this means no progress could be made */
263         /* We do have output space, so this should only happen if we
264            have no input but need some */
265
266         g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT,
267                              _("Need more input"));
268         return G_CONVERTER_ERROR;
269       }
270
271   if (res == Z_OK || res == Z_STREAM_END)
272     {
273       *bytes_read = inbuf_size - decompressor->zstream.avail_in;
274       *bytes_written = outbuf_size - decompressor->zstream.avail_out;
275
276       if (res == Z_STREAM_END)
277         return G_CONVERTER_FINISHED;
278       return G_CONVERTER_CONVERTED;
279     }
280
281   g_assert_not_reached ();
282 }
283
284 static void
285 g_zlib_decompressor_iface_init (GConverterIface *iface)
286 {
287   iface->convert = g_zlib_decompressor_convert;
288   iface->reset = g_zlib_decompressor_reset;
289 }
290
291 #define __G_ZLIB_DECOMPRESSOR_C__
292 #include "gioaliasdef.c"