Add support for BZ2 compression using GIO
authorBastien Nocera <hadess@hadess.net>
Fri, 27 Nov 2009 14:41:11 +0000 (14:41 +0000)
committerStephane Delcroix <stephane_delcroix@mckinsey.com>
Fri, 5 Mar 2010 12:35:28 +0000 (13:35 +0100)
Makefile.am
configure.ac
io-xcf.c
yelp-bz2-decompressor.c [new file with mode: 0644]
yelp-bz2-decompressor.h [new file with mode: 0644]

index 29e1de2..f53b98b 100644 (file)
@@ -10,9 +10,19 @@ INCLUDES =                   \
 
 AM_CFLAGS = -g
 
-libioxcf_la_SOURCES = io-xcf.c
+BZ2_DECOMPRESSOR_FILES = yelp-bz2-decompressor.c yelp-bz2-decompressor.h
+
+if GIO_2_23
+BZ2_DECOMPRESSOR = $(BZ2_DECOMPRESSOR_FILES)
+else
+BZ2_DECOMPRESSOR =
+endif
+
+libioxcf_la_SOURCES = io-xcf.c $(BZ2_DECOMPRESSOR)
 libioxcf_la_LDFLAGS = -export_dynamic -avoid-version -module -no-undefined
 libioxcf_la_LIBADD =           \
        $(GDKPIXBUF_LIBS)       \
        $(GLIB_LIBS)            \
        $(GIO_LIBS)
+
+EXTRA_DIST = $(BZ2_DECOMPRESSOR_FILES)
index 7b0c4aa..25269cb 100644 (file)
@@ -1,5 +1,6 @@
 AC_INIT(io-xcf, 0.0.1, stephane@delcroix.org)
 AC_CONFIG_SRCDIR(.)
+AC_CONFIG_HEADERS([config.h])
 
 AM_INIT_AUTOMAKE
 
@@ -10,7 +11,12 @@ AC_PROG_LIBTOOL
 PKG_CHECK_MODULES(GLIB, glib-2.0)
 PKG_CHECK_MODULES(GMODULE, gmodule-2.0)
 PKG_CHECK_MODULES(GDKPIXBUF, gdk-pixbuf-2.0)
-PKG_CHECK_MODULES(GIO, gio-2.0 >= 2.23 gio-unix-2.0, AC_DEFINE(GIO_2_23),old_gio=1)
+PKG_CHECK_MODULES(GIO, gio-2.0 >= 2.23 gio-unix-2.0, old_gio=0, old_gio=1)
+
+if test "x$old_gio" = "x0"; then
+       AC_DEFINE(GIO_2_23, 1, [Define if GIO is newer than 2.23])
+fi
+AM_CONDITIONAL([GIO_2_23],[test "x$old_gio" != "x1"])
 
 AC_CHECK_HEADER(bzlib.h,,AC_MSG_ERROR(Can not find bzlib header))
 AC_CHECK_LIB(bz2,BZ2_bzDecompressInit,,AC_MSG_ERROR(Can not find libbz2))
index e47e525..cb480e9 100644 (file)
--- a/io-xcf.c
+++ b/io-xcf.c
 
 #define GDK_PIXBUF_ENABLE_BACKEND
 
+#include "config.h"
+
 #include <gmodule.h>
 #include <gdk-pixbuf/gdk-pixbuf.h>
 #include <gio/gio.h>
 #if GIO_2_23
-#include <gio/gzlibcompressor.h>
-#include <gio/gunixinputstream.h>
-#include <gio/gunixoutputstream.h>
+#include "yelp-bz2-decompressor.h"
 #endif
 #include <math.h>
 #include <string.h>
 #define LAYERMODE_GRAINEXTRACT 20
 #define LAYERMODE_GRAINMERGE   21
 
