Merge remote branch 'gvdb/master'
[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 #GConverter 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 if (decompressor->format == G_ZLIB_COMPRESSOR_FORMAT_RAW)
148     {
149       /* Negative for gzip */
150       res = inflateInit2 (&decompressor->zstream, -MAX_WBITS);
151     }
152   else /* ZLIB */
153     res = inflateInit (&decompressor->zstream);
154
155   if (res == Z_MEM_ERROR )
156     g_error ("GZlibDecompressor: Not enough memory for zlib use");
157
158   if (res != Z_OK)
159     g_warning ("unexpected zlib error: %s\n", decompressor->zstream.msg);
160 }
161
162 static void
163 g_zlib_decompressor_class_init (GZlibDecompressorClass *klass)
164 {
165   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
166
167   gobject_class->finalize = g_zlib_decompressor_finalize;
168   gobject_class->constructed = g_zlib_decompressor_constructed;
169   gobject_class->get_property = g_zlib_decompressor_get_property;
170   gobject_class->set_property = g_zlib_decompressor_set_property;
171
172   g_object_class_install_property (gobject_class,
173                                    PROP_FORMAT,
174                                    g_param_spec_enum ("format",
175                                                       P_("compression format"),
176                                                       P_("The format of the compressed data"),
177                                                       G_TYPE_ZLIB_COMPRESSOR_FORMAT,
178                                                       G_ZLIB_COMPRESSOR_FORMAT_ZLIB,
179                                                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
180                                                       G_PARAM_STATIC_STRINGS));
181 }
182
183 /**
184  * g_zlib_decompressor_new:
185  * @format: The format to use for the compressed data
186  *
187  * Creates a new #GZlibDecompressor.
188  *
189  * Returns: a new #GZlibDecompressor
190  *
191  * Since: 2.24
192  **/
193 GZlibDecompressor *
194 g_zlib_decompressor_new (GZlibCompressorFormat format)
195 {
196   GZlibDecompressor *decompressor;
197
198   decompressor = g_object_new (G_TYPE_ZLIB_DECOMPRESSOR,
199                                "format", format,
200                                NULL);
201
202   return decompressor;
203 }
204
205 static void
206 g_zlib_decompressor_reset (GConverter *converter)
207 {
208   GZlibDecompressor *decompressor = G_ZLIB_DECOMPRESSOR (converter);
209   int res;
210
211   res = inflateReset (&decompressor->zstream);
212   if (res != Z_OK)
213     g_warning ("unexpected zlib error: %s\n", decompressor->zstream.msg);
214 }
215
216 static GConverterResult
217 g_zlib_decompressor_convert (GConverter *converter,
218                              const void *inbuf,
219                              gsize       inbuf_size,
220                              void       *outbuf,
221                              gsize       outbuf_size,
222                              GConverterFlags flags,
223                              gsize      *bytes_read,
224                              gsize      *bytes_written,
225                              GError    **error)
226 {
227   GZlibDecompressor *decompressor;
228   int res;
229
230   decompressor = G_ZLIB_DECOMPRESSOR (converter);
231
232   decompressor->zstream.next_in = (void *)inbuf;
233   decompressor->zstream.avail_in = inbuf_size;
234
235   decompressor->zstream.next_out = outbuf;
236   decompressor->zstream.avail_out = outbuf_size;
237
238   res = inflate (&decompressor->zstream, Z_NO_FLUSH);
239
240   if (res == Z_DATA_ERROR || res == Z_NEED_DICT)
241     {
242       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
243                            _("Invalid compressed data"));
244       return G_CONVERTER_ERROR;
245     }
246
247   if (res == Z_MEM_ERROR)
248     {
249       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
250                            _("Not enough memory"));
251       return G_CONVERTER_ERROR;
252     }
253
254     if (res == Z_STREAM_ERROR)
255     {
256       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
257                    _("Internal error: %s"), decompressor->zstream.msg);
258       return G_CONVERTER_ERROR;
259     }
260
261     if (res == Z_BUF_ERROR)
262       {
263         if (flags & G_CONVERTER_FLUSH)
264           return G_CONVERTER_FLUSHED;
265
266         /* Z_FINISH not set, so this means no progress could be made */
267         /* We do have output space, so this should only happen if we
268            have no input but need some */
269
270         g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT,
271                              _("Need more input"));
272         return G_CONVERTER_ERROR;
273       }
274
275   if (res == Z_OK || res == Z_STREAM_END)
276     {
277       *bytes_read = inbuf_size - decompressor->zstream.avail_in;
278       *bytes_written = outbuf_size - decompressor->zstream.avail_out;
279
280       if (res == Z_STREAM_END)
281         return G_CONVERTER_FINISHED;
282       return G_CONVERTER_CONVERTED;
283     }
284
285   g_assert_not_reached ();
286 }
287
288 static void
289 g_zlib_decompressor_iface_init (GConverterIface *iface)
290 {
291   iface->convert = g_zlib_decompressor_convert;
292   iface->reset = g_zlib_decompressor_reset;
293 }
294
295 #define __G_ZLIB_DECOMPRESSOR_C__
296 #include "gioaliasdef.c"