diff --git a/src/document/dom/node.c b/src/document/dom/node.c index 7ee0b065..ece10b6b 100644 --- a/src/document/dom/node.c +++ b/src/document/dom/node.c @@ -18,6 +18,8 @@ #include "util/string.h" +static void done_dom_node_data(struct dom_node *node); + /* Node lists */ #define DOM_NODE_LIST_GRANULARITY 0x7 @@ -84,6 +86,27 @@ add_to_dom_node_list(struct dom_node_list **list_ptr, return list; } +static void +del_from_dom_node_list(struct dom_node_list *list, struct dom_node *node) +{ + struct dom_node *entry; + size_t i; + + if (!list) return; + + foreach_dom_node(i, entry, list) { + size_t successors; + + if (entry != node) continue; + + successors = list->size - (i + 1); + if (successors) + memmove(&list->entries[i], &list->entries[i+1], + sizeof(*list->entries) * successors); + list->size--; + } +} + void done_dom_node_list(struct dom_node_list *list) { @@ -93,7 +116,8 @@ done_dom_node_list(struct dom_node_list *list) assert(list); foreach_dom_node (i, node, list) { - done_dom_node(node); + /* Avoid that the node start messing with the node list. */ + done_dom_node_data(node); } mem_free(list); @@ -213,6 +237,7 @@ init_dom_node_(unsigned char *file, int line, node->type = type; node->string = string; node->length = length; + node->parent = parent; if (parent) { struct dom_node_list **list = get_dom_node_list(parent, node); @@ -236,7 +261,7 @@ init_dom_node_(unsigned char *file, int line, } void -done_dom_node(struct dom_node *node) +done_dom_node_data(struct dom_node *node) { union dom_node_data *data; @@ -245,49 +270,79 @@ done_dom_node(struct dom_node *node) data = &node->data; switch (node->type) { - case DOM_NODE_ATTRIBUTE: - if (data->attribute.allocated) - mem_free(node->string); - break; + case DOM_NODE_ATTRIBUTE: + if (data->attribute.allocated) + mem_free(node->string); + break; - case DOM_NODE_DOCUMENT: - if (data->document.element_ids) - free_hash(data->document.element_ids); + case DOM_NODE_DOCUMENT: + if (data->document.element_ids) + free_hash(data->document.element_ids); - if (data->document.meta_nodes) - done_dom_node_list(data->document.meta_nodes); + if (data->document.meta_nodes) + done_dom_node_list(data->document.meta_nodes); - if (data->document.children) - done_dom_node_list(data->document.children); + if (data->document.children) + done_dom_node_list(data->document.children); + break; - break; + case DOM_NODE_ELEMENT: + if (data->element.children) + done_dom_node_list(data->element.children); - case DOM_NODE_ELEMENT: - if (data->element.children) - done_dom_node_list(data->element.children); + if (data->element.map) + done_dom_node_list(data->element.map); + break; - if (data->element.map) - done_dom_node_list(data->element.map); + case DOM_NODE_TEXT: + if (data->text.allocated) + mem_free(node->string); + break; - break; + case DOM_NODE_PROCESSING_INSTRUCTION: + if (data->proc_instruction.map) + done_dom_node_list(data->proc_instruction.map); + break; - case DOM_NODE_TEXT: - if (data->text.allocated) - mem_free(node->string); - break; - - case DOM_NODE_PROCESSING_INSTRUCTION: - if (data->proc_instruction.map) - done_dom_node_list(data->proc_instruction.map); - - break; - default: - break; + default: + break; } mem_free(node); } +void +done_dom_node(struct dom_node *node) +{ + assert(node); + + if (node->parent) { + struct dom_node *parent = node->parent; + union dom_node_data *data = &parent->data; + + switch (parent->type) { + case DOM_NODE_DOCUMENT: + del_from_dom_node_list(data->document.meta_nodes, node); + del_from_dom_node_list(data->document.children, node); + break; + + case DOM_NODE_ELEMENT: + del_from_dom_node_list(data->element.children, node); + del_from_dom_node_list(data->element.map, node); + break; + + case DOM_NODE_PROCESSING_INSTRUCTION: + del_from_dom_node_list(data->proc_instruction.map, node); + break; + + default: + break; + } + } + + done_dom_node_data(node); +} + #define set_node_name(name, namelen, str) \ do { (name) = (str); (namelen) = sizeof(str) - 1; } while (0) diff --git a/src/document/dom/node.h b/src/document/dom/node.h index 971154be..a9368cd0 100644 --- a/src/document/dom/node.h +++ b/src/document/dom/node.h @@ -190,6 +190,8 @@ struct dom_node { uint16_t length; unsigned char *string; + struct dom_node *parent; + /* Various info depending on the type of the node. */ union dom_node_data { struct dom_document_node document; @@ -218,13 +220,13 @@ struct dom_node_list { struct dom_node *entries[1]; }; -#define foreach_dom_node(iterator, node, list) \ - for (i = 0; i < (list)->size; i++) \ - if (((node) = (list)->entries[i])) +#define foreach_dom_node(i, node, list) \ + for ((i) = 0; (i) < (list)->size; (i)++) \ + if (((node) = (list)->entries[(i)])) -#define foreachback_dom_node(iterator, node, list) \ - for (i = (list)->size - 1; i > 0; i--) \ - if (((node) = (list)->entries[i])) +#define foreachback_dom_node(i, node, list) \ + for ((i) = (list)->size - 1; (i) > 0; (i)--) \ + if (((node) = (list)->entries[(i)])) #define is_dom_node_list_member(list, member) \ ((list) && 0 <= (member) && (member) < (list)->size) diff --git a/src/document/dom/stack.c b/src/document/dom/stack.c index d1dc11a6..e760a88f 100644 --- a/src/document/dom/stack.c +++ b/src/document/dom/stack.c @@ -48,7 +48,7 @@ void init_dom_stack(struct dom_stack *stack, void *parser, void *renderer, dom_stack_callback_T push_callbacks[DOM_NODES], dom_stack_callback_T pop_callbacks[DOM_NODES], - size_t object_size) + size_t object_size, int keep_nodes) { assert(stack); @@ -57,6 +57,7 @@ init_dom_stack(struct dom_stack *stack, void *parser, void *renderer, stack->parser = parser; stack->renderer = renderer; stack->object_size = object_size; + stack->keep_nodes = !!keep_nodes; if (push_callbacks) memcpy(stack->push_callbacks, push_callbacks, DOM_STACK_CALLBACKS_SIZE); @@ -148,6 +149,9 @@ do_pop_dom_node(struct dom_stack *stack, struct dom_stack_state *parent) callback(stack, state->node, state_data); } + if (!stack->keep_nodes) + done_dom_node(state->node); + stack->depth--; assert(stack->depth >= 0); diff --git a/src/document/dom/stack.h b/src/document/dom/stack.h index b3d603ad..15c55e1f 100644 --- a/src/document/dom/stack.h +++ b/src/document/dom/stack.h @@ -37,6 +37,9 @@ struct dom_stack { struct dom_stack_state *states; size_t depth; + /* Keep nodes when popping them or call done_dom_node() on them. */ + unsigned int keep_nodes:1; + /* This is one big array of parser specific objects. */ /* The objects hold parser specific data. For the SGML parser this * holds DTD-oriented info about the node (recorded in struct @@ -110,7 +113,7 @@ search_dom_stack(struct dom_stack *stack, enum dom_node_type type, void init_dom_stack(struct dom_stack *stack, void *parser, void *renderer, dom_stack_callback_T push_callbacks[DOM_NODES], dom_stack_callback_T pop_callbacks[DOM_NODES], - size_t object_size); + size_t object_size, int keep_nodes); void done_dom_stack(struct dom_stack *stack); /* Decends down to the given node making it the current parent */ diff --git a/src/document/sgml/parser.c b/src/document/sgml/parser.c index c65b3675..f28ccfa7 100644 --- a/src/document/sgml/parser.c +++ b/src/document/sgml/parser.c @@ -318,7 +318,8 @@ init_sgml_parser(enum sgml_parser_type type, void *renderer, struct uri *uri, parser->info = &sgml_html_info; init_dom_stack(&parser->stack, parser, renderer, - push_callbacks, pop_callbacks, obj_size); + push_callbacks, pop_callbacks, obj_size, + type != SGML_PARSER_STREAM); parser->root = add_sgml_document(&parser->stack, parser->uri); if (!parser->root) {