-#define FILETYPE_STREAMCLOSED  -1
-#define FILETYPE_UNKNOWN       0
-#define FILETYPE_XCF           1
-#define FILETYPE_XCF_BZ2       2
-#if GIO_2_23
-#define FILETYPE_XCF_GZ                3
-#endif
+enum {
+       FILETYPE_STREAMCLOSED = -1,
+       FILETYPE_UNKNOWN      = 0,
+       FILETYPE_XCF,
+       FILETYPE_XCF_BZ2,
+       FILETYPE_XCF_GZ
+};
 
 typedef struct _XcfContext XcfContext;
 struct _XcfContext {
@@ -1198,10 +1198,80 @@ xcf_image_load_real (FILE *f, XcfContext *context, GError **error)
 static GdkPixbuf*
 xcf_image_load (FILE *f, GError **error)
 {
-       guchar buffer[4];
-       fread (buffer, sizeof(guchar), 4, f);
+       guint type;
+
+       guchar buffer[8];
+       fread (buffer, sizeof(guchar), 8, f);
        rewind (f);
-       if (!strncmp (buffer, "BZh", 3)) { //Decompress the xcf.bz2 file to a temp file
+
+       if (!strncmp (buffer, "BZh", 3)) {
+               type = FILETYPE_XCF_BZ2;
+       } else if (!strncmp (buffer, "\x1f\x8b", 2)) {
+               type = FILETYPE_XCF_GZ;
+       } else if (!strncmp (buffer, "gimp xcf", 8)) {
+               type = FILETYPE_XCF;
+       } else {
+               g_set_error (error,
+                            GDK_PIXBUF_ERROR,
+                            GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
+                            "Unknown XCF file type");
+               return NULL;
+       }
+
+       if (type == FILETYPE_XCF)
+               return xcf_image_load_real (f, NULL, error);
+
+#if GIO_2_23
+       if (type == FILETYPE_XCF_BZ2 ||
+           type == FILETYPE_XCF_GZ) {
+               GConverter *decompressor;
+               GInputStream *input, *stream;
+
+               if (type == FILETYPE_XCF_BZ2)
+                       decompressor = G_CONVERTER (yelp_bz2_decompressor_new ());
+               else
+                       decompressor = G_CONVERTER (g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP));
+               input = g_unix_input_stream_new (fileno (f), FALSE);
+               stream = (GInputStream *) g_converter_input_stream_new (input, decompressor);
+               g_object_unref (decompressor);
+               g_object_unref (input);
+
+               gchar *tempname;
+               gint fd = g_file_open_tmp ("gdkpixbuf-xcf-tmp.XXXXXX", &tempname, NULL);
+               if (fd < 0) {
+                       gint save_errno = errno;
+                       g_set_error (error,
+                                       G_FILE_ERROR,
+                                       g_file_error_from_errno (save_errno),
+                                       "Failed to create temporary file when loading Xcf image");
+                       return NULL;
+               }
+               GOutputStream *output;
+               output = g_unix_output_stream_new (fd, TRUE);
+               if (!g_output_stream_splice (G_OUTPUT_STREAM (output), stream,
+                                            G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
+                                            NULL, NULL)) {
+                       LOG ("splicing failed\n");
+                       g_set_error (error,
+                                    GDK_PIXBUF_ERROR,
+                                    GDK_PIXBUF_ERROR_FAILED,
+                                    "Decompression error while loading Xcf.gz file");
+                       return NULL;
+               }
+
+               FILE *file;
+               file = fopen (tempname, "r");
+               g_unlink (tempname);
+               g_free (tempname);
+
+               GdkPixbuf *pixbuf = xcf_image_load_real (file, NULL, error);
+               fclose (file);
+
+               return pixbuf;
+       }
+#else
+       /* Decompress the xcf.bz2 file to a temp file */
+       if (type == FILETYPE_XCF_BZ2) {
                gchar *tempname;
                gint fd = g_file_open_tmp ("gdkpixbuf-xcf-tmp.XXXXXX", &tempname, NULL);
                if (fd < 0) {
@@ -1282,52 +1352,13 @@ xcf_image_load (FILE *f, GError **error)
                GdkPixbuf *pixbuf = xcf_image_load_real (file, NULL, error);
                fclose (file);
                return pixbuf;
-#if GIO_2_23
-       } else if (!strncmp (buffer, "\x1f\x8b", 2)) { //Decompress the .gz to a temp file
-               GZlibDecompressor *compressor;
-               GInputStream *input, *stream;
-
-               compressor = g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP);
-               input = g_unix_input_stream_new (fileno (f), FALSE);
-               stream = (GInputStream *) g_converter_input_stream_new (input, (GConverter *) (compressor));
-               g_object_unref (compressor);
-               g_object_unref (input);
-
-               gchar *tempname;
-               gint fd = g_file_open_tmp ("gdkpixbuf-xcf-tmp.XXXXXX", &tempname, NULL);
-               if (fd < 0) {
-                       gint save_errno = errno;
-                       g_set_error (error,
-                                       G_FILE_ERROR,
-                                       g_file_error_from_errno (save_errno),
-                                       "Failed to create temporary file when loading Xcf image");
-                       return NULL;
-               }
-               GOutputStream *output;
-               output = g_unix_output_stream_new (fd, TRUE);
-               if (!g_output_stream_splice (G_OUTPUT_STREAM (output), stream,
-                                            G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
-                                            NULL, NULL)) {
-                       LOG ("splicing failed\n");
-                       g_set_error (error,
-                                    GDK_PIXBUF_ERROR,
-                                    GDK_PIXBUF_ERROR_FAILED,
-                                    "Decompression error while loading Xcf.gz file");
-                       return NULL;
-               }
-
-               FILE *file;
-               file = fopen (tempname, "r");
-               g_unlink (tempname);
-               g_free (tempname);
-
-               GdkPixbuf *pixbuf = xcf_image_load_real (file, NULL, error);
-               fclose (file);
-
-               return pixbuf;
+       } else {
+               g_set_error (error,
+                            GDK_PIXBUF_ERROR,
+                            GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
+                            "Unhandled XCF file type");
+       }
 #endif
-       } else
-               return xcf_image_load_real (f, NULL, error);
 }
 
 
