/** * json_gobject_to_data: * @gobject: a #GObject * @length: (out): return value for the length of the buffer, or %NULL * * Serializes a #GObject into a JSON data stream, iterating recursively * over each property. * * If @gobject implements the #JsonSerializableIface interface, it will * be asked to serialize all its properties; otherwise, the default * implementation will be use to translate the compatible types into * JSON native types. * * Return value: a JSON data stream representing the passed #GObject * * Since: 0.10 */ gchar * json_gobject_to_data (GObject *gobject, gsize *length) { JsonGenerator *gen; JsonNode *root; gchar *data; g_return_val_if_fail (G_OBJECT (gobject), NULL); root = json_gobject_serialize (gobject); gen = g_object_new (JSON_TYPE_GENERATOR, "root", root, "pretty", TRUE, "indent", 2, NULL); data = json_generator_to_data (gen, length); g_object_unref (gen); json_node_unref (root); return data; }
static inline void json_parser_clear (JsonParser *parser) { JsonParserPrivate *priv = parser->priv; g_free (priv->variable_name); priv->variable_name = NULL; if (priv->last_error) { g_error_free (priv->last_error); priv->last_error = NULL; } if (priv->root) { json_node_unref (priv->root); priv->root = NULL; } }
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_unref (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) { JSON_NOTE (PARSER, "Empty object member name"); priv->error_code = JSON_PARSER_ERROR_EMPTY_MEMBER_NAME; json_object_unref (object); json_node_unref (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_unref (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_unref (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_unref (member); json_node_unref (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_unref (member); json_node_unref (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); if (priv->is_immutable) json_node_seal (member); 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); if (priv->is_immutable) json_object_seal (object); json_node_take_object (priv->current_node, object); if (priv->is_immutable) json_node_seal (priv->current_node); 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_unref (priv->current_node); priv->current_node = old_current; return token; } next_token = json_scanner_peek_next_token (scanner); /* look for missing commas */ if (next_token != G_TOKEN_COMMA && next_token != G_TOKEN_RIGHT_BRACE) { priv->error_code = JSON_PARSER_ERROR_MISSING_COMMA; json_array_unref (array); json_node_free (priv->current_node); json_node_free (element); priv->current_node = old_current; return G_TOKEN_COMMA; } /* look for trailing commas */ if (next_token == G_TOKEN_COMMA) { token = json_scanner_get_next_token (scanner); next_token = json_scanner_peek_next_token (scanner); if (next_token == G_TOKEN_RIGHT_BRACE) { priv->error_code = JSON_PARSER_ERROR_TRAILING_COMMA; json_array_unref (array); json_node_unref (priv->current_node); json_node_unref (element); priv->current_node = old_current; return G_TOKEN_RIGHT_BRACE; } } JSON_NOTE (PARSER, "Array element %d completed", idx); json_node_set_parent (element, priv->current_node); if (priv->is_immutable) json_node_seal (element); json_array_add_element (array, element); g_signal_emit (parser, parser_signals[ARRAY_ELEMENT], 0, array, idx); idx += 1; token = next_token; } array_done: json_scanner_get_next_token (scanner); if (priv->is_immutable) json_array_seal (array); json_node_take_array (priv->current_node, array); if (priv->is_immutable) json_node_seal (priv->current_node); 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; }