static JsonNode * json_serializable_real_serialize (JsonSerializable *serializable, const gchar *name, const GValue *value, GParamSpec *pspec) { JSON_NOTE (GOBJECT, "Default serialization for property '%s'", pspec->name); return json_serialize_pspec (value, pspec); }
static gboolean json_serializable_real_deserialize (JsonSerializable *serializable, const gchar *name, GValue *value, GParamSpec *pspec, JsonNode *node) { JSON_NOTE (GOBJECT, "Default deserialization for property '%s'", pspec->name); return json_deserialize_pspec (value, pspec, node); }
static GObject * json_gobject_new (GType gtype, JsonObject *object) { JsonSerializableIface *iface = NULL; JsonSerializable *serializable = NULL; gboolean find_property; gboolean deserialize_property; gboolean set_property; GList *members, *members_left, *l; guint n_members; GObjectClass *klass; GObject *retval; GArray *construct_params; gint i; klass = g_type_class_ref (gtype); n_members = json_object_get_size (object); members = json_object_get_members (object); members_left = NULL; /* first pass: construct-only properties; here we cannot use Serializable * because we don't have an instance yet; we use the default implementation * of json_deserialize_pspec() to deserialize known types * * FIXME - find a way to allow deserialization for these properties */ construct_params = g_array_sized_new (FALSE, FALSE, sizeof (GParameter), n_members); for (l = members; l != NULL; l = l->next) { const gchar *member_name = l->data; GParamSpec *pspec; GParameter param = { NULL, }; JsonNode *val; gboolean res = FALSE; pspec = g_object_class_find_property (klass, member_name); if (!pspec) goto next_member; /* we only apply construct-only properties here */ if ((pspec->flags & G_PARAM_CONSTRUCT_ONLY) == 0) goto next_member; if (!(pspec->flags & G_PARAM_WRITABLE)) goto next_member; g_value_init (¶m.value, G_PARAM_SPEC_VALUE_TYPE (pspec)); val = json_object_get_member (object, member_name); res = json_deserialize_pspec (¶m.value, pspec, val); if (!res) { g_warning ("Failed to deserialize \"%s\" property of type \"%s\" for an object of type \"%s\"", pspec->name, G_VALUE_TYPE_NAME (¶m.value), g_type_name (gtype)); g_value_unset (¶m.value); } else { param.name = g_strdup (pspec->name); g_array_append_val (construct_params, param); continue; } next_member: members_left = g_list_prepend (members_left, l->data); } retval = g_object_newv (gtype, construct_params->len, (GParameter *) construct_params->data); /* free the contents of the GArray */ for (i = 0; i < construct_params->len; i++) { GParameter *param = &g_array_index (construct_params, GParameter, i); g_free ((gchar *) param->name); g_value_unset (¶m->value); } g_array_free (construct_params, TRUE); g_list_free (members); /* we use g_list_prepend() above, but we want to maintain * the ordering of json_object_get_members() here */ members = g_list_reverse (members_left); /* do the Serializable type check once */ if (g_type_is_a (gtype, JSON_TYPE_SERIALIZABLE)) { serializable = JSON_SERIALIZABLE (retval); iface = JSON_SERIALIZABLE_GET_IFACE (serializable); find_property = (iface->find_property != NULL); deserialize_property = (iface->deserialize_property != NULL); set_property = (iface->set_property != NULL); } else { find_property = FALSE; deserialize_property = FALSE; set_property = FALSE; } g_object_freeze_notify (retval); for (l = members; l != NULL; l = l->next) { const gchar *member_name = l->data; GParamSpec *pspec; JsonNode *val; GValue value = { 0, }; gboolean res = FALSE; if (find_property) pspec = json_serializable_find_property (serializable, member_name); else pspec = g_object_class_find_property (klass, member_name); if (pspec == NULL) continue; /* we should have dealt with these above */ if (pspec->flags & G_PARAM_CONSTRUCT_ONLY) continue; if (!(pspec->flags & G_PARAM_WRITABLE)) continue; g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec)); val = json_object_get_member (object, member_name); if (deserialize_property) { JSON_NOTE (GOBJECT, "Using JsonSerializable for property '%s'", pspec->name); res = json_serializable_deserialize_property (serializable, pspec->name, &value, pspec, val); } if (!res) { JSON_NOTE (GOBJECT, "Using json_deserialize_pspec for property '%s'", pspec->name); res = json_deserialize_pspec (&value, pspec, val); } if (res) { JSON_NOTE (GOBJECT, "Calling set_property('%s', '%s')", pspec->name, g_type_name (G_VALUE_TYPE (&value))); if (set_property) json_serializable_set_property (serializable, pspec, &value); else g_object_set_property (retval, pspec->name, &value); } else g_warning ("Failed to deserialize \"%s\" property of type \"%s\" for an object of type \"%s\"", pspec->name, g_type_name (G_VALUE_TYPE (&value)), g_type_name (gtype)); g_value_unset (&value); } g_list_free (members); g_object_thaw_notify (retval); g_type_class_unref (klass); return retval; }
static guint json_parse_statement (JsonParser *parser, JsonScanner *scanner) { JsonParserPrivate *priv = parser->priv; guint token; token = json_scanner_peek_next_token (scanner); switch (token) { case G_TOKEN_LEFT_CURLY: JSON_NOTE (PARSER, "Statement is object declaration"); return json_parse_object (parser, scanner, &priv->root); case G_TOKEN_LEFT_BRACE: JSON_NOTE (PARSER, "Statement is array declaration"); return json_parse_array (parser, scanner, &priv->root); /* some web APIs are not only passing the data structures: they are * also passing an assigment, which makes parsing horribly complicated * only because web developers are lazy, and writing "var foo = " is * evidently too much to request from them. */ case JSON_TOKEN_VAR: { guint next_token; gchar *name; JSON_NOTE (PARSER, "Statement is an assignment"); /* swallow the 'var' token... */ token = json_scanner_get_next_token (scanner); /* ... swallow the variable name... */ next_token = json_scanner_get_next_token (scanner); if (next_token != G_TOKEN_IDENTIFIER) { priv->error_code = JSON_PARSER_ERROR_INVALID_BAREWORD; return G_TOKEN_IDENTIFIER; } name = g_strdup (scanner->value.v_identifier); /* ... and finally swallow the '=' */ next_token = json_scanner_get_next_token (scanner); if (next_token != '=') { priv->error_code = JSON_PARSER_ERROR_INVALID_BAREWORD; g_free (name); return '='; } priv->has_assignment = TRUE; priv->variable_name = name; token = json_parse_statement (parser, scanner); /* remove the trailing semi-colon */ next_token = json_scanner_peek_next_token (scanner); if (next_token == ';') { token = json_scanner_get_next_token (scanner); return G_TOKEN_NONE; } return token; } break; case JSON_TOKEN_NULL: case JSON_TOKEN_TRUE: case JSON_TOKEN_FALSE: case '-': case G_TOKEN_INT: case G_TOKEN_FLOAT: case G_TOKEN_STRING: case G_TOKEN_IDENTIFIER: JSON_NOTE (PARSER, "Statement is a value"); token = json_scanner_get_next_token (scanner); return json_parse_value (parser, scanner, token, &priv->root); default: JSON_NOTE (PARSER, "Unknown statement"); json_scanner_get_next_token (scanner); priv->error_code = JSON_PARSER_ERROR_INVALID_BAREWORD; return G_TOKEN_SYMBOL; } }
static guint json_parse_object (JsonParser *parser, JsonScanner *scanner, JsonNode **node) { JsonParserPrivate *priv = parser->priv; JsonObject *object; JsonNode *old_current; guint token; old_current = priv->current_node; priv->current_node = json_node_init_object (json_node_alloc (), NULL); object = json_object_new (); token = json_scanner_get_next_token (scanner); g_assert (token == G_TOKEN_LEFT_CURLY); g_signal_emit (parser, parser_signals[OBJECT_START], 0); while (token != G_TOKEN_RIGHT_CURLY) { guint next_token = json_scanner_peek_next_token (scanner); JsonNode *member = NULL; gchar *name; /* we need to abort here because empty objects do not * have member names */ if (next_token == G_TOKEN_RIGHT_CURLY) break; /* parse the member's name */ if (next_token != G_TOKEN_STRING) { JSON_NOTE (PARSER, "Missing object member name"); priv->error_code = JSON_PARSER_ERROR_INVALID_BAREWORD; json_object_unref (object); json_node_free (priv->current_node); priv->current_node = old_current; return G_TOKEN_STRING; } /* member name */ token = json_scanner_get_next_token (scanner); name = g_strdup (scanner->value.v_string); if (name == NULL || *name == '\0') { JSON_NOTE (PARSER, "Empty object member name"); priv->error_code = JSON_PARSER_ERROR_EMPTY_MEMBER_NAME; json_object_unref (object); json_node_free (priv->current_node); priv->current_node = old_current; return G_TOKEN_STRING; } JSON_NOTE (PARSER, "Object member '%s'", name); /* a colon separates names from values */ next_token = json_scanner_peek_next_token (scanner); if (next_token != ':') { JSON_NOTE (PARSER, "Missing object member name separator"); priv->error_code = JSON_PARSER_ERROR_MISSING_COLON; g_free (name); json_object_unref (object); json_node_free (priv->current_node); priv->current_node = old_current; return ':'; } /* we swallow the ':' */ token = json_scanner_get_next_token (scanner); g_assert (token == ':'); next_token = json_scanner_peek_next_token (scanner); /* parse the member's value */ switch (next_token) { case G_TOKEN_LEFT_BRACE: JSON_NOTE (PARSER, "Nested array at member %s", name); token = json_parse_array (parser, scanner, &member); break; case G_TOKEN_LEFT_CURLY: JSON_NOTE (PARSER, "Nested object at member %s", name); token = json_parse_object (parser, scanner, &member); break; default: /* once a member name is defined we need a value */ token = json_scanner_get_next_token (scanner); token = json_parse_value (parser, scanner, token, &member); break; } if (token != G_TOKEN_NONE || member == NULL) { /* the json_parse_* functions will have set the error code */ g_free (name); json_object_unref (object); json_node_free (priv->current_node); priv->current_node = old_current; return token; } next_token = json_scanner_peek_next_token (scanner); if (next_token == G_TOKEN_COMMA) { token = json_scanner_get_next_token (scanner); next_token = json_scanner_peek_next_token (scanner); /* look for trailing commas */ if (next_token == G_TOKEN_RIGHT_CURLY) { priv->error_code = JSON_PARSER_ERROR_TRAILING_COMMA; json_object_unref (object); json_node_free (member); json_node_free (priv->current_node); priv->current_node = old_current; return G_TOKEN_RIGHT_BRACE; } } else if (next_token == G_TOKEN_STRING) { priv->error_code = JSON_PARSER_ERROR_MISSING_COMMA; json_object_unref (object); json_node_free (member); json_node_free (priv->current_node); priv->current_node = old_current; return G_TOKEN_COMMA; } JSON_NOTE (PARSER, "Object member '%s' completed", name); json_node_set_parent (member, priv->current_node); json_object_set_member (object, name, member); g_signal_emit (parser, parser_signals[OBJECT_MEMBER], 0, object, name); g_free (name); token = next_token; } json_scanner_get_next_token (scanner); json_node_take_object (priv->current_node, object); json_node_set_parent (priv->current_node, old_current); g_signal_emit (parser, parser_signals[OBJECT_END], 0, object); if (node != NULL && *node == NULL) *node = priv->current_node; priv->current_node = old_current; return G_TOKEN_NONE; }
static guint json_parse_array (JsonParser *parser, JsonScanner *scanner, JsonNode **node) { JsonParserPrivate *priv = parser->priv; JsonNode *old_current; JsonArray *array; guint token; gint idx; old_current = priv->current_node; priv->current_node = json_node_init_array (json_node_alloc (), NULL); array = json_array_new (); token = json_scanner_get_next_token (scanner); g_assert (token == G_TOKEN_LEFT_BRACE); g_signal_emit (parser, parser_signals[ARRAY_START], 0); idx = 0; while (token != G_TOKEN_RIGHT_BRACE) { guint next_token = json_scanner_peek_next_token (scanner); JsonNode *element = NULL; /* parse the element */ switch (next_token) { case G_TOKEN_LEFT_BRACE: JSON_NOTE (PARSER, "Nested array at index %d", idx); token = json_parse_array (parser, scanner, &element); break; case G_TOKEN_LEFT_CURLY: JSON_NOTE (PARSER, "Nested object at index %d", idx); token = json_parse_object (parser, scanner, &element); break; case G_TOKEN_RIGHT_BRACE: goto array_done; default: token = json_scanner_get_next_token (scanner); token = json_parse_value (parser, scanner, token, &element); break; } if (token != G_TOKEN_NONE || element == NULL) { /* the json_parse_* functions will have set the error code */ json_array_unref (array); json_node_free (priv->current_node); priv->current_node = old_current; return token; } next_token = json_scanner_peek_next_token (scanner); if (next_token == G_TOKEN_COMMA) { token = json_scanner_get_next_token (scanner); next_token = json_scanner_peek_next_token (scanner); /* look for trailing commas */ if (next_token == G_TOKEN_RIGHT_BRACE) { priv->error_code = JSON_PARSER_ERROR_TRAILING_COMMA; json_array_unref (array); json_node_free (priv->current_node); json_node_free (element); priv->current_node = old_current; return G_TOKEN_RIGHT_BRACE; } } JSON_NOTE (PARSER, "Array element %d completed", idx + 1); json_node_set_parent (element, priv->current_node); json_array_add_element (array, element); g_signal_emit (parser, parser_signals[ARRAY_ELEMENT], 0, array, idx); token = next_token; } array_done: json_scanner_get_next_token (scanner); json_node_take_array (priv->current_node, array); json_node_set_parent (priv->current_node, old_current); g_signal_emit (parser, parser_signals[ARRAY_END], 0, array); if (node != NULL && *node == NULL) *node = priv->current_node; priv->current_node = old_current; return G_TOKEN_NONE; }
static guint json_parse_value (JsonParser *parser, JsonScanner *scanner, guint token, JsonNode **node) { JsonParserPrivate *priv = parser->priv; JsonNode *current_node = priv->current_node; gboolean is_negative = FALSE; if (token == '-') { guint next_token = json_scanner_peek_next_token (scanner); if (next_token == G_TOKEN_INT || next_token == G_TOKEN_FLOAT) { is_negative = TRUE; token = json_scanner_get_next_token (scanner); } else return G_TOKEN_INT; } switch (token) { case G_TOKEN_INT: JSON_NOTE (PARSER, "abs(node): %" G_GINT64_FORMAT " (sign: %s)", scanner->value.v_int64, is_negative ? "negative" : "positive"); *node = json_node_init_int (json_node_alloc (), is_negative ? scanner->value.v_int64 * -1 : scanner->value.v_int64); break; case G_TOKEN_FLOAT: JSON_NOTE (PARSER, "abs(node): %.6f (sign: %s)", scanner->value.v_float, is_negative ? "negative" : "positive"); *node = json_node_init_double (json_node_alloc (), is_negative ? scanner->value.v_float * -1.0 : scanner->value.v_float); break; case G_TOKEN_STRING: JSON_NOTE (PARSER, "node: '%s'", scanner->value.v_string); *node = json_node_init_string (json_node_alloc (), scanner->value.v_string); break; case JSON_TOKEN_TRUE: case JSON_TOKEN_FALSE: JSON_NOTE (PARSER, "node: '%s'", JSON_TOKEN_TRUE ? "<true>" : "<false>"); *node = json_node_init_boolean (json_node_alloc (), token == JSON_TOKEN_TRUE ? TRUE : FALSE); break; case JSON_TOKEN_NULL: JSON_NOTE (PARSER, "node: <null>"); *node = json_node_init_null (json_node_alloc ()); break; case G_TOKEN_IDENTIFIER: JSON_NOTE (PARSER, "node: identifier '%s'", scanner->value.v_identifier); priv->error_code = JSON_PARSER_ERROR_INVALID_BAREWORD; *node = NULL; return G_TOKEN_SYMBOL; default: { JsonNodeType cur_type; *node = NULL; JSON_NOTE (PARSER, "node: invalid token"); cur_type = json_node_get_node_type (current_node); if (cur_type == JSON_NODE_ARRAY) { priv->error_code = JSON_PARSER_ERROR_PARSE; return G_TOKEN_RIGHT_BRACE; } else if (cur_type == JSON_NODE_OBJECT) { priv->error_code = JSON_PARSER_ERROR_PARSE; return G_TOKEN_RIGHT_CURLY; } else { priv->error_code = JSON_PARSER_ERROR_INVALID_BAREWORD; return G_TOKEN_SYMBOL; } } break; } return G_TOKEN_NONE; }