diff options
author | Emmanuele Bassi <ebassi@openedhand.com> | 2007-11-20 18:20:33 +0000 |
---|---|---|
committer | Emmanuele Bassi <ebassi@openedhand.com> | 2007-11-20 18:20:33 +0000 |
commit | 1110e098fa879abf7f67f24af2a1b736ce359dd6 (patch) | |
tree | 84a09740b042d01479727e60dc06bcb0354d772d /json-glib/json-gobject.c | |
parent | 2674ce68e574cebeca147944cf748b41fbe27507 (diff) | |
download | json-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.c | 170 |
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; |