summaryrefslogtreecommitdiff
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
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.
-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;