summaryrefslogtreecommitdiff
path: root/libsoup/soup-coding.c
diff options
context:
space:
mode:
Diffstat (limited to 'libsoup/soup-coding.c')
-rw-r--r--libsoup/soup-coding.c258
1 files changed, 258 insertions, 0 deletions
diff --git a/libsoup/soup-coding.c b/libsoup/soup-coding.c
new file mode 100644
index 00000000..74c48268
--- /dev/null
+++ b/libsoup/soup-coding.c
@@ -0,0 +1,258 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-coding.c: Data encoding/decoding class
+ *
+ * Copyright (C) 2005 Novell, Inc.
+ * Copyright (C) 2008 Red Hat, Inc.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "soup-coding.h"
+#include "soup-enum-types.h"
+#include "soup-session-feature.h"
+
+static void soup_coding_session_feature_init (SoupSessionFeatureInterface *feature_interface, gpointer interface_data);
+
+G_DEFINE_TYPE_WITH_CODE (SoupCoding, soup_coding, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (SOUP_TYPE_SESSION_FEATURE,
+ soup_coding_session_feature_init))
+
+enum {
+ PROP_0,
+
+ PROP_DIRECTION,
+
+ LAST_PROP
+};
+
+static void set_property (GObject *object, guint prop_id,
+ const GValue *value, GParamSpec *pspec);
+static void get_property (GObject *object, guint prop_id,
+ GValue *value, GParamSpec *pspec);
+
+static SoupBuffer *apply (SoupCoding *coding,
+ gconstpointer input, gsize input_length,
+ gboolean done, GError **error);
+
+static void
+soup_coding_class_init (SoupCodingClass *coding_class)
+{
+ GObjectClass *object_class = (GObjectClass *)coding_class;
+
+ object_class->set_property = set_property;
+ object_class->get_property = get_property;
+
+ coding_class->apply = apply;
+
+ /* properties */
+ g_object_class_install_property (
+ object_class, PROP_DIRECTION,
+#if 0
+ g_param_spec_enum (SOUP_CODING_DIRECTION,
+#else
+ g_param_spec_uint (SOUP_CODING_DIRECTION,
+#endif
+ "Direction",
+ "Whether to encode or decode",
+ 0, 2,
+ SOUP_CODING_ENCODE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+soup_coding_session_feature_init (SoupSessionFeatureInterface *feature_interface,
+ gpointer interface_data)
+{
+ ;
+}
+
+static void
+soup_coding_init (SoupCoding *coding)
+{
+ ;
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ SoupCoding *coding = SOUP_CODING (object);
+
+ switch (prop_id) {
+ case PROP_DIRECTION:
+#if 0
+ coding->direction = g_value_get_enum (value);
+#else
+ coding->direction = g_value_get_uint (value);
+#endif
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+ GValue *value, GParamSpec *pspec)
+{
+ SoupCoding *coding = SOUP_CODING (object);
+
+ switch (prop_id) {
+ case PROP_DIRECTION:
+#if 0
+ g_value_set_enum (value, coding->direction);
+#else
+ g_value_set_uint (value, coding->direction);
+#endif
+ break;
+ default:
+ break;
+ }
+}
+
+static SoupBuffer *
+apply (SoupCoding *coding,
+ gconstpointer input, gsize input_length,
+ gboolean done, GError **error)
+{
+ gsize outbuf_length, outbuf_used, outbuf_cur, input_used, input_cur;
+ char *outbuf;
+ SoupCodingStatus status;
+
+ if (coding->direction == SOUP_CODING_ENCODE)
+ outbuf_length = MAX (input_length / 2, 1024);
+ else
+ outbuf_length = MAX (input_length * 2, 1024);
+ outbuf = g_malloc (outbuf_length);
+ outbuf_cur = input_cur = 0;
+
+ do {
+ status = soup_coding_apply_into (
+ coding,
+ (guchar *)input + input_cur, input_length - input_cur,
+ &input_used,
+ outbuf + outbuf_cur, outbuf_length - outbuf_cur,
+ &outbuf_used,
+ done, error);
+ input_cur += input_used;
+ outbuf_cur += outbuf_used;
+
+ switch (status) {
+ case SOUP_CODING_STATUS_OK:
+ case SOUP_CODING_STATUS_COMPLETE:
+ break;
+
+ case SOUP_CODING_STATUS_NEED_SPACE:
+ outbuf_length *= 2;
+ outbuf = g_realloc (outbuf, outbuf_length);
+ break;
+
+ case SOUP_CODING_STATUS_ERROR:
+ default:
+ g_free (outbuf);
+ return NULL;
+ }
+ } while (input_cur < input_length ||
+ (done && status != SOUP_CODING_STATUS_COMPLETE));
+
+ if (outbuf_cur)
+ return soup_buffer_new (SOUP_MEMORY_TAKE, outbuf, outbuf_cur);
+ else {
+ g_free (outbuf);
+ return NULL;
+ }
+}
+
+/**
+ * soup_coding_apply:
+ * @coding: a #SoupCoding
+ * @input: input data
+ * @input_length: length of @input
+ * @done: %TRUE if this is the last piece of data to encode/decode
+ * @error: error pointer
+ *
+ * Applies @coding to @input_length bytes of data from @input, and
+ * returns a new #SoupBuffer containing the encoded/decoded data. If
+ * @done is %FALSE, the encoder may buffer some or all of the data in
+ * @input rather than outputting it right away. If @done is %TRUE, the
+ * encoder will flush any buffered data, and (if possible) verify that
+ * the input has reached the end of the stream.
+ *
+ * Return value: a #SoupBuffer containing the encoded/decoded data, or
+ * %NULL if no data can be returned at this point, or if an error
+ * occurred. (If you pass %NULL for @error, there is no way to
+ * distinguish the latter two cases).
+ **/
+SoupBuffer *
+soup_coding_apply (SoupCoding *coding,
+ gconstpointer input, gsize input_length,
+ gboolean done, GError **error)
+{
+ g_return_val_if_fail (SOUP_IS_CODING (coding), NULL);
+
+ return SOUP_CODING_GET_CLASS (coding)->apply (
+ coding, input, input_length, done, error);
+}
+
+/**
+ * SoupCodingStatus:
+ * @SOUP_CODING_STATUS_OK: Success
+ * @SOUP_CODING_STATUS_ERROR: An error occurred
+ * @SOUP_CODING_STATUS_NEED_SPACE: Output buffer was too small to
+ * output any data.
+ * @SOUP_CODING_STATUS_COMPLETE: The stream end has been reached and
+ * the output buffer contains the last bytes of encoded/decoded data.
+ *
+ * The result from a call to soup_coding_apply_into().
+ **/
+
+/**
+ * soup_coding_apply_into:
+ * @coding: a #SoupCoding
+ * @input: input data
+ * @input_length: length of @input
+ * @input_used: on return, contains the number of bytes of @input that
+ * were encoded/decoded.
+ * @output: output buffer
+ * @output_length: length of @output
+ * @output_used: on return, contains the number of bytes of @output that
+ * were filled with encoded/decoded data.
+ * @done: %TRUE if this is the last piece of data to encode/decode
+ * @error: error pointer
+ *
+ * Applies @coding to @input_length bytes of data from @input, and
+ * outputs between %0 and @output_length encoded/decoded bytes into
+ * @output. @input and @output may not overlap.
+ *
+ * Return value: the status; %SOUP_CODING_STATUS_OK on intermediate
+ * success, %SOUP_CODING_STATUS_COMPLETE if the stream has been fully
+ * encoded/decoded, %SOUP_CODING_STATUS_NEED_SPACE if a larger
+ * @output_length is required to make progress, or
+ * %SOUP_CODING_STATUS_ERROR on error (in which case @error will be
+ * set).
+ **/
+SoupCodingStatus
+soup_coding_apply_into (SoupCoding *coding,
+ gconstpointer input, gsize input_length, gsize *input_used,
+ gpointer output, gsize output_length, gsize *output_used,
+ gboolean done, GError **error)
+{
+ g_return_val_if_fail (SOUP_IS_CODING (coding), 0);
+
+ return SOUP_CODING_GET_CLASS (coding)->apply_into (
+ coding, input, input_length, input_used,
+ output, output_length, output_used,
+ done, error);
+}
+
+GQuark
+soup_coding_error_quark (void)
+{
+ static GQuark error;
+ if (!error)
+ error = g_quark_from_static_string ("soup_coding_error_quark");
+ return error;
+}