/** * json_node_seal: * @node: a #JsonNode * * Seals the #JsonNode, making it immutable to further changes. In order to be * sealed, the @node must have a type and value set. The value will be * recursively sealed — if the node holds an object, that #JsonObject will be * sealed, etc. * * If the @node is already immutable, this is a no-op. * * Since: 1.2 */ void json_node_seal (JsonNode *node) { g_return_if_fail (JSON_NODE_IS_VALID (node)); if (node->immutable) return; switch (node->type) { case JSON_NODE_OBJECT: g_return_if_fail (node->data.object != NULL); json_object_seal (node->data.object); break; case JSON_NODE_ARRAY: g_return_if_fail (node->data.array != NULL); json_array_seal (node->data.array); break; case JSON_NODE_NULL: break; case JSON_NODE_VALUE: g_return_if_fail (node->data.value != NULL); json_value_seal (node->data.value); break; default: g_assert_not_reached (); } node->immutable = TRUE; }
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; }