From: Alexander Larsson Date: Thu, 19 Nov 2009 16:20:20 +0000 (+0100) Subject: Add GZlibDecompressor for zlib decompression X-Git-Url: http://git.openbox.org/?a=commitdiff_plain;h=38c3eb14e42da8ca2d55918be048cf1729591486;p=dana%2Fcg-glib.git Add GZlibDecompressor for zlib decompression --- diff --git a/gio/Makefile.am b/gio/Makefile.am index 45c89429..f508fdf4 100644 --- a/gio/Makefile.am +++ b/gio/Makefile.am @@ -265,6 +265,7 @@ libgio_2_0_la_SOURCES = \ gvfs.c \ gvolume.c \ gvolumemonitor.c \ + gzlibdecompressor.c \ gmountprivate.h \ gioenumtypes.h \ gioenumtypes.c \ @@ -390,6 +391,7 @@ gio_headers = \ gvfs.h \ gvolume.h \ gvolumemonitor.h \ + gzlibdecompressor.h \ $(NULL) gioincludedir=$(includedir)/glib-2.0/gio/ diff --git a/gio/gio.h b/gio/gio.h index 9f3410d7..218e9674 100644 --- a/gio/gio.h +++ b/gio/gio.h @@ -93,6 +93,7 @@ #include #include #include +#include #undef __GIO_GIO_H_INSIDE__ diff --git a/gio/gioenums.h b/gio/gioenums.h index 808e223e..2c9433ea 100644 --- a/gio/gioenums.h +++ b/gio/gioenums.h @@ -673,6 +673,21 @@ typedef enum { G_SOCKET_PROTOCOL_SCTP = 132 } GSocketProtocol; +/** + * GZlibCompressorFormat: + * @G_ZLIB_COMRESSOR_FORMAT_RAW: Raw zlib compression data + * @G_ZLIB_COMRESSOR_FORMAT_GZIP: gzip file format + * + * Used to select the type of data format to use for #GZlibDecompressor + * and #GZlibCompressor. + * + * Since: 2.24 + */ +typedef enum { + G_ZLIB_COMPRESSOR_FORMAT_RAW, + G_ZLIB_COMPRESSOR_FORMAT_GZIP +} GZlibCompressorFormat; + G_END_DECLS #endif /* __GIO_ENUMS_H__ */ diff --git a/gio/giotypes.h b/gio/giotypes.h index 8c00891d..1a283d1b 100644 --- a/gio/giotypes.h +++ b/gio/giotypes.h @@ -43,6 +43,7 @@ typedef struct _GConverter GConverter; typedef struct _GConverterInputStream GConverterInputStream; typedef struct _GConverterOutputStream GConverterOutputStream; typedef struct _GDataInputStream GDataInputStream; +typedef struct _GZlibDecompressor GZlibDecompressor; /** * GDrive: diff --git a/gio/gzlibdecompressor.c b/gio/gzlibdecompressor.c new file mode 100644 index 00000000..e19c28e9 --- /dev/null +++ b/gio/gzlibdecompressor.c @@ -0,0 +1,292 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2009 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Alexander Larsson + */ + +#include "config.h" + +#include +#include +#include + +#include "gzlibdecompressor.h" +#include "glib.h" +#include "gioerror.h" +#include "glibintl.h" +#include "gioenums.h" +#include "gioenumtypes.h" + +#include "gioalias.h" + +enum { + PROP_0, + PROP_FORMAT +}; + +/** + * SECTION:gzdecompressor + * @short_description: Zlib decompressor + * @include: gio/gio.h + * + * #GZlibDecompressor is an implementation of #GDecompressor that + * decompresses data compressed with zlib. + */ + +static void g_zlib_decompressor_iface_init (GConverterIface *iface); + +/** + * GZlibDecompressor: + * + * Zlib decompression + */ +struct _GZlibDecompressor +{ + GObject parent_instance; + + GZlibCompressorFormat format; + z_stream zstream; +}; + +G_DEFINE_TYPE_WITH_CODE (GZlibDecompressor, g_zlib_decompressor, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER, + g_zlib_decompressor_iface_init)) + +static void +g_zlib_decompressor_finalize (GObject *object) +{ + GZlibDecompressor *decompressor; + + decompressor = G_ZLIB_DECOMPRESSOR (object); + + inflateEnd (&decompressor->zstream); + + G_OBJECT_CLASS (g_zlib_decompressor_parent_class)->finalize (object); +} + + +static void +g_zlib_decompressor_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GZlibDecompressor *decompressor; + + decompressor = G_ZLIB_DECOMPRESSOR (object); + + switch (prop_id) + { + case PROP_FORMAT: + decompressor->format = g_value_get_enum (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + +} + +static void +g_zlib_decompressor_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GZlibDecompressor *decompressor; + + decompressor = G_ZLIB_DECOMPRESSOR (object); + + switch (prop_id) + { + case PROP_FORMAT: + g_value_set_enum (value, decompressor->format); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +g_zlib_decompressor_init (GZlibDecompressor *decompressor) +{ +} + +static void +g_zlib_decompressor_constructed (GObject *object) +{ + GZlibDecompressor *decompressor; + int res; + + decompressor = G_ZLIB_DECOMPRESSOR (object); + + if (decompressor->format == G_ZLIB_COMPRESSOR_FORMAT_GZIP) + { + /* + 16 for gzip */ + res = inflateInit2 (&decompressor->zstream, MAX_WBITS + 16); + } + else + res = inflateInit (&decompressor->zstream); + + if (res == Z_MEM_ERROR ) + g_error ("GZlibDecompressor: Not enough memory for zlib use"); + + if (res != Z_OK) + g_warning ("unexpected zlib error: %s\n", decompressor->zstream.msg); +} + +static void +g_zlib_decompressor_class_init (GZlibDecompressorClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = g_zlib_decompressor_finalize; + gobject_class->constructed = g_zlib_decompressor_constructed; + gobject_class->get_property = g_zlib_decompressor_get_property; + gobject_class->set_property = g_zlib_decompressor_set_property; + + g_object_class_install_property (gobject_class, + PROP_FORMAT, + g_param_spec_enum ("format", + P_("compression format"), + P_("The format of the compressed data"), + G_TYPE_ZLIB_COMPRESSOR_FORMAT, + G_ZLIB_COMPRESSOR_FORMAT_RAW, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); +} + +/** + * g_zlib_decompressor_new: + * @format: The format to use for the compressed data + * + * Creates a new #GZlibDecompressor. + * + * Returns: a new #GZlibDecompressor + * + * Since: 2.24 + **/ +GZlibDecompressor * +g_zlib_decompressor_new (GZlibCompressorFormat format) +{ + GZlibDecompressor *decompressor; + + decompressor = g_object_new (G_TYPE_ZLIB_DECOMPRESSOR, + "format", format, + NULL); + + return decompressor; +} + +static void +g_zlib_decompressor_reset (GConverter *converter) +{ + GZlibDecompressor *decompressor = G_ZLIB_DECOMPRESSOR (converter); + int res; + + res = inflateReset (&decompressor->zstream); + if (res != Z_OK) + g_warning ("unexpected zlib error: %s\n", decompressor->zstream.msg); +} + +static GConverterResult +g_zlib_decompressor_convert (GConverter *converter, + const void *inbuf, + gsize inbuf_size, + void *outbuf, + gsize outbuf_size, + GConverterFlags flags, + gsize *bytes_read, + gsize *bytes_written, + GError **error) +{ + GZlibDecompressor *decompressor; + gsize header_size; + int res; + + decompressor = G_ZLIB_DECOMPRESSOR (converter); + + decompressor->zstream.next_in = (void *)inbuf; + decompressor->zstream.avail_in = inbuf_size; + + decompressor->zstream.next_out = outbuf; + decompressor->zstream.avail_out = outbuf_size; + + res = inflate (&decompressor->zstream, Z_NO_FLUSH); + + if (res == Z_DATA_ERROR || res == Z_NEED_DICT) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, + _("Invalid compressed data")); + return G_CONVERTER_ERROR; + } + + if (res == Z_MEM_ERROR) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + _("Not enough memory")); + return G_CONVERTER_ERROR; + } + + if (res == Z_STREAM_ERROR) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + _("Internal error: %s"), decompressor->zstream.msg); + return G_CONVERTER_ERROR; + } + + if (res == Z_BUF_ERROR) + { + if (flags & G_CONVERTER_FLUSH) + return G_CONVERTER_FLUSHED; + + /* Z_FINISH not set, so this means no progress could be made */ + /* We do have output space, so this should only happen if we + have no input but need some */ + + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT, + _("Need more input")); + return G_CONVERTER_ERROR; + } + + if (res == Z_OK || res == Z_STREAM_END) + { + *bytes_read = inbuf_size - decompressor->zstream.avail_in; + *bytes_written = outbuf_size - decompressor->zstream.avail_out; + + if (res == Z_STREAM_END) + return G_CONVERTER_FINISHED; + return G_CONVERTER_CONVERTED; + } + + g_assert_not_reached (); +} + +static void +g_zlib_decompressor_iface_init (GConverterIface *iface) +{ + iface->convert = g_zlib_decompressor_convert; + iface->reset = g_zlib_decompressor_reset; +} + +#define __G_ZLIB_DECOMPRESSOR_C__ +#include "gioaliasdef.c" diff --git a/gio/gzlibdecompressor.h b/gio/gzlibdecompressor.h new file mode 100644 index 00000000..a2ec7b38 --- /dev/null +++ b/gio/gzlibdecompressor.h @@ -0,0 +1,50 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2009 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Alexander Larsson + */ + +#ifndef __G_ZLIB_DECOMPRESSOR_H__ +#define __G_ZLIB_DECOMPRESSOR_H__ + +#include + +G_BEGIN_DECLS + +#define G_TYPE_ZLIB_DECOMPRESSOR (g_zlib_decompressor_get_type ()) +#define G_ZLIB_DECOMPRESSOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_ZLIB_DECOMPRESSOR, GZlibDecompressor)) +#define G_ZLIB_DECOMPRESSOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_ZLIB_DECOMPRESSOR, GZlibDecompressorClass)) +#define G_IS_ZLIB_DECOMPRESSOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_ZLIB_DECOMPRESSOR)) +#define G_IS_ZLIB_DECOMPRESSOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_ZLIB_DECOMPRESSOR)) +#define G_ZLIB_DECOMPRESSOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_ZLIB_DECOMPRESSOR, GZlibDecompressorClass)) + +typedef struct _GZlibDecompressorClass GZlibDecompressorClass; + +struct _GZlibDecompressorClass +{ + GObjectClass parent_class; +}; + +GType g_zlib_decompressor_get_type (void) G_GNUC_CONST; + +GZlibDecompressor *g_zlib_decompressor_new (GZlibCompressorFormat format); + +G_END_DECLS + +#endif /* __G_ZLIB_DECOMPRESSOR_H__ */