summaryrefslogtreecommitdiff
path: root/libsoup/soup-coding-gzip.c
diff options
context:
space:
mode:
authorDan Winship <danw@gnome.org>2008-03-15 09:52:35 -0400
committerDan Winship <danw@gnome.org>2009-12-16 15:40:29 +0100
commit35e78b4ded68e5d6550d51ec161ff0034fd3736b (patch)
treee1f159185ed8ac8fcc8ceeef096b0b280f36c65c /libsoup/soup-coding-gzip.c
parent5a6e1e873e13e1bc77298b501ff6f7a66fadcb63 (diff)
downloadlibsoup-35e78b4ded68e5d6550d51ec161ff0034fd3736b.tar.gz
Content-Encoding support
Adds SoupContentDecoder, which provides support for decoding "gzip" Content-Encoding. For now other types are not supported and can't be added. The SoupCoding interface is private because it will eventually be replaced with something GConverter-based. https://bugzilla.gnome.org/show_bug.cgi?id=522772
Diffstat (limited to 'libsoup/soup-coding-gzip.c')
-rw-r--r--libsoup/soup-coding-gzip.c142
1 files changed, 142 insertions, 0 deletions
diff --git a/libsoup/soup-coding-gzip.c b/libsoup/soup-coding-gzip.c
new file mode 100644
index 00000000..b1731d57
--- /dev/null
+++ b/libsoup/soup-coding-gzip.c
@@ -0,0 +1,142 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-coding-gzip.c: "gzip" coding
+ *
+ * Copyright (C) 2005 Novell, Inc.
+ * Copyright (C) 2008 Red Hat, Inc.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "soup-coding-gzip.h"
+
+#include <zlib.h>
+
+typedef struct {
+ z_stream stream;
+
+} SoupCodingGzipPrivate;
+#define SOUP_CODING_GZIP_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_CODING_GZIP, SoupCodingGzipPrivate))
+
+G_DEFINE_TYPE (SoupCodingGzip, soup_coding_gzip, SOUP_TYPE_CODING)
+
+static void constructed (GObject *object);
+static void finalize (GObject *object);
+static SoupCodingStatus apply_into (SoupCoding *coding,
+ gconstpointer input, gsize input_length,
+ gsize *input_used,
+ gpointer output, gsize output_length,
+ gsize *output_used,
+ gboolean done, GError **error);
+
+static void
+soup_coding_gzip_init (SoupCodingGzip *gzip)
+{
+ SoupCodingGzipPrivate *priv = SOUP_CODING_GZIP_GET_PRIVATE (gzip);
+
+ priv->stream.zalloc = Z_NULL;
+ priv->stream.zfree = Z_NULL;
+ priv->stream.opaque = Z_NULL;
+}
+
+static void
+soup_coding_gzip_class_init (SoupCodingGzipClass *gzip_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (gzip_class);
+ SoupCodingClass *coding_class = SOUP_CODING_CLASS (gzip_class);
+
+ g_type_class_add_private (gzip_class, sizeof (SoupCodingGzipPrivate));
+
+ coding_class->name = "gzip";
+
+ object_class->constructed = constructed;
+ object_class->finalize = finalize;
+
+ coding_class->apply_into = apply_into;
+}
+
+static void
+constructed (GObject *object)
+{
+ SoupCodingGzipPrivate *priv = SOUP_CODING_GZIP_GET_PRIVATE (object);
+
+ /* All of these values are the defaults according to the zlib
+ * documentation. "16" is a magic number that means gzip
+ * instead of zlib.
+ */
+ if (SOUP_CODING (object)->direction == SOUP_CODING_ENCODE) {
+ deflateInit2 (&priv->stream, Z_DEFAULT_COMPRESSION,
+ Z_DEFLATED, MAX_WBITS | 16, 8,
+ Z_DEFAULT_STRATEGY);
+ } else
+ inflateInit2 (&priv->stream, MAX_WBITS | 16);
+}
+
+static void
+finalize (GObject *object)
+{
+ SoupCodingGzipPrivate *priv = SOUP_CODING_GZIP_GET_PRIVATE (object);
+
+ if (SOUP_CODING (object)->direction == SOUP_CODING_ENCODE)
+ deflateEnd (&priv->stream);
+ else
+ inflateEnd (&priv->stream);
+
+ G_OBJECT_CLASS (soup_coding_gzip_parent_class)->finalize (object);
+}
+
+static SoupCodingStatus
+apply_into (SoupCoding *coding,
+ gconstpointer input, gsize input_length, gsize *input_used,
+ gpointer output, gsize output_length, gsize *output_used,
+ gboolean done, GError **error)
+{
+ SoupCodingGzipPrivate *priv = SOUP_CODING_GZIP_GET_PRIVATE (coding);
+ int ret;
+
+ priv->stream.avail_in = input_length;
+ priv->stream.next_in = (gpointer)input;
+ priv->stream.total_in = 0;
+
+ priv->stream.avail_out = output_length;
+ priv->stream.next_out = output;
+ priv->stream.total_out = 0;
+
+ if (coding->direction == SOUP_CODING_ENCODE)
+ ret = deflate (&priv->stream, done ? Z_FINISH : Z_NO_FLUSH);
+ else
+ ret = inflate (&priv->stream, Z_SYNC_FLUSH);
+
+ *input_used = priv->stream.total_in;
+ *output_used = priv->stream.total_out;
+
+ switch (ret) {
+ case Z_NEED_DICT:
+ case Z_DATA_ERROR:
+ case Z_STREAM_ERROR:
+ g_set_error_literal (error, SOUP_CODING_ERROR,
+ SOUP_CODING_ERROR_DATA_ERROR,
+ priv->stream.msg ? priv->stream.msg : "Bad data");
+ return SOUP_CODING_STATUS_ERROR;
+
+ case Z_BUF_ERROR:
+ case Z_MEM_ERROR:
+ g_set_error_literal (error, SOUP_CODING_ERROR,
+ SOUP_CODING_ERROR_INTERNAL_ERROR,
+ priv->stream.msg ? priv->stream.msg : "Internal error");
+ return SOUP_CODING_STATUS_ERROR;
+
+ case Z_STREAM_END:
+ return SOUP_CODING_STATUS_COMPLETE;
+
+ case Z_OK:
+ default:
+ if (*output_used == output_length &&
+ *input_used < input_length)
+ return SOUP_CODING_STATUS_NEED_SPACE;
+ else
+ return SOUP_CODING_STATUS_OK;
+ }
+}