summaryrefslogtreecommitdiff
path: root/json-glib/json-gobject.c
diff options
context:
space:
mode:
authorEmmanuele Bassi <ebassi@openedhand.com>2007-11-20 18:20:33 +0000
committerEmmanuele Bassi <ebassi@openedhand.com>2007-11-20 18:20:33 +0000
commit1110e098fa879abf7f67f24af2a1b736ce359dd6 (patch)
tree84a09740b042d01479727e60dc06bcb0354d772d /json-glib/json-gobject.c
parent2674ce68e574cebeca147944cf748b41fbe27507 (diff)
downloadjson-glib-1110e098fa879abf7f67f24af2a1b736ce359dd6.tar.gz
Allow deserialization of strings into enums/flags
If the target value is a G_TYPE_ENUM or a G_TYPE_FLAGS we can effectively deserialize a string into the corresponding value (or bit mask) using the introspection API for the GEnum and GFlags types. This code is taken from ClutterScript and it was adapted from GtkBuilder.
Diffstat (limited to 'json-glib/json-gobject.c')
-rw-r--r--json-glib/json-gobject.c170
1 files changed, 170 insertions, 0 deletions
diff --git a/json-glib/json-gobject.c b/json-glib/json-gobject.c
index f10434d..fdb17e4 100644
--- a/json-glib/json-gobject.c
+++ b/json-glib/json-gobject.c
@@ -130,6 +130,134 @@ json_serializable_deserialize_property (JsonSerializable *serializable,
}
static gboolean
+enum_from_string (GType type,
+ const gchar *string,
+ gint *enum_value)
+{
+ GEnumClass *eclass;
+ GEnumValue *ev;
+ gchar *endptr;
+ gint value;
+ gboolean retval = TRUE;
+
+ g_return_val_if_fail (G_TYPE_IS_ENUM (type), 0);
+ g_return_val_if_fail (string != NULL, 0);
+
+ value = strtoul (string, &endptr, 0);
+ if (endptr != string) /* parsed a number */
+ *enum_value = value;
+ else
+ {
+ eclass = g_type_class_ref (type);
+ ev = g_enum_get_value_by_name (eclass, string);
+ if (!ev)
+ ev = g_enum_get_value_by_nick (eclass, string);
+
+ if (ev)
+ *enum_value = ev->value;
+ else
+ retval = FALSE;
+
+ g_type_class_unref (eclass);
+ }
+
+ return retval;
+}
+
+static gboolean
+flags_from_string (GType type,
+ const gchar *string,
+ gint *flags_value)
+{
+ GFlagsClass *fclass;
+ gchar *endptr, *prevptr;
+ guint i, j, ret, value;
+ gchar *flagstr;
+ GFlagsValue *fv;
+ const gchar *flag;
+ gunichar ch;
+ gboolean eos;
+
+ g_return_val_if_fail (G_TYPE_IS_FLAGS (type), 0);
+ g_return_val_if_fail (string != 0, 0);
+
+ ret = TRUE;
+
+ value = strtoul (string, &endptr, 0);
+ if (endptr != string) /* parsed a number */
+ *flags_value = value;
+ else
+ {
+ fclass = g_type_class_ref (type);
+
+ flagstr = g_strdup (string);
+ for (value = i = j = 0; ; i++)
+ {
+ eos = flagstr[i] == '\0';
+
+ if (!eos && flagstr[i] != '|')
+ continue;
+
+ flag = &flagstr[j];
+ endptr = &flagstr[i];
+
+ if (!eos)
+ {
+ flagstr[i++] = '\0';
+ j = i;
+ }
+
+ /* trim spaces */
+ for (;;)
+ {
+ ch = g_utf8_get_char (flag);
+ if (!g_unichar_isspace (ch))
+ break;
+ flag = g_utf8_next_char (flag);
+ }
+
+ while (endptr > flag)
+ {
+ prevptr = g_utf8_prev_char (endptr);
+ ch = g_utf8_get_char (prevptr);
+ if (!g_unichar_isspace (ch))
+ break;
+ endptr = prevptr;
+ }
+
+ if (endptr > flag)
+ {
+ *endptr = '\0';
+ fv = g_flags_get_value_by_name (fclass, flag);
+
+ if (!fv)
+ fv = g_flags_get_value_by_nick (fclass, flag);
+
+ if (fv)
+ value |= fv->value;
+ else
+ {
+ ret = FALSE;
+ break;
+ }
+ }
+
+ if (eos)
+ {
+ *flags_value = value;
+ break;
+ }
+ }
+
+ g_free (flagstr);
+
+ g_type_class_unref (fclass);
+ }
+
+ return ret;
+}
+
+static gboolean
json_deserialize_pspec (GValue *value,
GParamSpec *pspec,
JsonNode *node)
@@ -201,6 +329,48 @@ json_deserialize_pspec (GValue *value,
retval = TRUE;
break;
+ case G_TYPE_ENUM:
+ {
+ gint enum_value;
+
+ if (G_VALUE_HOLDS (&node_value, G_TYPE_INT))
+ {
+ enum_value = g_value_get_int (&node_value);
+ retval = TRUE;
+ }
+ else if (G_VALUE_HOLDS (&node_value, G_TYPE_STRING))
+ {
+ retval = enum_from_string (G_VALUE_TYPE (value),
+ g_value_get_string (&node_value),
+ &enum_value);
+ }
+
+ if (retval)
+ g_value_set_enum (value, enum_value);
+ }
+ break;
+
+ case G_TYPE_FLAGS:
+ {
+ gint flags_value;
+
+ if (G_VALUE_HOLDS (&node_value, G_TYPE_INT))
+ {
+ flags_value = g_value_get_int (&node_value);
+ retval = TRUE;
+ }
+ else if (G_VALUE_HOLDS (&node_value, G_TYPE_STRING))
+ {
+ retval = flags_from_string (G_VALUE_TYPE (value),
+ g_value_get_string (&node_value),
+ &flags_value);
+ }
+
+ if (retval)
+ g_value_set_flags (value, flags_value);
+ }
+ break;
+
default:
retval = FALSE;
break;