@@ -1387,22 +1418,9 @@ xcf_image_stop_load (gpointer data, GError **error)
 
        g_return_val_if_fail (data, TRUE);
 
-       if (context->type == FILETYPE_XCF ||
-           context->type == FILETYPE_XCF_BZ2) {
-               fflush (context->file);
-               rewind (context->file);
-               if (context->tempname) {
-                       g_unlink (context->tempname);
-                       g_free (context->tempname);
-                       context->tempname = NULL;
-               }
-               GdkPixbuf *pixbuf = xcf_image_load_real (context->file, context, error);
-               if (!pixbuf)
-                       retval = FALSE;
-               else
-                       g_object_unref (pixbuf);
 #if GIO_2_23
-       } else if (context->type == FILETYPE_XCF_GZ) {
+       if (context->type == FILETYPE_XCF_GZ ||
+           context->type == FILETYPE_XCF_BZ2) {
                g_object_unref (context->input);
                context->input = NULL;
 
@@ -1426,11 +1444,28 @@ xcf_image_stop_load (gpointer data, GError **error)
                        retval = FALSE;
                        goto bail;
                }
+               goto done;
+       }
 #endif
+       if (context->type == FILETYPE_XCF ||
+           context->type == FILETYPE_XCF_BZ2) {
+               fflush (context->file);
+               rewind (context->file);
+               if (context->tempname) {
+                       g_unlink (context->tempname);
+                       g_free (context->tempname);
+                       context->tempname = NULL;
+               }
+               GdkPixbuf *pixbuf = xcf_image_load_real (context->file, context, error);
+               if (!pixbuf)
+                       retval = FALSE;
+               else
+                       g_object_unref (pixbuf);
        } else {
                g_assert_not_reached ();
        }
 
