#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 {
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) {
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);
}
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;
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) {
}
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;
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;
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:
--- /dev/null
+/* -*- 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;
+}
--- /dev/null
+/* -*- 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__ */