summaryrefslogtreecommitdiff
path: root/libsoup/soup-form.c
diff options
context:
space:
mode:
Diffstat (limited to 'libsoup/soup-form.c')
-rw-r--r--libsoup/soup-form.c163
1 files changed, 163 insertions, 0 deletions
diff --git a/libsoup/soup-form.c b/libsoup/soup-form.c
new file mode 100644
index 00000000..299fc884
--- /dev/null
+++ b/libsoup/soup-form.c
@@ -0,0 +1,163 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* soup-form.c : utility functions for HTML forms */
+
+/*
+ * Copyright 2008 Red Hat, Inc.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include "soup-form.h"
+
+#define XDIGIT(c) ((c) <= '9' ? (c) - '0' : ((c) & 0x4F) - 'A' + 10)
+#define HEXCHAR(s) ((XDIGIT (s[1]) << 4) + XDIGIT (s[2]))
+
+static gboolean
+form_decode (char *part)
+{
+ unsigned char *s, *d;
+
+ s = d = (unsigned char *)part;
+ do {
+ if (*s == '%') {
+ if (!g_ascii_isxdigit (s[1]) ||
+ !g_ascii_isxdigit (s[2]))
+ return FALSE;
+ *d++ = HEXCHAR (s);
+ s += 2;
+ } else if (*s == '+')
+ *d++ = ' ';
+ else
+ *d++ = *s;
+ } while (*s++);
+
+ return TRUE;
+}
+
+/**
+ * soup_form_decode_urlencoded:
+ * @encoded_form: data of type "application/x-www-form-urlencoded"
+ *
+ * Decodes @form, which is an urlencoded dataset as defined in the
+ * HTML 4.01 spec.
+ *
+ * Return value: a hash table containing the name/value pairs from
+ * @encoded_form, which you can free with g_hash_table_destroy().
+ **/
+GHashTable *
+soup_form_decode_urlencoded (const char *encoded_form)
+{
+ GHashTable *form_data_set;
+ char **pairs, *eq, *name, *value;
+ int i;
+
+ form_data_set = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, NULL);
+ pairs = g_strsplit (encoded_form, "&", -1);
+ for (i = 0; pairs[i]; i++) {
+ name = pairs[i];
+ eq = strchr (name, '=');
+ if (!form_decode (name)) {
+ g_free (name);
+ continue;
+ }
+ if (eq) {
+ *eq = '\0';
+ value = eq + 1;
+ } else
+ value = NULL;
+
+ g_hash_table_insert (form_data_set, name, value);
+ }
+ g_free (pairs);
+
+ return form_data_set;
+}
+
+static void
+append_form_encoded (GString *str, const char *in)
+{
+ const unsigned char *s = (const unsigned char *)in;
+
+ while (*s) {
+ if (*s == ' ') {
+ g_string_append_c (str, '+');
+ s++;
+ } else if (!g_ascii_isalnum (*s))
+ g_string_append_printf (str, "%%%02X", (int)*s++);
+ else
+ g_string_append_c (str, *s++);
+ }
+}
+
+static void
+encode_pair (GString *str, const char *name, const char *value)
+{
+ if (str->len)
+ g_string_append_c (str, '&');
+ append_form_encoded (str, name);
+ g_string_append_c (str, '=');
+ append_form_encoded (str, value);
+}
+
+static void
+hash_encode_foreach (gpointer name, gpointer value, gpointer str)
+{
+ encode_pair (str, name, value);
+}
+
+/**
+ * soup_form_encode_urlencoded:
+ * @form_data_set: a hash table containing name/value pairs
+ *
+ * Encodes @form_data_set into a value of type
+ * "application/x-www-form-urlencoded", as defined in the HTML 4.01
+ * spec.
+ *
+ * Note that the spec states that "The control names/values are listed
+ * in the order they appear in the document." Since
+ * soup_form_encode_urlencoded() takes a hash table, this cannot be
+ * enforced; if you care about the ordering of the form fields, use
+ * soup_form_encode_urlencoded_list().
+ *
+ * Return value: the encoded form
+ **/
+char *
+soup_form_encode_urlencoded (GHashTable *form_data_set)
+{
+ GString *str = g_string_new (NULL);
+
+ g_hash_table_foreach (form_data_set, hash_encode_foreach, str);
+ return g_string_free (str, FALSE);
+}
+
+static void
+datalist_encode_foreach (GQuark key_id, gpointer value, gpointer str)
+{
+ encode_pair (str, g_quark_to_string (key_id), value);
+}
+
+/**
+ * soup_form_encode_urlencoded_list:
+ * @form_data_set: a hash table containing name/value pairs
+ *
+ * Encodes @form_data_set into a value of type
+ * "application/x-www-form-urlencoded", as defined in the HTML 4.01
+ * spec. Unlike soup_form_encode_urlencoded(), this preserves the
+ * ordering of the form elements, which may be required in some
+ * situations.
+ *
+ * Return value: the encoded form
+ **/
+char *
+soup_form_encode_urlencoded_list (GData **form_data_set)
+{
+ GString *str = g_string_new (NULL);
+
+ g_datalist_foreach (form_data_set, datalist_encode_foreach, str);
+ return g_string_free (str, FALSE);
+}