+done:
        fflush (context->file);
        rewind (context->file);
        if (context->tempname) {
@@ -1475,11 +1510,30 @@ xcf_image_load_increment (gpointer data,
        }
 
        if (context->type == FILETYPE_UNKNOWN) { // first chunk
-               if (!strncmp (buf, "gimp xcf ", 9))
+               if (!strncmp (buf, "gimp xcf ", 9)) {
                        context->type = FILETYPE_XCF;
-               else if (!strncmp (buf, "BZh", 3)) {
+               else if (!strncmp (buf, "BZh", 3)) {
                        context->type = FILETYPE_XCF_BZ2;
+               } else if (!strncmp (buf, "\x1f\x8b", 2)) {
+                       context->type = FILETYPE_XCF_GZ;
+               }
 
+#if GIO_2_23
+               if (context->type == FILETYPE_XCF_GZ ||
+                   context->type == FILETYPE_XCF_BZ2) {
+                       GConverter *decompressor;
+
+                       if (context->type == FILETYPE_XCF_BZ2)
+                               decompressor = G_CONVERTER (yelp_bz2_decompressor_new ());
+                       else
+                               decompressor = G_CONVERTER (g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP));
+
+                       context->input = g_memory_input_stream_new ();
+                       context->stream = (GInputStream *) g_converter_input_stream_new (context->input, decompressor);
+                       g_object_unref (decompressor);
+               }
+#else
+               if (context->type == FILETYPE_XCF_BZ2) {
                        //Initialize bzlib
                        context->bz_stream = g_new (bz_stream, 1);
                        context->bz_stream->bzalloc = NULL;
@@ -1493,23 +1547,20 @@ xcf_image_load_increment (gpointer data,
                                context->bz_stream = NULL;
                                return FALSE;
                        }
-#if GIO_2_23
-               } else if (!strncmp (buf, "\x1f\x8b", 2)) {
-                       GZlibDecompressor *compressor;
-
-                       context->type = FILETYPE_XCF_GZ;
-                       compressor = g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP);
-
-                       context->input = g_memory_input_stream_new ();
-                       context->stream = (GInputStream *) g_converter_input_stream_new (context->input, (GConverter *) (compressor));
-                       g_object_unref (compressor);
-#endif
                }
+#endif
                LOG ("File type %d\n", context->type);
        }
 
        gchar *outbuf;
        switch (context->type) {
+#if GIO_2_23
+       case FILETYPE_XCF_GZ:
+       case FILETYPE_XCF_BZ2:
+               g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (context->input),
+                                                                      buf, size, NULL);
+               break;
+#else
        case FILETYPE_XCF_BZ2:
                outbuf = g_new (gchar, 65536);
                context->bz_stream->next_in = (gchar*)buf;
@@ -1563,11 +1614,6 @@ xcf_image_load_increment (gpointer data,
                   context->bz_stream = NULL;
                }
                break;
-#if GIO_2_23
-       case FILETYPE_XCF_GZ:
-               g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (context->input),
-                                                                      buf, size, NULL);
-               break;
 #endif
        case FILETYPE_XCF:
        default:
