void pop_dom_node(struct dom_stack *stack) { struct dom_stack_state *state; int i; assert(stack); if (dom_stack_is_empty(stack)) return; state = get_dom_stack_top(stack); if (state->immutable) return; if (call_dom_stack_callbacks(stack, state, DOM_STACK_POP) || (stack->flags & DOM_STACK_FLAG_FREE_NODES)) done_dom_node(state->node); stack->depth--; assert(stack->depth >= 0); for (i = 0; i < stack->contexts_size; i++) { struct dom_stack_context *context = stack->contexts[i]; if (context->info->object_size) { void *state_data = get_dom_stack_state_data(context, state); memset(state_data, 0, context->info->object_size); } } memset(state, 0, sizeof(*state)); }
/* Create a new parsing state by pushing a new text node containing the*/ static struct sgml_parsing_state * init_sgml_parsing_state(struct sgml_parser *parser, struct dom_string *buffer) { struct dom_stack_state *state; struct dom_node *node; node = init_dom_node(DOM_NODE_TEXT, buffer); if (!node || !push_dom_node(&parser->parsing, node)) return NULL; state = get_dom_stack_top(&parser->parsing); return get_dom_stack_state_data(parser->parsing.contexts[0], state); }
/* Returns whether the node should be freed with done_dom_node(). */ static int call_dom_stack_callbacks(struct dom_stack *stack, struct dom_stack_state *state, enum dom_stack_action action) { int free_node = 0; int i; for (i = 0; i < stack->contexts_size; i++) { struct dom_stack_context *context = stack->contexts[i]; dom_stack_callback_T callback; assert(state->node->type < DOM_NODES); /* unsigned comparison */ if_assert_failed { /* The node type is out of range for the * callback arrays. The node may have been * corrupted or already freed. Ignore * free_node here because attempting to free * the node would probably just corrupt things * further. */ return 0; } if (action == DOM_STACK_PUSH) callback = context->info->push[state->node->type]; else callback = context->info->pop[state->node->type]; if (callback) { void *data = get_dom_stack_state_data(context, state); stack->current = context; switch (callback(stack, state->node, data)) { case DOM_CODE_FREE_NODE: free_node = 1; break; default: break; } stack->current = NULL; } } return free_node; }
/* FIXME: Instead of walking all nodes in the tree only visit those which are * of actual interest to the contexts on the stack. */ void walk_dom_nodes(struct dom_stack *stack, struct dom_node *root) { struct dom_stack_context *context; assert(root && stack); context = add_dom_stack_context(stack, NULL, &dom_stack_walk_context_info); if (!context) return; if (push_dom_node(stack, root) != DOM_CODE_OK) return; while (!dom_stack_is_empty(stack)) { struct dom_stack_state *state = get_dom_stack_top(stack); struct dom_stack_walk_state *wstate = get_dom_stack_state_data(context, state); struct dom_node_list *list = wstate->list; struct dom_node *node = state->node; switch (node->type) { case DOM_NODE_DOCUMENT: if (!list) list = node->data.document.children; break; case DOM_NODE_ELEMENT: if (!list) list = node->data.element.map; if (list == node->data.element.children) break; if (is_dom_node_list_member(list, wstate->index) && list == node->data.element.map) break; list = node->data.element.children; break; case DOM_NODE_PROCESSING_INSTRUCTION: if (!list) list = node->data.proc_instruction.map; break; case DOM_NODE_DOCUMENT_TYPE: if (!list) list = node->data.document_type.entities; if (list == node->data.document_type.notations) break; if (is_dom_node_list_member(list, wstate->index) && list == node->data.document_type.entities) break; list = node->data.document_type.notations; break; case DOM_NODE_ATTRIBUTE: case DOM_NODE_TEXT: case DOM_NODE_CDATA_SECTION: case DOM_NODE_COMMENT: case DOM_NODE_NOTATION: case DOM_NODE_DOCUMENT_FRAGMENT: case DOM_NODE_ENTITY_REFERENCE: case DOM_NODE_ENTITY: default: break; } /* Reset list state if it is a new list */ if (list != wstate->list) { wstate->list = list; wstate->index = 0; } /* If we have next child node */ if (is_dom_node_list_member(list, wstate->index)) { struct dom_node *child = list->entries[wstate->index++]; if (push_dom_node(stack, child) == DOM_CODE_OK) continue; } pop_dom_node(stack); } done_dom_stack_context(stack, context); }