From 92b9218cbf8cbc594c3a067b2dc09730416df85f Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Fri, 20 Nov 2009 12:04:31 +0100 Subject: [PATCH] Add GZlibCompressor --- gio/Makefile.am | 2 + gio/gio.h | 1 + gio/giotypes.h | 1 + gio/gzlibcompressor.c | 316 ++++++++++++++++++++++++++++++++++++++++++ gio/gzlibcompressor.h | 51 +++++++ 5 files changed, 371 insertions(+) create mode 100644 gio/gzlibcompressor.c create mode 100644 gio/gzlibcompressor.h diff --git a/gio/Makefile.am b/gio/Makefile.am index f508fdf43..f5fd0450f 100644 --- a/gio/Makefile.am +++ b/gio/Makefile.am @@ -265,6 +265,7 @@ libgio_2_0_la_SOURCES = \ gvfs.c \ gvolume.c \ gvolumemonitor.c \ + gzlibcompressor.c \ gzlibdecompressor.c \ gmountprivate.h \ gioenumtypes.h \ @@ -391,6 +392,7 @@ gio_headers = \ gvfs.h \ gvolume.h \ gvolumemonitor.h \ + gzlibcompressor.h \ gzlibdecompressor.h \ $(NULL) diff --git a/gio/gio.h b/gio/gio.h index 218e96742..861f17231 100644 --- a/gio/gio.h +++ b/gio/gio.h @@ -93,6 +93,7 @@ #include #include #include +#include #include #undef __GIO_GIO_H_INSIDE__ diff --git a/gio/giotypes.h b/gio/giotypes.h index 1a283d1be..1e67b0b22 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 _GZlibCompressor GZlibCompressor; typedef struct _GZlibDecompressor GZlibDecompressor; /** diff --git a/gio/gzlibcompressor.c b/gio/gzlibcompressor.c new file mode 100644 index 000000000..20fd8ff0f --- /dev/null +++ b/gio/gzlibcompressor.c @@ -0,0 +1,316 @@ +/* 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 "gzlibcompressor.h" +#include "glib.h" +#include "gioerror.h" +#include "glibintl.h" +#include "gioenums.h" +#include "gioenumtypes.h" + +#include "gioalias.h" + +enum { + PROP_0, + PROP_FORMAT, + PROP_LEVEL +}; + +/** + * SECTION:gzcompressor + * @short_description: Zlib compressor + * @include: gio/gio.h + * + * #GZlibCompressor is an implementation of #GCompressor that + * decompresses data compressed with zlib. + */ + +static void g_zlib_compressor_iface_init (GConverterIface *iface); + +/** + * GZlibCompressor: + * + * Zlib decompression + */ +struct _GZlibCompressor +{ + GObject parent_instance; + + GZlibCompressorFormat format; + int level; + z_stream zstream; +}; + +G_DEFINE_TYPE_WITH_CODE (GZlibCompressor, g_zlib_compressor, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER, + g_zlib_compressor_iface_init)) + +static void +g_zlib_compressor_finalize (GObject *object) +{ + GZlibCompressor *compressor; + + compressor = G_ZLIB_COMPRESSOR (object); + + deflateEnd (&compressor->zstream); + + G_OBJECT_CLASS (g_zlib_compressor_parent_class)->finalize (object); +} + + +static void +g_zlib_compressor_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GZlibCompressor *compressor; + + compressor = G_ZLIB_COMPRESSOR (object); + + switch (prop_id) + { + case PROP_FORMAT: + compressor->format = g_value_get_enum (value); + break; + + case PROP_LEVEL: + compressor->level = g_value_get_int (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + +} + +static void +g_zlib_compressor_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GZlibCompressor *compressor; + + compressor = G_ZLIB_COMPRESSOR (object); + + switch (prop_id) + { + case PROP_FORMAT: + g_value_set_enum (value, compressor->format); + break; + + case PROP_LEVEL: + g_value_set_int (value, compressor->level); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +g_zlib_compressor_init (GZlibCompressor *compressor) +{ +} + +static void +g_zlib_compressor_constructed (GObject *object) +{ + GZlibCompressor *compressor; + int res; + + compressor = G_ZLIB_COMPRESSOR (object); + + if (compressor->format == G_ZLIB_COMPRESSOR_FORMAT_GZIP) + { + /* + 16 for gzip */ + res = deflateInit2 (&compressor->zstream, + compressor->level, Z_DEFLATED, + MAX_WBITS + 16, 8, + Z_DEFAULT_STRATEGY); + } + else + res = deflateInit (&compressor->zstream, compressor->level); + + if (res == Z_MEM_ERROR ) + g_error ("GZlibCompressor: Not enough memory for zlib use"); + + if (res != Z_OK) + g_warning ("unexpected zlib error: %s\n", compressor->zstream.msg); +} + +static void +g_zlib_compressor_class_init (GZlibCompressorClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = g_zlib_compressor_finalize; + gobject_class->constructed = g_zlib_compressor_constructed; + gobject_class->get_property = g_zlib_compressor_get_property; + gobject_class->set_property = g_zlib_compressor_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_object_class_install_property (gobject_class, + PROP_LEVEL, + g_param_spec_int ("level", + P_("compression level"), + P_("The level of compression from 0 (no compression) to 9 (most compression), -1 for the default level"), + -1, 9, + -1, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); +} + +/** + * g_zlib_compressor_new: + * @format: The format to use for the compressed data + * @level: compression level (0-9), -1 for default + * + * Creates a new #GZlibCompressor. + * + * Returns: a new #GZlibCompressor + * + * Since: 2.24 + **/ +GZlibCompressor * +g_zlib_compressor_new (GZlibCompressorFormat format, + int level) +{ + GZlibCompressor *compressor; + + compressor = g_object_new (G_TYPE_ZLIB_COMPRESSOR, + "format", format, + "level", level, + NULL); + + return compressor; +} + +static void +g_zlib_compressor_reset (GConverter *converter) +{ + GZlibCompressor *compressor = G_ZLIB_COMPRESSOR (converter); + int res; + + res = deflateReset (&compressor->zstream); + if (res != Z_OK) + g_warning ("unexpected zlib error: %s\n", compressor->zstream.msg); +} + +static GConverterResult +g_zlib_compressor_convert (GConverter *converter, + const void *inbuf, + gsize inbuf_size, + void *outbuf, + gsize outbuf_size, + GConverterFlags flags, + gsize *bytes_read, + gsize *bytes_written, + GError **error) +{ + GZlibCompressor *compressor; + int res; + int flush; + + compressor = G_ZLIB_COMPRESSOR (converter); + + compressor->zstream.next_in = (void *)inbuf; + compressor->zstream.avail_in = inbuf_size; + + compressor->zstream.next_out = outbuf; + compressor->zstream.avail_out = outbuf_size; + + flush = Z_NO_FLUSH; + if (flags & G_CONVERTER_INPUT_AT_END) + flush = Z_FINISH; + else if (flags & G_CONVERTER_FLUSH) + flush = Z_SYNC_FLUSH; + + res = deflate (&compressor->zstream, flush); + + 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"), compressor->zstream.msg); + return G_CONVERTER_ERROR; + } + + if (res == Z_BUF_ERROR) + { + if (flags & G_CONVERTER_FLUSH) + return G_CONVERTER_FLUSHED; + + /* 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 - compressor->zstream.avail_in; + *bytes_written = outbuf_size - compressor->zstream.avail_out; + + if (res == Z_STREAM_END) + return G_CONVERTER_FINISHED; + return G_CONVERTER_CONVERTED; + } + + g_assert_not_reached (); +} + +static void +g_zlib_compressor_iface_init (GConverterIface *iface) +{ + iface->convert = g_zlib_compressor_convert; + iface->reset = g_zlib_compressor_reset; +} + +#define __G_ZLIB_COMPRESSOR_C__ +#include "gioaliasdef.c" diff --git a/gio/gzlibcompressor.h b/gio/gzlibcompressor.h new file mode 100644 index 000000000..7f6d80f79 --- /dev/null +++ b/gio/gzlibcompressor.h @@ -0,0 +1,51 @@ +/* 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_COMPRESSOR_H__ +#define __G_ZLIB_COMPRESSOR_H__ + +#include + +G_BEGIN_DECLS + +#define G_TYPE_ZLIB_COMPRESSOR (g_zlib_compressor_get_type ()) +#define G_ZLIB_COMPRESSOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_ZLIB_COMPRESSOR, GZlibCompressor)) +#define G_ZLIB_COMPRESSOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_ZLIB_COMPRESSOR, GZlibCompressorClass)) +#define G_IS_ZLIB_COMPRESSOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_ZLIB_COMPRESSOR)) +#define G_IS_ZLIB_COMPRESSOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_ZLIB_COMPRESSOR)) +#define G_ZLIB_COMPRESSOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_ZLIB_COMPRESSOR, GZlibCompressorClass)) + +typedef struct _GZlibCompressorClass GZlibCompressorClass; + +struct _GZlibCompressorClass +{ + GObjectClass parent_class; +}; + +GType g_zlib_compressor_get_type (void) G_GNUC_CONST; + +GZlibCompressor *g_zlib_compressor_new (GZlibCompressorFormat format, + int level); + +G_END_DECLS + +#endif /* __G_ZLIB_COMPRESSOR_H__ */