diff --git a/yelp-bz2-decompressor.c b/yelp-bz2-decompressor.c
new file mode 100644 (file)
index 0000000..98802ce
--- /dev/null
@@ -0,0 +1,173 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2009 Shaun McCance <shaunm@gnome.org>
+ *
+ * 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: Shaun McCance <shaunm@gnome.org>
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <string.h>
+
+#include <glib/gi18n.h>
+
+#include "yelp-bz2-decompressor.h"
+
+static void yelp_bz2_decompressor_iface_init          (GConverterIface *iface);
+
+struct _YelpBz2Decompressor
+{
+    GObject parent_instance;
+
+    bz_stream bzstream;
+};
+
+G_DEFINE_TYPE_WITH_CODE (YelpBz2Decompressor, yelp_bz2_decompressor, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER,
+                                                yelp_bz2_decompressor_iface_init))
+
+static void
+yelp_bz2_decompressor_finalize (GObject *object)
+{
+    YelpBz2Decompressor *decompressor;
+
+    decompressor = YELP_BZ2_DECOMPRESSOR (object);
+
+    BZ2_bzDecompressEnd (&decompressor->bzstream);
+
+    G_OBJECT_CLASS (yelp_bz2_decompressor_parent_class)->finalize (object);
+}
+
+static void
+yelp_bz2_decompressor_init (YelpBz2Decompressor *decompressor)
+{
+}
+
+static void
+yelp_bz2_decompressor_constructed (GObject *object)
+{
+    YelpBz2Decompressor *decompressor;
+    int res;
+
+    decompressor = YELP_BZ2_DECOMPRESSOR (object);
+
+    res = BZ2_bzDecompressInit (&decompressor->bzstream, 0, FALSE);
+
+    if (res == BZ_MEM_ERROR )
+        g_error ("YelpBz2Decompressor: Not enough memory for bzip2 use");
+
+    if (res != BZ_OK)
+        g_error ("YelpBz2Decompressor: Unexpected bzip2 error");
+}
+
+static void
+yelp_bz2_decompressor_class_init (YelpBz2DecompressorClass *klass)
+{
+    GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+    gobject_class->finalize = yelp_bz2_decompressor_finalize;
+    gobject_class->constructed = yelp_bz2_decompressor_constructed;
+}
+
+YelpBz2Decompressor *
+yelp_bz2_decompressor_new (void)
+{
+    YelpBz2Decompressor *decompressor;
+
+    decompressor = g_object_new (YELP_TYPE_BZ2_DECOMPRESSOR, NULL);
+
+    return decompressor;
+}
+
+static void
+yelp_bz2_decompressor_reset (GConverter *converter)
+{
+    YelpBz2Decompressor *decompressor = YELP_BZ2_DECOMPRESSOR (converter);
+    int res;
+
+    /* libbzip2 doesn't have a reset function.  Ending and reiniting
+     * might do the trick.  But this is untested.  If reset matters
+     * to you, test this.
+     */
+    BZ2_bzDecompressEnd (&decompressor->bzstream);
+    res = BZ2_bzDecompressInit (&decompressor->bzstream, 0, FALSE);
+
+    if (res == BZ_MEM_ERROR )
+        g_error ("YelpBz2Decompressor: Not enough memory for bzip2 use");
+
+    if (res != BZ_OK)
+        g_error ("YelpBz2Decompressor: Unexpected bzip2 error");
+}
+
+static GConverterResult
+yelp_bz2_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)
+{
+    YelpBz2Decompressor *decompressor;
+    gsize header_size;
+    int res;
+
+    decompressor = YELP_BZ2_DECOMPRESSOR (converter);
+
+    decompressor->bzstream.next_in = (void *)inbuf;
+    decompressor->bzstream.avail_in = inbuf_size;
+
+    decompressor->bzstream.next_out = outbuf;
+    decompressor->bzstream.avail_out = outbuf_size;
+
+    res = BZ2_bzDecompress (&decompressor->bzstream);
+
+    if (res == BZ_DATA_ERROR || res == BZ_DATA_ERROR_MAGIC) {
+        g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
+                             _("Invalid compressed data"));
+        return G_CONVERTER_ERROR;
+    }
+
+    if (res == BZ_MEM_ERROR) {
+        g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                             _("Not enough memory"));
+        return G_CONVERTER_ERROR;
+    }
+
+    if (res == BZ_OK || res == BZ_STREAM_END) {
+        *bytes_read = inbuf_size - decompressor->bzstream.avail_in;
+        *bytes_written = outbuf_size - decompressor->bzstream.avail_out;
+
+        if (res == BZ_STREAM_END)
+            return G_CONVERTER_FINISHED;
+        return G_CONVERTER_CONVERTED;
+    }
+
+    g_assert_not_reached ();
+}
+
+static void
+yelp_bz2_decompressor_iface_init (GConverterIface *iface)
+{
+  iface->convert = yelp_bz2_decompressor_convert;
+  iface->reset = yelp_bz2_decompressor_reset;
+}
diff --git a/yelp-bz2-decompressor.h b/yelp-bz2-decompressor.h
new file mode 100644 (file)
index 0000000..e067f26
--- /dev/null
@@ -0,0 +1,53 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 
+ * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2009 Shaun McCance <shaunm@gnome.org>
+ *
+ * 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: Shaun McCance <shaunm@gnome.org>
+ */
+
+#ifndef __YELP_BZ2_DECOMPRESSOR_H__
+#define __YELP_BZ2_DECOMPRESSOR_H__
+
+#include <gio/gio.h>
+#include <bzlib.h>
+
+G_BEGIN_DECLS
+
+#define YELP_TYPE_BZ2_DECOMPRESSOR         (yelp_bz2_decompressor_get_type ())
+#define YELP_BZ2_DECOMPRESSOR(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), YELP_TYPE_BZ2_DECOMPRESSOR, YelpBz2Decompressor))
+#define YELP_BZ2_DECOMPRESSOR_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), YELP_TYPE_BZ2_DECOMPRESSOR, YelpBz2DecompressorClass))
+#define YELP_IS_BZ2_DECOMPRESSOR(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), YELP_TYPE_BZ2_DECOMPRESSOR))
+#define YELP_IS_BZ2_DECOMPRESSOR_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), YELP_TYPE_BZ2_DECOMPRESSOR))
+#define YELP_BZ2_DECOMPRESSOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), YELP_TYPE_BZ2_DECOMPRESSOR, YelpBz2DecompressorClass))
+
+typedef struct _YelpBz2Decompressor        YelpBz2Decompressor;
+typedef struct _YelpBz2DecompressorClass   YelpBz2DecompressorClass;
+
+struct _YelpBz2DecompressorClass
+{
+    GObjectClass parent_class;
+};
+
+GType               yelp_bz2_decompressor_get_type (void);
+
+YelpBz2Decompressor *yelp_bz2_decompressor_new (void);
+
+G_END_DECLS
+
+#endif /* __YELP_BZ2_DECOMPRESSOR_H__ */