From b50dc50a2b25c7cc77843b25adc41575cfce7fd6 Mon Sep 17 00:00:00 2001 From: John Mark Bell Date: Wed, 15 Apr 2009 11:02:53 +0000 Subject: Manually merge r7070 into trunk svn path=/trunk/hubbub/; revision=7082 --- include/hubbub/tree.h | 99 +-- src/treebuilder/after_after_body.c | 17 +- src/treebuilder/after_after_frameset.c | 9 +- src/treebuilder/after_body.c | 11 +- src/treebuilder/after_frameset.c | 12 +- src/treebuilder/after_head.c | 32 +- src/treebuilder/before_head.c | 9 +- src/treebuilder/before_html.c | 21 +- src/treebuilder/generic_rcdata.c | 8 +- src/treebuilder/in_body.c | 1127 ++++++++++++++++++++------------ src/treebuilder/in_caption.c | 14 +- src/treebuilder/in_cell.c | 21 +- src/treebuilder/in_column_group.c | 19 +- src/treebuilder/in_foreign_content.c | 28 +- src/treebuilder/in_frameset.c | 26 +- src/treebuilder/in_head.c | 47 +- src/treebuilder/in_head_noscript.c | 8 +- src/treebuilder/in_row.c | 45 +- src/treebuilder/in_select.c | 75 ++- src/treebuilder/in_select_in_table.c | 6 +- src/treebuilder/in_table.c | 86 ++- src/treebuilder/in_table_body.c | 37 +- src/treebuilder/initial.c | 33 +- src/treebuilder/internal.h | 37 +- src/treebuilder/treebuilder.c | 398 ++++++----- test/tree-buf.c | 99 +-- test/tree.c | 105 +-- test/tree2.c | 103 +-- 28 files changed, 1559 insertions(+), 973 deletions(-) diff --git a/include/hubbub/tree.h b/include/hubbub/tree.h index e9bd75b..5da768b 100644 --- a/include/hubbub/tree.h +++ b/include/hubbub/tree.h @@ -16,11 +16,12 @@ * \param ctx Client's context * \param data String content of node * \param result Pointer to location to receive created node - * \return 0 on success, 1 on failure. + * \return HUBBUB_OK on success, appropriate error otherwise. * * Postcondition: if successful, result's reference count must be 1. */ -typedef int (*hubbub_tree_create_comment)(void *ctx, const hubbub_string *data, +typedef hubbub_error (*hubbub_tree_create_comment)(void *ctx, + const hubbub_string *data, void **result); /** @@ -29,11 +30,11 @@ typedef int (*hubbub_tree_create_comment)(void *ctx, const hubbub_string *data, * \param ctx Client's context * \param doctype Data for doctype node (name, public id, system id) * \param result Pointer to location to receive created node - * \return 0 on success, 1 on failure. + * \return HUBBUB_OK on success, appropriate error otherwise. * * Postcondition: if successful, result's reference count must be 1. */ -typedef int (*hubbub_tree_create_doctype)(void *ctx, +typedef hubbub_error (*hubbub_tree_create_doctype)(void *ctx, const hubbub_doctype *doctype, void **result); @@ -43,11 +44,12 @@ typedef int (*hubbub_tree_create_doctype)(void *ctx, * \param ctx Client's context * \param tag Data for element node (namespace, name, attributes) * \param result Pointer to location to receive created node - * \return 0 on success, 1 on failure. + * \return HUBBUB_OK on success, appropriate error otherwise. * * Postcondition: if successful, result's reference count must be 1. */ -typedef int (*hubbub_tree_create_element)(void *ctx, const hubbub_tag *tag, +typedef hubbub_error (*hubbub_tree_create_element)(void *ctx, + const hubbub_tag *tag, void **result); /** @@ -56,11 +58,12 @@ typedef int (*hubbub_tree_create_element)(void *ctx, const hubbub_tag *tag, * \param ctx Client's context * \param data String content of node * \param result Pointer to location to receive created node - * \return 0 on success, 1 on failure. + * \return HUBBUB_OK on success, appropriate error otherwise. * * Postcondition: if successful, result's reference count must be 1. */ -typedef int (*hubbub_tree_create_text)(void *ctx, const hubbub_string *data, +typedef hubbub_error (*hubbub_tree_create_text)(void *ctx, + const hubbub_string *data, void **result); /** @@ -68,24 +71,24 @@ typedef int (*hubbub_tree_create_text)(void *ctx, const hubbub_string *data, * * \param ctx Client's context * \param node Node to reference - * \param 0 on success, 1 on failure. + * \return HUBBUB_OK on success, appropriate error otherwise. * * Postcondition: node's reference count is one larger than before */ -typedef int (*hubbub_tree_ref_node)(void *ctx, void *node); +typedef hubbub_error (*hubbub_tree_ref_node)(void *ctx, void *node); /** * Decrease a node's reference count * * \param ctx Client's context * \param node Node to reference - * \param 0 on success, 1 on failure. + * \return HUBBUB_OK on success, appropriate error otherwise. * * Postcondition: If the node's reference count becomes zero, and it has no * parent, and it is not the document node, then it is destroyed. Otherwise, * the reference count is one less than before. */ -typedef int (*hubbub_tree_unref_node)(void *ctx, void *node); +typedef hubbub_error (*hubbub_tree_unref_node)(void *ctx, void *node); /** * Append a node to the end of another's child list @@ -94,13 +97,15 @@ typedef int (*hubbub_tree_unref_node)(void *ctx, void *node); * \param parent The node to append to * \param child The node to append * \param result Pointer to location to receive appended node - * \return 0 on success, 1 on failure + * \return HUBBUB_OK on success, appropriate error otherwise. * * Postcondition: if successful, result's reference count is increased by 1 * * Important: *result may not == child (e.g. if text nodes got coalesced) */ -typedef int (*hubbub_tree_append_child)(void *ctx, void *parent, void *child, +typedef hubbub_error (*hubbub_tree_append_child)(void *ctx, + void *parent, + void *child, void **result); /** @@ -111,14 +116,17 @@ typedef int (*hubbub_tree_append_child)(void *ctx, void *parent, void *child, * \param child The node to insert * \param ref_child The node to insert before * \param result Pointer to location to receive inserted node - * \return 0 on success, 1 on failure + * \return HUBBUB_OK on success, appropriate error otherwise. * * Postcondition: if successful, result's reference count is increased by 1 * * Important: *result may not == child (e.g. if text nodes got coalesced) */ -typedef int (*hubbub_tree_insert_before)(void *ctx, void *parent, void *child, - void *ref_child, void **result); +typedef hubbub_error (*hubbub_tree_insert_before)(void *ctx, + void *parent, + void *child, + void *ref_child, + void **result); /** * Remove a node from another's child list @@ -127,11 +135,13 @@ typedef int (*hubbub_tree_insert_before)(void *ctx, void *parent, void *child, * \param parent The node to remove from * \param child The node to remove * \param result Pointer to location to receive removed node - * \return 0 on success, 1 on failure + * \return HUBBUB_OK on success, appropriate error otherwise. * * Postcondition: if successful, result's reference count is increased by 1 */ -typedef int (*hubbub_tree_remove_child)(void *ctx, void *parent, void *child, +typedef hubbub_error (*hubbub_tree_remove_child)(void *ctx, + void *parent, + void *child, void **result); /** @@ -141,11 +151,13 @@ typedef int (*hubbub_tree_remove_child)(void *ctx, void *parent, void *child, * \param node The node to clone * \param deep True to clone entire subtree, false to clone only the node * \param result Pointer to location to receive clone - * \return 0 on success, 1 on failure + * \return HUBBUB_OK on success, appropriate error otherwise. * * Postcondition: if successful, result's reference count must be 1. */ -typedef int (*hubbub_tree_clone_node)(void *ctx, void *node, bool deep, +typedef hubbub_error (*hubbub_tree_clone_node)(void *ctx, + void *node, + bool deep, void **result); /** @@ -154,9 +166,10 @@ typedef int (*hubbub_tree_clone_node)(void *ctx, void *node, bool deep, * \param ctx Client's context * \param node The initial parent node * \param new_parent The new parent node - * \return 0 on success, 1 on failure + * \return HUBBUB_OK on success, appropriate error otherwise. */ -typedef int (*hubbub_tree_reparent_children)(void *ctx, void *node, +typedef hubbub_error (*hubbub_tree_reparent_children)(void *ctx, + void *node, void *new_parent); /** @@ -166,7 +179,7 @@ typedef int (*hubbub_tree_reparent_children)(void *ctx, void *node, * \param node Node to retrieve the parent of * \param element_only True if the parent must be an element, false otherwise * \param result Pointer to location to receive parent node - * \return 0 on success, 1 on failure + * \return HUBBUB_OK on success, appropriate error otherwise. * * If there is a parent node, but it is not an element node and element_only * is true, then act as if no parent existed. @@ -174,7 +187,9 @@ typedef int (*hubbub_tree_reparent_children)(void *ctx, void *node, * Postcondition: if there is a parent, then result's reference count must be * increased. */ -typedef int (*hubbub_tree_get_parent)(void *ctx, void *node, bool element_only, +typedef hubbub_error (*hubbub_tree_get_parent)(void *ctx, + void *node, + bool element_only, void **result); /** @@ -183,9 +198,11 @@ typedef int (*hubbub_tree_get_parent)(void *ctx, void *node, bool element_only, * \param ctx Client's context * \param node The node to inspect * \param result Location to receive result - * \return 0 on success, 1 on failure + * \return HUBBUB_OK on success, appropriate error otherwise. */ -typedef int (*hubbub_tree_has_children)(void *ctx, void *node, bool *result); +typedef hubbub_error (*hubbub_tree_has_children)(void *ctx, + void *node, + bool *result); /** * Associate a node with a form @@ -193,9 +210,11 @@ typedef int (*hubbub_tree_has_children)(void *ctx, void *node, bool *result); * \param ctx Client's context * \param form The form to associate with * \param node The node to associate - * \return 0 on success, 1 on failure + * \return HUBBUB_OK on success, appropriate error otherwise. */ -typedef int (*hubbub_tree_form_associate)(void *ctx, void *form, void *node); +typedef hubbub_error (*hubbub_tree_form_associate)(void *ctx, + void *form, + void *node); /** * Add attributes to a node @@ -204,29 +223,35 @@ typedef int (*hubbub_tree_form_associate)(void *ctx, void *form, void *node); * \param node The node to add to * \param attributes Array of attributes to add * \param n_attributes Number of entries in array - * \return 0 on success, 1 on failure + * \return HUBBUB_OK on success, appropriate error otherwise. */ -typedef int (*hubbub_tree_add_attributes)(void *ctx, void *node, - const hubbub_attribute *attributes, uint32_t n_attributes); +typedef hubbub_error (*hubbub_tree_add_attributes)(void *ctx, + void *node, + const hubbub_attribute *attributes, + uint32_t n_attributes); /** * Notification of the quirks mode of a document * * \param ctx Client's context * \param mode The quirks mode - * \return 0 on success, 1 on failure + * \return HUBBUB_OK on success, appropriate error otherwise. */ -typedef int (*hubbub_tree_set_quirks_mode)(void *ctx, hubbub_quirks_mode mode); +typedef hubbub_error (*hubbub_tree_set_quirks_mode)(void *ctx, + hubbub_quirks_mode mode); /** * Notification that a potential encoding change is required * * \param ctx Client's context * \param charset The new charset for the source data - * \return 0 to ignore the change and continue using the current input handler, - * 1 to stop processing immediately and return control to the client. + * \return HUBBUB_OK to continue using the current input handler, + * HUBBUB_ENCODINGCHANGE to stop processing immediately and + * return control to the client, + * appropriate error otherwise. */ -typedef int (*hubbub_tree_encoding_change)(void *ctx, const char *encname); +typedef hubbub_error (*hubbub_tree_encoding_change)(void *ctx, + const char *encname); /** * Hubbub tree handler diff --git a/src/treebuilder/after_after_body.c b/src/treebuilder/after_after_body.c index 372d12c..9644e3d 100644 --- a/src/treebuilder/after_after_body.c +++ b/src/treebuilder/after_after_body.c @@ -19,7 +19,9 @@ * * \param treebuilder The treebuilder instance * \param token The token to handle - * \return True to reprocess token, false otherwise + * \return HUBBUB_OK on completion, + * HUBBUB_REPROCESS to reprocess the token, + * appropriate error otherwise */ hubbub_error handle_after_after_body(hubbub_treebuilder *treebuilder, const hubbub_token *token) @@ -28,18 +30,17 @@ hubbub_error handle_after_after_body(hubbub_treebuilder *treebuilder, switch (token->type) { case HUBBUB_TOKEN_CHARACTER: - if (process_characters_expect_whitespace(treebuilder, - token, true)) { + err = process_characters_expect_whitespace(treebuilder, + token, true); + if (err == HUBBUB_REPROCESS) treebuilder->context.mode = IN_BODY; - err = HUBBUB_REPROCESS; - } break; case HUBBUB_TOKEN_COMMENT: - process_comment_append(treebuilder, token, + err = process_comment_append(treebuilder, token, treebuilder->context.document); break; case HUBBUB_TOKEN_DOCTYPE: - handle_in_body(treebuilder, token); + err = handle_in_body(treebuilder, token); break; case HUBBUB_TOKEN_START_TAG: { @@ -48,7 +49,7 @@ hubbub_error handle_after_after_body(hubbub_treebuilder *treebuilder, if (type == HTML) { /* Process as if "in body" */ - handle_in_body(treebuilder, token); + err = handle_in_body(treebuilder, token); } else { /** \todo parse error */ treebuilder->context.mode = IN_BODY; diff --git a/src/treebuilder/after_after_frameset.c b/src/treebuilder/after_after_frameset.c index 0b1617a..f068714 100644 --- a/src/treebuilder/after_after_frameset.c +++ b/src/treebuilder/after_after_frameset.c @@ -28,14 +28,13 @@ hubbub_error handle_after_after_frameset(hubbub_treebuilder *treebuilder, switch (token->type) { case HUBBUB_TOKEN_CHARACTER: - if (process_characters_expect_whitespace(treebuilder, - token, true)) { + err = process_characters_expect_whitespace(treebuilder, + token, true); + if (err == HUBBUB_REPROCESS) treebuilder->context.mode = IN_FRAMESET; - err = HUBBUB_REPROCESS; - } break; case HUBBUB_TOKEN_COMMENT: - process_comment_append(treebuilder, token, + err = process_comment_append(treebuilder, token, treebuilder->context.document); break; case HUBBUB_TOKEN_END_TAG: diff --git a/src/treebuilder/after_body.c b/src/treebuilder/after_body.c index beaed69..42e982b 100644 --- a/src/treebuilder/after_body.c +++ b/src/treebuilder/after_body.c @@ -30,7 +30,6 @@ hubbub_error handle_after_body(hubbub_treebuilder *treebuilder, case HUBBUB_TOKEN_CHARACTER: { /* mostly cribbed from process_characters_expect_whitespace */ - const uint8_t *data = token->data.character.ptr; size_t len = token->data.character.len; size_t c; @@ -42,12 +41,14 @@ hubbub_error handle_after_body(hubbub_treebuilder *treebuilder, break; } - /* Non-whitespace characters in token, so handle as in body */ + /* Whitespace characters in token, so handle as in body */ if (c > 0) { hubbub_token temp = *token; temp.data.character.len = c; - handle_in_body(treebuilder, &temp); + err = handle_in_body(treebuilder, &temp); + if (err != HUBBUB_OK) + return err; } /* Anything else, switch to in body */ @@ -62,7 +63,7 @@ hubbub_error handle_after_body(hubbub_treebuilder *treebuilder, } break; case HUBBUB_TOKEN_COMMENT: - process_comment_append(treebuilder, token, + err = process_comment_append(treebuilder, token, treebuilder->context.element_stack[ 0].node); break; @@ -76,7 +77,7 @@ hubbub_error handle_after_body(hubbub_treebuilder *treebuilder, if (type == HTML) { /* Process as if "in body" */ - handle_in_body(treebuilder, token); + err = handle_in_body(treebuilder, token); } else { /** \todo parse error */ treebuilder->context.mode = IN_BODY; diff --git a/src/treebuilder/after_frameset.c b/src/treebuilder/after_frameset.c index a94eb86..04888ab 100644 --- a/src/treebuilder/after_frameset.c +++ b/src/treebuilder/after_frameset.c @@ -28,13 +28,17 @@ hubbub_error handle_after_frameset(hubbub_treebuilder *treebuilder, switch (token->type) { case HUBBUB_TOKEN_CHARACTER: - if (process_characters_expect_whitespace(treebuilder, - token, true)) { + err = process_characters_expect_whitespace(treebuilder, + token, true); + if (err == HUBBUB_REPROCESS) { /** \todo parse error */ + + /* Ignore the token */ + err = HUBBUB_OK; } break; case HUBBUB_TOKEN_COMMENT: - process_comment_append(treebuilder, token, + err = process_comment_append(treebuilder, token, treebuilder->context.element_stack[ treebuilder->context.current_node].node); break; @@ -47,7 +51,7 @@ hubbub_error handle_after_frameset(hubbub_treebuilder *treebuilder, &token->data.tag.name); if (type == HTML) { - handle_in_body(treebuilder, token); + err = handle_in_body(treebuilder, token); } else if (type == NOFRAMES) { err = handle_in_head(treebuilder, token); } else { diff --git a/src/treebuilder/after_head.c b/src/treebuilder/after_head.c index 9af0796..6305f4c 100644 --- a/src/treebuilder/after_head.c +++ b/src/treebuilder/after_head.c @@ -33,7 +33,7 @@ hubbub_error handle_after_head(hubbub_treebuilder *treebuilder, token, true); break; case HUBBUB_TOKEN_COMMENT: - process_comment_append(treebuilder, token, + err = process_comment_append(treebuilder, token, treebuilder->context.element_stack[ treebuilder->context.current_node].node); break; @@ -47,12 +47,14 @@ hubbub_error handle_after_head(hubbub_treebuilder *treebuilder, if (type == HTML) { /* Process as if "in body" */ - handle_in_body(treebuilder, token); + err = handle_in_body(treebuilder, token); } else if (type == BODY) { handled = true; } else if (type == FRAMESET) { - insert_element(treebuilder, &token->data.tag, true); - treebuilder->context.mode = IN_FRAMESET; + err = insert_element(treebuilder, &token->data.tag, + true); + if (err == HUBBUB_OK) + treebuilder->context.mode = IN_FRAMESET; } else if (type == BASE || type == LINK || type == META || type == NOFRAMES || type == SCRIPT || type == STYLE || type == TITLE) { @@ -60,25 +62,26 @@ hubbub_error handle_after_head(hubbub_treebuilder *treebuilder, element_type otype; void *node; uint32_t index; + hubbub_error e; /** \todo parse error */ - if (!element_stack_push(treebuilder, + err = element_stack_push(treebuilder, HUBBUB_NS_HTML, HEAD, - treebuilder->context.head_element)) { - /** \todo errors */ - } + treebuilder->context.head_element); + if (err != HUBBUB_OK) + return err; index = treebuilder->context.current_node; /* Process as "in head" */ err = handle_in_head(treebuilder, token); - if (!element_stack_remove(treebuilder, index, - &ns, &otype, &node)) { - /** \todo errors */ - } + e = element_stack_remove(treebuilder, index, + &ns, &otype, &node); + /* Can't result in error -- ensure this. */ + assert(e == HUBBUB_OK); /* No need to unref node as we never increased * its reference count when pushing it on the stack */ @@ -107,6 +110,7 @@ hubbub_error handle_after_head(hubbub_treebuilder *treebuilder, } if (handled || err == HUBBUB_REPROCESS) { + hubbub_error e; hubbub_tag tag; if (err == HUBBUB_REPROCESS) { @@ -121,7 +125,9 @@ hubbub_error handle_after_head(hubbub_treebuilder *treebuilder, tag = token->data.tag; } - insert_element(treebuilder, &tag, true); + e = insert_element(treebuilder, &tag, true); + if (e != HUBBUB_OK) + return e; treebuilder->context.mode = IN_BODY; } diff --git a/src/treebuilder/before_head.c b/src/treebuilder/before_head.c index 19bf800..15e82a8 100644 --- a/src/treebuilder/before_head.c +++ b/src/treebuilder/before_head.c @@ -33,7 +33,7 @@ hubbub_error handle_before_head(hubbub_treebuilder *treebuilder, token, false); break; case HUBBUB_TOKEN_COMMENT: - process_comment_append(treebuilder, token, + err = process_comment_append(treebuilder, token, treebuilder->context.element_stack[ treebuilder->context.current_node].node); break; @@ -47,7 +47,7 @@ hubbub_error handle_before_head(hubbub_treebuilder *treebuilder, if (type == HTML) { /* Process as if "in body" */ - handle_in_body(treebuilder, token); + err = handle_in_body(treebuilder, token); } else if (type == HEAD) { handled = true; } else { @@ -74,6 +74,7 @@ hubbub_error handle_before_head(hubbub_treebuilder *treebuilder, } if (handled || err == HUBBUB_REPROCESS) { + hubbub_error e; hubbub_tag tag; if (err == HUBBUB_REPROCESS) { @@ -88,7 +89,9 @@ hubbub_error handle_before_head(hubbub_treebuilder *treebuilder, tag = token->data.tag; } - insert_element(treebuilder, &tag, true); + e = insert_element(treebuilder, &tag, true); + if (e != HUBBUB_OK) + return e; treebuilder->tree_handler->ref_node( treebuilder->tree_handler->ctx, diff --git a/src/treebuilder/before_html.c b/src/treebuilder/before_html.c index d5a0d22..1ed3717 100644 --- a/src/treebuilder/before_html.c +++ b/src/treebuilder/before_html.c @@ -32,7 +32,7 @@ hubbub_error handle_before_html(hubbub_treebuilder *treebuilder, /** \todo parse error */ break; case HUBBUB_TOKEN_COMMENT: - process_comment_append(treebuilder, token, + err = process_comment_append(treebuilder, token, treebuilder->context.document); break; case HUBBUB_TOKEN_CHARACTER: @@ -59,7 +59,7 @@ hubbub_error handle_before_html(hubbub_treebuilder *treebuilder, if (handled || err == HUBBUB_REPROCESS) { - int success; + hubbub_error e; void *html, *appended; /* We can't use insert_element() here, as it assumes @@ -78,31 +78,30 @@ hubbub_error handle_before_html(hubbub_treebuilder *treebuilder, tag.n_attributes = 0; tag.attributes = NULL; - success = treebuilder->tree_handler->create_element( + e = treebuilder->tree_handler->create_element( treebuilder->tree_handler->ctx, &tag, &html); } else { - success = treebuilder->tree_handler->create_element( + e = treebuilder->tree_handler->create_element( treebuilder->tree_handler->ctx, &token->data.tag, &html); } - if (success != 0) { - /** \todo errors */ - } + if (e != HUBBUB_OK) + return e; - success = treebuilder->tree_handler->append_child( + e = treebuilder->tree_handler->append_child( treebuilder->tree_handler->ctx, treebuilder->context.document, html, &appended); - if (success != 0) { - /** \todo errors */ - } treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, html); + if (e != HUBBUB_OK) + return e; + /* We can't use element_stack_push() here, as it * assumes that current_node is pointing at the index * before the one to insert at. For the first entry in diff --git a/src/treebuilder/generic_rcdata.c b/src/treebuilder/generic_rcdata.c index 627068a..2da8d44 100644 --- a/src/treebuilder/generic_rcdata.c +++ b/src/treebuilder/generic_rcdata.c @@ -50,7 +50,7 @@ hubbub_error handle_generic_rcdata(hubbub_treebuilder *treebuilder, if (chars.len == 0) break; - append_text(treebuilder, &chars); + err = append_text(treebuilder, &chars); } break; case HUBBUB_TOKEN_END_TAG: @@ -85,14 +85,14 @@ hubbub_error handle_generic_rcdata(hubbub_treebuilder *treebuilder, } if (done) { + hubbub_error e; hubbub_ns ns; element_type otype; void *node; /* Pop the current node from the stack */ - if (!element_stack_pop(treebuilder, &ns, &otype, &node)) { - /** \todo errors */ - } + e = element_stack_pop(treebuilder, &ns, &otype, &node); + assert(e == HUBBUB_OK); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, diff --git a/src/treebuilder/in_body.c b/src/treebuilder/in_body.c index ce3032e..58d145a 100644 --- a/src/treebuilder/in_body.c +++ b/src/treebuilder/in_body.c @@ -15,6 +15,14 @@ #undef DEBUG_IN_BODY +/* In body mode states */ +enum { + IBS_INITIAL = 0, + IBS_DONE_FORMATTING_LIST = 1, + IBS_REMOVED_NODE = 2, + IBS_CLOSED_P = 3, +}; + /** * Bookmark for formatting list. Used in adoption agency */ @@ -23,90 +31,93 @@ typedef struct bookmark { formatting_list_entry *next; /**< Next entry */ } bookmark; -static void process_character(hubbub_treebuilder *treebuilder, +static hubbub_error process_character(hubbub_treebuilder *treebuilder, const hubbub_token *token); -static bool process_start_tag(hubbub_treebuilder *treebuilder, +static hubbub_error process_start_tag(hubbub_treebuilder *treebuilder, const hubbub_token *token); -static bool process_end_tag(hubbub_treebuilder *treebuilder, +static hubbub_error process_end_tag(hubbub_treebuilder *treebuilder, const hubbub_token *token); -static void process_html_in_body(hubbub_treebuilder *treebuilder, +static hubbub_error process_html_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token); -static void process_body_in_body(hubbub_treebuilder *treebuilder, +static hubbub_error process_body_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token); -static void process_frameset_in_body(hubbub_treebuilder *treebuilder, +static hubbub_error process_frameset_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token); -static void process_container_in_body(hubbub_treebuilder *treebuilder, +static hubbub_error process_container_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token); -static void process_hN_in_body(hubbub_treebuilder *treebuilder, +static hubbub_error process_hN_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token); -static void process_form_in_body(hubbub_treebuilder *treebuilder, +static hubbub_error process_form_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token); -static void process_dd_dt_li_in_body(hubbub_treebuilder *treebuilder, +static hubbub_error process_dd_dt_li_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token, element_type type); -static void process_plaintext_in_body(hubbub_treebuilder *treebuilder, +static hubbub_error process_plaintext_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token); -static void process_a_in_body(hubbub_treebuilder *treebuilder, +static hubbub_error process_a_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token); -static void process_presentational_in_body(hubbub_treebuilder *treebuilder, +static hubbub_error process_presentational_in_body( + hubbub_treebuilder *treebuilder, const hubbub_token *token, element_type type); -static void process_nobr_in_body(hubbub_treebuilder *treebuilder, +static hubbub_error process_nobr_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token); -static void process_button_in_body(hubbub_treebuilder *treebuilder, +static hubbub_error process_button_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token); -static void process_applet_marquee_object_in_body( +static hubbub_error process_applet_marquee_object_in_body( hubbub_treebuilder *treebuilder, const hubbub_token *token, element_type type); -static void process_hr_in_body(hubbub_treebuilder *treebuilder, +static hubbub_error process_hr_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token); -static void process_image_in_body(hubbub_treebuilder *treebuilder, +static hubbub_error process_image_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token); -static void process_isindex_in_body(hubbub_treebuilder *treebuilder, +static hubbub_error process_isindex_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token); -static void process_textarea_in_body(hubbub_treebuilder *treebuilder, +static hubbub_error process_textarea_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token); -static void process_select_in_body(hubbub_treebuilder *treebuilder, +static hubbub_error process_select_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token); -static void process_opt_in_body(hubbub_treebuilder *treebuilder, +static hubbub_error process_opt_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token); -static void process_phrasing_in_body(hubbub_treebuilder *treebuilder, +static hubbub_error process_phrasing_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token); -static bool process_0body_in_body(hubbub_treebuilder *treebuilder); -static void process_0container_in_body(hubbub_treebuilder *treebuilder, +static hubbub_error process_0body_in_body(hubbub_treebuilder *treebuilder); +static hubbub_error process_0container_in_body(hubbub_treebuilder *treebuilder, element_type type); -static void process_0form_in_body(hubbub_treebuilder *treebuilder); -static void process_0p_in_body(hubbub_treebuilder *treebuilder); -static void process_0dd_dt_li_in_body(hubbub_treebuilder *treebuilder, +static hubbub_error process_0form_in_body(hubbub_treebuilder *treebuilder); +static hubbub_error process_0p_in_body(hubbub_treebuilder *treebuilder); +static hubbub_error process_0dd_dt_li_in_body(hubbub_treebuilder *treebuilder, element_type type); -static void process_0h_in_body(hubbub_treebuilder *treebuilder, +static hubbub_error process_0h_in_body(hubbub_treebuilder *treebuilder, element_type type); -static void process_0presentational_in_body(hubbub_treebuilder *treebuilder, +static hubbub_error process_0presentational_in_body( + hubbub_treebuilder *treebuilder, element_type type); -static void process_0applet_button_marquee_object_in_body( +static hubbub_error process_0applet_button_marquee_object_in_body( hubbub_treebuilder *treebuilder, element_type type); -static void process_0br_in_body(hubbub_treebuilder *treebuilder); -static void process_0generic_in_body(hubbub_treebuilder *treebuilder, +static hubbub_error process_0br_in_body(hubbub_treebuilder *treebuilder); +static hubbub_error process_0generic_in_body(hubbub_treebuilder *treebuilder, element_type type); -static bool aa_find_and_validate_formatting_element( +static hubbub_error aa_find_and_validate_formatting_element( hubbub_treebuilder *treebuilder, element_type type, formatting_list_entry **element); static formatting_list_entry *aa_find_formatting_element( hubbub_treebuilder *treebuilder, element_type type); -static bool aa_find_furthest_block(hubbub_treebuilder *treebuilder, +static hubbub_error aa_find_furthest_block(hubbub_treebuilder *treebuilder, formatting_list_entry *formatting_element, uint32_t *furthest_block); -static void aa_remove_from_parent(hubbub_treebuilder *treebuilder, void *node); -static void *aa_reparent_node(hubbub_treebuilder *treebuilder, void *node, - void *new_parent); -static void aa_find_bookmark_location_reparenting_misnested( +static hubbub_error aa_reparent_node(hubbub_treebuilder *treebuilder, + void *node, void *new_parent, void **reparented); +static hubbub_error aa_find_bookmark_location_reparenting_misnested( hubbub_treebuilder *treebuilder, uint32_t formatting_element, uint32_t *furthest_block, bookmark *bookmark, uint32_t *last_node); -static void aa_remove_element_stack_item(hubbub_treebuilder *treebuilder, +static hubbub_error aa_remove_element_stack_item( + hubbub_treebuilder *treebuilder, uint32_t index, uint32_t limit); -static void aa_clone_and_replace_entries(hubbub_treebuilder *treebuilder, +static hubbub_error aa_clone_and_replace_entries( + hubbub_treebuilder *treebuilder, formatting_list_entry *element); @@ -137,10 +148,10 @@ hubbub_error handle_in_body(hubbub_treebuilder *treebuilder, switch (token->type) { case HUBBUB_TOKEN_CHARACTER: - process_character(treebuilder, token); + err = process_character(treebuilder, token); break; case HUBBUB_TOKEN_COMMENT: - process_comment_append(treebuilder, token, + err = process_comment_append(treebuilder, token, treebuilder->context.element_stack[ treebuilder->context.current_node].node); break; @@ -186,13 +197,21 @@ hubbub_error handle_in_body(hubbub_treebuilder *treebuilder, * \param treebuilder The treebuilder instance * \param token The token to process */ -void process_character(hubbub_treebuilder *treebuilder, +hubbub_error process_character(hubbub_treebuilder *treebuilder, const hubbub_token *token) { + hubbub_error err = HUBBUB_OK; hubbub_string dummy = token->data.character; + bool lr_flag = treebuilder->context.strip_leading_lr; const uint8_t *p; - reconstruct_active_formatting_list(treebuilder); + if (treebuilder->context.mode_state == IBS_INITIAL) { + err = reconstruct_active_formatting_list(treebuilder); + if (err != HUBBUB_OK) + return err; + + treebuilder->context.mode_state = IBS_DONE_FORMATTING_LIST; + } if (treebuilder->context.strip_leading_lr) { const uint8_t *str = dummy.ptr; @@ -205,8 +224,15 @@ void process_character(hubbub_treebuilder *treebuilder, treebuilder->context.strip_leading_lr = false; } - if (dummy.len) - append_text(treebuilder, &dummy); + if (dummy.len) { + err = append_text(treebuilder, &dummy); + if (err != HUBBUB_OK) { + /* Restore LR stripping flag */ + treebuilder->context.strip_leading_lr = lr_flag; + + return err; + } + } if (treebuilder->context.frameset_ok) { for (p = dummy.ptr; p < dummy.ptr + dummy.len; p++) { @@ -217,6 +243,10 @@ void process_character(hubbub_treebuilder *treebuilder, } } } + + treebuilder->context.mode_state = IBS_INITIAL; + + return HUBBUB_OK; } /** @@ -224,9 +254,11 @@ void process_character(hubbub_treebuilder *treebuilder, * * \param treebuilder The treebuilder instance * \param token The token to process - * \return True to reprocess the token + * \return HUBBUB_OK on success, + * HUBBUB_REPROCESS to reprocess the token, + * appropriate error otherwise. */ -bool process_start_tag(hubbub_treebuilder *treebuilder, +hubbub_error process_start_tag(hubbub_treebuilder *treebuilder, const hubbub_token *token) { hubbub_error err = HUBBUB_OK; @@ -234,17 +266,16 @@ bool process_start_tag(hubbub_treebuilder *treebuilder, &token->data.tag.name); if (type == HTML) { - process_html_in_body(treebuilder, token); + err = process_html_in_body(treebuilder, token); } else if (type == BASE || type == COMMAND || type == LINK || type == META || type == NOFRAMES || type == SCRIPT || type == STYLE || type == TITLE) { /* Process as "in head" */ err = handle_in_head(treebuilder, token); } else if (type == BODY) { - process_body_in_body(treebuilder, token); + err = process_body_in_body(treebuilder, token); } else if (type == FRAMESET) { - process_frameset_in_body(treebuilder, token); - treebuilder->context.mode = IN_FRAMESET; + err = process_frameset_in_body(treebuilder, token); } else if (type == ADDRESS || type == ARTICLE || type == ASIDE || type == BLOCKQUOTE || type == CENTER || type == DATAGRID || type == DETAILS || @@ -254,73 +285,96 @@ bool process_start_tag(hubbub_treebuilder *treebuilder, type == HEADER || type == MENU || type == NAV || type == OL || type == P || type == SECTION || type == UL) { - process_container_in_body(treebuilder, token); + err = process_container_in_body(treebuilder, token); } else if (type == H1 || type == H2 || type == H3 || type == H4 || type == H5 || type == H6) { - process_hN_in_body(treebuilder, token); + err = process_hN_in_body(treebuilder, token); } else if (type == PRE || type == LISTING) { - process_container_in_body(treebuilder, token); + err = process_container_in_body(treebuilder, token); - treebuilder->context.strip_leading_lr = true; - treebuilder->context.frameset_ok = false; + if (err == HUBBUB_OK) { + treebuilder->context.strip_leading_lr = true; + treebuilder->context.frameset_ok = false; + } } else if (type == FORM) { - process_form_in_body(treebuilder, token); + err = process_form_in_body(treebuilder, token); } else if (type == DD || type == DT || type == LI) { - process_dd_dt_li_in_body(treebuilder, token, type); + err = process_dd_dt_li_in_body(treebuilder, token, type); } else if (type == PLAINTEXT) { - process_plaintext_in_body(treebuilder, token); + err = process_plaintext_in_body(treebuilder, token); } else if (type == A) { - process_a_in_body(treebuilder, token); + err = process_a_in_body(treebuilder, token); } else if (type == B || type == BIG || type == CODE || type == EM || type == FONT || type == I || type == S || type == SMALL || type == STRIKE || type == STRONG || type == TT || type == U) { - process_presentational_in_body(treebuilder, + err = process_presentational_in_body(treebuilder, token, type); } else if (type == NOBR) { - process_nobr_in_body(treebuilder, token); + err = process_nobr_in_body(treebuilder, token); } else if (type == BUTTON) { - process_button_in_body(treebuilder, token); + err = process_button_in_body(treebuilder, token); } else if (type == APPLET || type == MARQUEE || type == OBJECT) { - process_applet_marquee_object_in_body(treebuilder, + err = process_applet_marquee_object_in_body(treebuilder, token, type); } else if (type == XMP) { - reconstruct_active_formatting_list(treebuilder); - treebuilder->context.frameset_ok = false; - parse_generic_rcdata(treebuilder, token, false); - } else if (type == TABLE) { - process_container_in_body(treebuilder, token); + if (treebuilder->context.mode_state == IBS_INITIAL) { + err = reconstruct_active_formatting_list(treebuilder); + if (err != HUBBUB_OK) + return err; + + treebuilder->context.mode_state = + IBS_DONE_FORMATTING_LIST; + } treebuilder->context.frameset_ok = false; - treebuilder->context.element_stack[current_table(treebuilder)] - .tainted = false; - treebuilder->context.mode = IN_TABLE; + err = parse_generic_rcdata(treebuilder, token, false); + } else if (type == TABLE) { + err = process_container_in_body(treebuilder, token); + if (err == HUBBUB_OK) { + treebuilder->context.frameset_ok = false; + + treebuilder->context.element_stack[ + current_table(treebuilder)].tainted = false; + treebuilder->context.mode = IN_TABLE; + } } else if (type == AREA || type == BASEFONT || type == BGSOUND || type == BR || type == EMBED || type == IMG || type == INPUT || type == PARAM || type == SPACER || type == WBR) { - reconstruct_active_formatting_list(treebuilder); - insert_element(treebuilder, &token->data.tag, false); - treebuilder->context.frameset_ok = false; + if (treebuilder->context.mode_state == IBS_INITIAL) { + err = reconstruct_active_formatting_list(treebuilder); + if (err != HUBBUB_OK) + return err; + + treebuilder->context.mode_state = + IBS_DONE_FORMATTING_LIST; + } + + err = insert_element(treebuilder, &token->data.tag, false); + if (err == HUBBUB_OK) + treebuilder->context.frameset_ok = false; } else if (type == HR) { - process_hr_in_body(treebuilder, token); + err = process_hr_in_body(treebuilder, token); } else if (type == IMAGE) { - process_image_in_body(treebuilder, token); + err = process_image_in_body(treebuilder, token); } else if (type == ISINDEX) { - process_isindex_in_body(treebuilder, token); + err = process_isindex_in_body(treebuilder, token); } else if (type == TEXTAREA) { - process_textarea_in_body(treebuilder, token); + err = process_textarea_in_body(treebuilder, token); } else if (type == IFRAME || type == NOEMBED || type == NOFRAMES || (treebuilder->context.enable_scripting && type == NOSCRIPT)) { if (type == IFRAME) treebuilder->context.frameset_ok = false; - parse_generic_rcdata(treebuilder, token, false); + err = parse_generic_rcdata(treebuilder, token, false); } else if (type == SELECT) { - process_select_in_body(treebuilder, token); + err = process_select_in_body(treebuilder, token); + if (err != HUBBUB_OK) + return err; if (treebuilder->context.mode == IN_BODY) { treebuilder->context.mode = IN_SELECT; @@ -333,13 +387,21 @@ bool process_start_tag(hubbub_treebuilder *treebuilder, treebuilder->context.mode = IN_SELECT_IN_TABLE; } } else if (type == OPTGROUP || type == OPTION) { - process_opt_in_body(treebuilder, token); + err = process_opt_in_body(treebuilder, token); } else if (type == RP || type == RT) { /** \todo ruby */ } else if (type == MATH || type == SVG) { hubbub_tag tag = token->data.tag; - reconstruct_active_formatting_list(treebuilder); + if (treebuilder->context.mode_state == IBS_INITIAL) { + err = reconstruct_active_formatting_list(treebuilder); + if (err != HUBBUB_OK) + return err; + + treebuilder->context.mode_state = + IBS_DONE_FORMATTING_LIST; + } + adjust_foreign_attributes(treebuilder, &tag); if (type == SVG) { @@ -351,13 +413,15 @@ bool process_start_tag(hubbub_treebuilder *treebuilder, } if (token->data.tag.self_closing) { - insert_element(treebuilder, &tag, false); + err = insert_element(treebuilder, &tag, false); /** \todo ack sc flag */ } else { - insert_element(treebuilder, &tag, true); - treebuilder->context.second_mode = - treebuilder->context.mode; - treebuilder->context.mode = IN_FOREIGN_CONTENT; + err = insert_element(treebuilder, &tag, true); + if (err == HUBBUB_OK) { + treebuilder->context.second_mode = + treebuilder->context.mode; + treebuilder->context.mode = IN_FOREIGN_CONTENT; + } } } else if (type == CAPTION || type == COL || type == COLGROUP || type == FRAME || type == HEAD || type == TBODY || @@ -365,9 +429,12 @@ bool process_start_tag(hubbub_treebuilder *treebuilder, type == THEAD || type == TR) { /** \todo parse error */ } else { - process_phrasing_in_body(treebuilder, token); + err = process_phrasing_in_body(treebuilder, token); } + if (err == HUBBUB_OK || err == HUBBUB_REPROCESS) + treebuilder->context.mode_state = IBS_INITIAL; + return err; } @@ -378,7 +445,7 @@ bool process_start_tag(hubbub_treebuilder *treebuilder, * \param token The token to process * \return True to reprocess the token */ -bool process_end_tag(hubbub_treebuilder *treebuilder, +hubbub_error process_end_tag(hubbub_treebuilder *treebuilder, const hubbub_token *token) { hubbub_error err = HUBBUB_OK; @@ -386,18 +453,14 @@ bool process_end_tag(hubbub_treebuilder *treebuilder, &token->data.tag.name); if (type == BODY) { - if (process_0body_in_body(treebuilder) && - treebuilder->context.mode == IN_BODY) { - treebuilder->context.mode = AFTER_BODY; - } + err = process_0body_in_body(treebuilder); + /* Never reprocess */ + if (err == HUBBUB_REPROCESS) + err = HUBBUB_OK; } else if (type == HTML) { /* Act as if has been seen then, if * that wasn't ignored, reprocess this token */ - if (process_0body_in_body(treebuilder) && - treebuilder->context.mode == IN_BODY) { - treebuilder->context.mode = AFTER_BODY; - } - err = HUBBUB_REPROCESS; + err = process_0body_in_body(treebuilder); } else if (type == ADDRESS || type == ARTICLE || type == ASIDE || type == BLOCKQUOTE || type == CENTER || type == DIR || type == DATAGRID || type == DIV || type == DL || @@ -405,28 +468,28 @@ bool process_end_tag(hubbub_treebuilder *treebuilder, type == LISTING || type == MENU || type == NAV || type == OL || type == PRE || type == SECTION || type == UL) { - process_0container_in_body(treebuilder, type); + err = process_0container_in_body(treebuilder, type); } else if (type == FORM) { - process_0form_in_body(treebuilder); + err = process_0form_in_body(treebuilder); } else if (type == P) { - process_0p_in_body(treebuilder); + err = process_0p_in_body(treebuilder); } else if (type == DD || type == DT || type == LI) { - process_0dd_dt_li_in_body(treebuilder, type); + err = process_0dd_dt_li_in_body(treebuilder, type); } else if (type == H1 || type == H2 || type == H3 || type == H4 || type == H5 || type == H6) { - process_0h_in_body(treebuilder, type); + err = process_0h_in_body(treebuilder, type); } else if (type == A || type == B || type == BIG || type == CODE || type == EM || type == FONT || type == I || type == NOBR || type == S || type == SMALL || type == STRIKE || type == STRONG || type == TT || type == U) { - process_0presentational_in_body(treebuilder, type); + err = process_0presentational_in_body(treebuilder, type); } else if (type == APPLET || type == BUTTON || type == MARQUEE || type == OBJECT) { - process_0applet_button_marquee_object_in_body( + err = process_0applet_button_marquee_object_in_body( treebuilder, type); } else if (type == BR) { - process_0br_in_body(treebuilder); + err = process_0br_in_body(treebuilder); } else if (type == AREA || type == BASEFONT || type == BGSOUND || type == EMBED || type == HR || type == IFRAME || @@ -440,9 +503,12 @@ bool process_end_tag(hubbub_treebuilder *treebuilder, type == NOSCRIPT)) { /** \todo parse error */ } else { - process_0generic_in_body(treebuilder, type); + err = process_0generic_in_body(treebuilder, type); } + if (err == HUBBUB_OK || err == HUBBUB_REPROCESS) + treebuilder->context.mode_state = IBS_INITIAL; + return err; } @@ -452,12 +518,12 @@ bool process_end_tag(hubbub_treebuilder *treebuilder, * \param treebuilder The treebuilder instance * \param token The token to process */ -void process_html_in_body(hubbub_treebuilder *treebuilder, +hubbub_error process_html_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token) { /** \todo parse error */ - treebuilder->tree_handler->add_attributes( + return treebuilder->tree_handler->add_attributes( treebuilder->tree_handler->ctx, treebuilder->context.element_stack[0].node, token->data.tag.attributes, @@ -470,16 +536,16 @@ void process_html_in_body(hubbub_treebuilder *treebuilder, * \param treebuilder The treebuilder instance * \param token The token to process */ -void process_body_in_body(hubbub_treebuilder *treebuilder, +hubbub_error process_body_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token) { /** \todo parse error */ if (treebuilder->context.current_node < 1 || treebuilder->context.element_stack[1].type != BODY) - return; + return HUBBUB_OK; - treebuilder->tree_handler->add_attributes( + return treebuilder->tree_handler->add_attributes( treebuilder->tree_handler->ctx, treebuilder->context.element_stack[1].node, token->data.tag.attributes, @@ -492,50 +558,37 @@ void process_body_in_body(hubbub_treebuilder *treebuilder, * \param treebuilder The treebuilder instance * \param token The token to process */ -void process_frameset_in_body(hubbub_treebuilder *treebuilder, +hubbub_error process_frameset_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token) { - void *parent = NULL; + hubbub_error err = HUBBUB_OK; /** \todo parse error */ if (treebuilder->context.current_node < 1 || treebuilder->context.element_stack[1].type != BODY) - return; + return HUBBUB_OK; if (treebuilder->context.frameset_ok == false) - return; - - if (treebuilder->tree_handler->get_parent( - treebuilder->tree_handler->ctx, - treebuilder->context.element_stack[1].node, - false, &parent)) { - /** \todo errors */ - } + return HUBBUB_OK; - if (parent != NULL) { - void *removed; + if (treebuilder->context.mode_state == IBS_INITIAL) { + err = remove_node_from_dom(treebuilder, + treebuilder->context.element_stack[1].node); + if (err != HUBBUB_OK) + return err; - if (treebuilder->tree_handler->remove_child( - treebuilder->tree_handler->ctx, - parent, - treebuilder->context.element_stack[1].node, - &removed)) { - /** \todo errors */ - } - - treebuilder->tree_handler->unref_node( - treebuilder->tree_handler->ctx, removed); + err = element_stack_pop_until(treebuilder, BODY); + assert(err == HUBBUB_OK); - treebuilder->tree_handler->unref_node( - treebuilder->tree_handler->ctx, parent); + treebuilder->context.mode_state = IBS_REMOVED_NODE; } - if (element_stack_pop_until(treebuilder, BODY) == false) { - /** \todo errors */ - } + err = insert_element(treebuilder, &token->data.tag, true); + if (err == HUBBUB_OK) + treebuilder->context.mode = IN_FRAMESET; - insert_element(treebuilder, &token->data.tag, true); + return err; } /** @@ -544,14 +597,22 @@ void process_frameset_in_body(hubbub_treebuilder *treebuilder, * \param treebuilder The treebuilder instance * \param token The token to process */ -void process_container_in_body(hubbub_treebuilder *treebuilder, +hubbub_error process_container_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token) { - if (element_in_scope(treebuilder, P, false)) { - process_0p_in_body(treebuilder); + hubbub_error err; + + if (treebuilder->context.mode_state == IBS_INITIAL) { + if (element_in_scope(treebuilder, P, false)) { + err = process_0p_in_body(treebuilder); + if (err != HUBBUB_OK) + return err; + } + + treebuilder->context.mode_state = IBS_CLOSED_P; } - insert_element(treebuilder, &token->data.tag, true); + return insert_element(treebuilder, &token->data.tag, true); } /** @@ -560,36 +621,43 @@ void process_container_in_body(hubbub_treebuilder *treebuilder, * \param treebuilder The treebuilder instance * \param token The token to process */ -void process_hN_in_body(hubbub_treebuilder *treebuilder, +hubbub_error process_hN_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token) { + hubbub_error err; element_type type; - if (element_in_scope(treebuilder, P, false)) { - process_0p_in_body(treebuilder); - } + if (treebuilder->context.mode_state == IBS_INITIAL) { + if (element_in_scope(treebuilder, P, false)) { + err = process_0p_in_body(treebuilder); + if (err != HUBBUB_OK) + return err; + } - type = treebuilder->context.element_stack[ - treebuilder->context.current_node].type; + type = treebuilder->context.element_stack[ + treebuilder->context.current_node].type; - if (type == H1 || type == H2 || type == H3 || type == H4 || - type == H5 || type == H6) { - hubbub_ns ns; - element_type otype; - void *node; + if (type == H1 || type == H2 || type == H3 || type == H4 || + type == H5 || type == H6) { + hubbub_ns ns; + element_type otype; + void *node; - /** \todo parse error */ + /** \todo parse error */ - if (!element_stack_pop(treebuilder, &ns, &otype, &node)) { - /** \todo errors */ + err = element_stack_pop(treebuilder, + &ns, &otype, &node); + assert(err == HUBBUB_OK); + + treebuilder->tree_handler->unref_node( + treebuilder->tree_handler->ctx, + node); } - treebuilder->tree_handler->unref_node( - treebuilder->tree_handler->ctx, - node); + treebuilder->context.mode_state = IBS_CLOSED_P; } - insert_element(treebuilder, &token->data.tag, true); + return insert_element(treebuilder, &token->data.tag, true); } /** @@ -598,17 +666,27 @@ void process_hN_in_body(hubbub_treebuilder *treebuilder, * \param treebuilder The treebuilder instance * \param token The token to process */ -void process_form_in_body(hubbub_treebuilder *treebuilder, +hubbub_error process_form_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token) { + hubbub_error err; + if (treebuilder->context.form_element != NULL) { /** \todo parse error */ } else { - if (element_in_scope(treebuilder, P, false)) { - process_0p_in_body(treebuilder); + if (treebuilder->context.mode_state == IBS_INITIAL) { + if (element_in_scope(treebuilder, P, false)) { + err = process_0p_in_body(treebuilder); + if (err != HUBBUB_OK) + return err; + } + + treebuilder->context.mode_state = IBS_CLOSED_P; } - insert_element(treebuilder, &token->data.tag, true); + err = insert_element(treebuilder, &token->data.tag, true); + if (err != HUBBUB_OK) + return err; /* Claim a reference on the node and * use it as the current form element */ @@ -621,6 +699,8 @@ void process_form_in_body(hubbub_treebuilder *treebuilder, treebuilder->context.element_stack[ treebuilder->context.current_node].node; } + + return HUBBUB_OK; } /** @@ -630,62 +710,69 @@ void process_form_in_body(hubbub_treebuilder *treebuilder, * \param token The token to process * \param type The element type */ -void process_dd_dt_li_in_body(hubbub_treebuilder *treebuilder, +hubbub_error process_dd_dt_li_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token, element_type type) { + hubbub_error err; element_context *stack = treebuilder->context.element_stack; uint32_t node; - treebuilder->context.frameset_ok = false; - - if (element_in_scope(treebuilder, P, false)) { - process_0p_in_body(treebuilder); - } + if (treebuilder->context.mode_state == IBS_INITIAL) { + treebuilder->context.frameset_ok = false; - /* Find last LI/(DD,DT) on stack, if any */ - for (node = treebuilder->context.current_node; node > 0; node--) { - element_type ntype = stack[node].type; + if (element_in_scope(treebuilder, P, false)) { + err = process_0p_in_body(treebuilder); + if (err != HUBBUB_OK) + return err; + } - if (type == LI && ntype == LI) - break; + /* Find last LI/(DD,DT) on stack, if any */ + for (node = treebuilder->context.current_node; node > 0; + node--) { + element_type ntype = stack[node].type; - if (((type == DD || type == DT) && - (ntype == DD || ntype == DT))) - break; + if (type == LI && ntype == LI) + break; - if (!is_formatting_element(ntype) && - !is_phrasing_element(ntype) && - ntype != ADDRESS && - ntype != DIV) - break; - } + if (((type == DD || type == DT) && + (ntype == DD || ntype == DT))) + break; - /* If we found one, then pop all nodes up to and including it */ - if (stack[node].type == LI || stack[node].type == DD || - stack[node].type == DT) { - /* Check that we're only popping one node - * and emit a parse error if not */ - if (treebuilder->context.current_node > node) { - /** \todo parse error */ + if (!is_formatting_element(ntype) && + !is_phrasing_element(ntype) && + ntype != ADDRESS && + ntype != DIV) + break; } - do { - hubbub_ns ns; - element_type otype; - void *node; - - if (!element_stack_pop(treebuilder, &ns, - &otype, &node)) { - /** \todo errors */ + /* If we found one, then pop all nodes up to and including it */ + if (stack[node].type == LI || stack[node].type == DD || + stack[node].type == DT) { + /* Check that we're only popping one node + * and emit a parse error if not */ + if (treebuilder->context.current_node > node) { + /** \todo parse error */ } - treebuilder->tree_handler->unref_node( - treebuilder->tree_handler->ctx, - node); - } while (treebuilder->context.current_node >= node); + do { + hubbub_ns ns; + element_type otype; + void *node; + + err = element_stack_pop(treebuilder, &ns, + &otype, &node); + assert(err == HUBBUB_OK); + + treebuilder->tree_handler->unref_node( + treebuilder->tree_handler->ctx, + node); + } while (treebuilder->context.current_node >= node); + } + + treebuilder->context.mode_state = IBS_CLOSED_P; } - insert_element(treebuilder, &token->data.tag, true); + return insert_element(treebuilder, &token->data.tag, true); } /** @@ -694,22 +781,34 @@ void process_dd_dt_li_in_body(hubbub_treebuilder *treebuilder, * \param treebuilder The treebuilder instance * \param token The token to process */ -void process_plaintext_in_body(hubbub_treebuilder *treebuilder, +hubbub_error process_plaintext_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token) { + hubbub_error err; hubbub_tokeniser_optparams params; - if (element_in_scope(treebuilder, P, false)) { - process_0p_in_body(treebuilder); + if (treebuilder->context.mode_state == IBS_INITIAL) { + if (element_in_scope(treebuilder, P, false)) { + err = process_0p_in_body(treebuilder); + if (err != HUBBUB_OK) + return err; + } + + treebuilder->context.mode_state = IBS_CLOSED_P; } - insert_element(treebuilder, &token->data.tag, true); + err = insert_element(treebuilder, &token->data.tag, true); + if (err != HUBBUB_OK) + return err; params.content_model.model = HUBBUB_CONTENT_MODEL_PLAINTEXT; - hubbub_tokeniser_setopt(treebuilder->tokeniser, + err = hubbub_tokeniser_setopt(treebuilder->tokeniser, HUBBUB_TOKENISER_CONTENT_MODEL, ¶ms); + assert(err == HUBBUB_OK); + + return HUBBUB_OK; } /** @@ -718,9 +817,10 @@ void process_plaintext_in_body(hubbub_treebuilder *treebuilder, * \param treebuilder The treebuilder instance * \param token The token to process */ -void process_a_in_body(hubbub_treebuilder *treebuilder, +hubbub_error process_a_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token) { +/** \todo error recovery */ formatting_list_entry *entry = aa_find_formatting_element(treebuilder, A); @@ -779,6 +879,8 @@ void process_a_in_body(hubbub_treebuilder *treebuilder, treebuilder->context.element_stack[ treebuilder->context.current_node].node, treebuilder->context.current_node); + + return HUBBUB_OK; } /** @@ -789,21 +891,56 @@ void process_a_in_body(hubbub_treebuilder *treebuilder, * \param token The token to process * \param type The element type */ -void process_presentational_in_body(hubbub_treebuilder *treebuilder, +hubbub_error process_presentational_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token, element_type type) { - reconstruct_active_formatting_list(treebuilder); + hubbub_error err; - insert_element(treebuilder, &token->data.tag, true); + if (treebuilder->context.mode_state == IBS_INITIAL) { + err = reconstruct_active_formatting_list(treebuilder); + if (err != HUBBUB_OK) + return err; + + treebuilder->context.mode_state = IBS_DONE_FORMATTING_LIST; + } + + err = insert_element(treebuilder, &token->data.tag, true); + if (err != HUBBUB_OK) + return err; treebuilder->tree_handler->ref_node(treebuilder->tree_handler->ctx, treebuilder->context.element_stack[ treebuilder->context.current_node].node); - formatting_list_append(treebuilder, token->data.tag.ns, type, + err = formatting_list_append(treebuilder, token->data.tag.ns, type, treebuilder->context.element_stack[ treebuilder->context.current_node].node, treebuilder->context.current_node); + if (err != HUBBUB_OK) { + hubbub_error e; + hubbub_ns ns; + element_type type; + void *node; + + e = remove_node_from_dom(treebuilder, + treebuilder->context.element_stack[ + treebuilder->context.current_node].node); + assert(e == HUBBUB_OK); + + e = element_stack_pop(treebuilder, &ns, &type, &node); + assert(e == HUBBUB_OK); + + /* Unref twice (once for stack, once for formatting list) */ + treebuilder->tree_handler->unref_node( + treebuilder->tree_handler->ctx, node); + + treebuilder->tree_handler->unref_node( + treebuilder->tree_handler->ctx, node); + + return err; + } + + return HUBBUB_OK; } /** @@ -812,9 +949,10 @@ void process_presentational_in_body(hubbub_treebuilder *treebuilder, * \param treebuilder The treebuilder instance * \param token The token to process */ -void process_nobr_in_body(hubbub_treebuilder *treebuilder, +hubbub_error process_nobr_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token) { +/** \todo error recovery */ reconstruct_active_formatting_list(treebuilder); if (element_in_scope(treebuilder, NOBR, false)) { @@ -838,6 +976,8 @@ void process_nobr_in_body(hubbub_treebuilder *treebuilder, treebuilder->context.element_stack[ treebuilder->context.current_node].node, treebuilder->context.current_node); + + return HUBBUB_OK; } /** @@ -846,32 +986,68 @@ void process_nobr_in_body(hubbub_treebuilder *treebuilder, * \param treebuilder The treebuilder instance * \param token The token to process */ -void process_button_in_body(hubbub_treebuilder *treebuilder, +hubbub_error process_button_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token) { - if (element_in_scope(treebuilder, BUTTON, false)) { - /** \todo parse error */ + hubbub_error err; - /* Act as if has been seen */ - process_0applet_button_marquee_object_in_body(treebuilder, - BUTTON); - } + if (treebuilder->context.mode_state == IBS_INITIAL) { + if (element_in_scope(treebuilder, BUTTON, false)) { + /** \todo parse error */ - reconstruct_active_formatting_list(treebuilder); + /* Act as if has been seen */ + err = process_0applet_button_marquee_object_in_body( + treebuilder, BUTTON); + assert(err == HUBBUB_OK); + } - insert_element(treebuilder, &token->data.tag, true); + err = reconstruct_active_formatting_list(treebuilder); + if (err != HUBBUB_OK) + return err; + + treebuilder->context.mode_state = IBS_DONE_FORMATTING_LIST; + } + + err = insert_element(treebuilder, &token->data.tag, true); + if (err != HUBBUB_OK) + return err; treebuilder->tree_handler->ref_node( treebuilder->tree_handler->ctx, treebuilder->context.element_stack[ treebuilder->context.current_node].node); - formatting_list_append(treebuilder, token->data.tag.ns, BUTTON, + err = formatting_list_append(treebuilder, token->data.tag.ns, BUTTON, treebuilder->context.element_stack[ treebuilder->context.current_node].node, treebuilder->context.current_node); + if (err != HUBBUB_OK) { + hubbub_error e; + hubbub_ns ns; + element_type type; + void *node; + + e = remove_node_from_dom(treebuilder, + treebuilder->context.element_stack[ + treebuilder->context.current_node].node); + assert(e == HUBBUB_OK); + + e = element_stack_pop(treebuilder, &ns, &type, &node); + assert(e == HUBBUB_OK); + + /* Unref twice (once for stack, once for formatting list) */ + treebuilder->tree_handler->unref_node( + treebuilder->tree_handler->ctx, node); + + treebuilder->tree_handler->unref_node( + treebuilder->tree_handler->ctx, node); + + return err; + } treebuilder->context.frameset_ok = false; + + return HUBBUB_OK; } /** @@ -881,24 +1057,60 @@ void process_button_in_body(hubbub_treebuilder *treebuilder, * \param token The token to process * \param type The element type */ -void process_applet_marquee_object_in_body(hubbub_treebuilder *treebuilder, +hubbub_error process_applet_marquee_object_in_body( + hubbub_treebuilder *treebuilder, const hubbub_token *token, element_type type) { - reconstruct_active_formatting_list(treebuilder); + hubbub_error err; - insert_element(treebuilder, &token->data.tag, true); + if (treebuilder->context.mode_state == IBS_INITIAL) { + err = reconstruct_active_formatting_list(treebuilder); + if (err != HUBBUB_OK) + return err; + + treebuilder->context.mode_state = IBS_DONE_FORMATTING_LIST; + } + + err = insert_element(treebuilder, &token->data.tag, true); + if (err != HUBBUB_OK) + return err; treebuilder->tree_handler->ref_node( treebuilder->tree_handler->ctx, treebuilder->context.element_stack[ treebuilder->context.current_node].node); - formatting_list_append(treebuilder, token->data.tag.ns, type, + err = formatting_list_append(treebuilder, token->data.tag.ns, type, treebuilder->context.element_stack[ treebuilder->context.current_node].node, treebuilder->context.current_node); + if (err != HUBBUB_OK) { + hubbub_error e; + hubbub_ns ns; + element_type type; + void *node; + + e = remove_node_from_dom(treebuilder, + treebuilder->context.element_stack[ + treebuilder->context.current_node].node); + assert(e == HUBBUB_OK); + + e = element_stack_pop(treebuilder, &ns, &type, &node); + assert(e == HUBBUB_OK); + + /* Unref twice (once for stack, once for formatting list) */ + treebuilder->tree_handler->unref_node( + treebuilder->tree_handler->ctx, node); + + treebuilder->tree_handler->unref_node( + treebuilder->tree_handler->ctx, node); + + return err; + } treebuilder->context.frameset_ok = false; + + return HUBBUB_OK; } /** @@ -907,16 +1119,26 @@ void process_applet_marquee_object_in_body(hubbub_treebuilder *treebuilder, * \param treebuilder The treebuilder instance * \param token The token to process */ -void process_hr_in_body(hubbub_treebuilder *treebuilder, +hubbub_error process_hr_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token) { - if (element_in_scope(treebuilder, P, false)) { - process_0p_in_body(treebuilder); + hubbub_error err; + + if (treebuilder->context.mode_state == IBS_INITIAL) { + if (element_in_scope(treebuilder, P, false)) { + err = process_0p_in_body(treebuilder); + if (err != HUBBUB_OK) + return err; + } + + treebuilder->context.mode_state = IBS_CLOSED_P; } - insert_element(treebuilder, &token->data.tag, false); + err = insert_element(treebuilder, &token->data.tag, false); + if (err == HUBBUB_OK) + treebuilder->context.frameset_ok = false; - treebuilder->context.frameset_ok = false; + return err; } /** @@ -925,9 +1147,10 @@ void process_hr_in_body(hubbub_treebuilder *treebuilder, * \param treebuilder The treebuilder instance * \param token The token to process */ -void process_image_in_body(hubbub_treebuilder *treebuilder, +hubbub_error process_image_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token) { + hubbub_error err; hubbub_tag tag; tag.ns = HUBBUB_NS_HTML; @@ -937,9 +1160,15 @@ void process_image_in_body(hubbub_treebuilder *treebuilder, tag.n_attributes = token->data.tag.n_attributes; tag.attributes = token->data.tag.attributes; - reconstruct_active_formatting_list(treebuilder); + if (treebuilder->context.mode_state == IBS_INITIAL) { + err = reconstruct_active_formatting_list(treebuilder); + if (err != HUBBUB_OK) + return err; + + treebuilder->context.mode_state = IBS_DONE_FORMATTING_LIST; + } - insert_element(treebuilder, &tag, false); + return insert_element(treebuilder, &tag, false); } /** @@ -948,9 +1177,10 @@ void process_image_in_body(hubbub_treebuilder *treebuilder, * \param treebuilder The treebuilder instance * \param token The token to process */ -void process_isindex_in_body(hubbub_treebuilder *treebuilder, +hubbub_error process_isindex_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token) { +/** \todo error recovery */ hubbub_token dummy; hubbub_attribute *action = NULL; hubbub_attribute *prompt = NULL; @@ -960,7 +1190,7 @@ void process_isindex_in_body(hubbub_treebuilder *treebuilder, /** \todo parse error */ if (treebuilder->context.form_element != NULL) - return; + return HUBBUB_OK; /* First up, clone the token's attributes */ if (token->data.tag.n_attributes > 0) { @@ -969,10 +1199,8 @@ void process_isindex_in_body(hubbub_treebuilder *treebuilder, (token->data.tag.n_attributes + 1) * sizeof(hubbub_attribute), treebuilder->alloc_pw); - if (attrs == NULL) { - /** \todo error handling */ - return; - } + if (attrs == NULL) + return HUBBUB_NOMEM; for (i = 0; i < token->data.tag.n_attributes; i++) { hubbub_attribute *attr = &token->data.tag.attributes[i]; @@ -1084,6 +1312,8 @@ void process_isindex_in_body(hubbub_treebuilder *treebuilder, /* Clean up */ treebuilder->alloc(attrs, 0, treebuilder->alloc_pw); + + return HUBBUB_OK; } /** @@ -1092,12 +1322,12 @@ void process_isindex_in_body(hubbub_treebuilder *treebuilder, * \param treebuilder The treebuilder instance * \param token The token to process */ -void process_textarea_in_body(hubbub_treebuilder *treebuilder, +hubbub_error process_textarea_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token) { treebuilder->context.strip_leading_lr = true; treebuilder->context.frameset_ok = false; - parse_generic_rcdata(treebuilder, token, true); + return parse_generic_rcdata(treebuilder, token, true); } /** @@ -1106,14 +1336,24 @@ void process_textarea_in_body(hubbub_treebuilder *treebuilder, * \param treebuilder The treebuilder instance * \param token The token to process */ -void process_select_in_body(hubbub_treebuilder *treebuilder, +hubbub_error process_select_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token) { - reconstruct_active_formatting_list(treebuilder); + hubbub_error err; - insert_element(treebuilder, &token->data.tag, true); + if (treebuilder->context.mode_state == IBS_INITIAL) { + err = reconstruct_active_formatting_list(treebuilder); + if (err != HUBBUB_OK) + return err; - treebuilder->context.frameset_ok = false; + treebuilder->context.mode_state = IBS_DONE_FORMATTING_LIST; + } + + err = insert_element(treebuilder, &token->data.tag, true); + if (err == HUBBUB_OK) + treebuilder->context.frameset_ok = false; + + return err; } /** @@ -1122,16 +1362,26 @@ void process_select_in_body(hubbub_treebuilder *treebuilder, * \param treebuilder The treebuilder instance * \param token The token to process */ -void process_opt_in_body(hubbub_treebuilder *treebuilder, +hubbub_error process_opt_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token) { - if (element_in_scope(treebuilder, OPTION, false)) { - process_0generic_in_body(treebuilder, OPTION); - } + hubbub_error err; + + if (treebuilder->context.mode_state == IBS_INITIAL) { + if (element_in_scope(treebuilder, OPTION, false)) { + err = process_0generic_in_body(treebuilder, OPTION); + /* Cannot fail */ + assert(err == HUBBUB_OK); + } - reconstruct_active_formatting_list(treebuilder); + err = reconstruct_active_formatting_list(treebuilder); + if (err != HUBBUB_OK) + return err; - insert_element(treebuilder, &token->data.tag, true); + treebuilder->context.mode_state = IBS_DONE_FORMATTING_LIST; + } + + return insert_element(treebuilder, &token->data.tag, true); } /** @@ -1140,12 +1390,18 @@ void process_opt_in_body(hubbub_treebuilder *treebuilder, * \param treebuilder The treebuilder instance * \param token The token to process */ -void process_phrasing_in_body(hubbub_treebuilder *treebuilder, +hubbub_error process_phrasing_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token) { - reconstruct_active_formatting_list(treebuilder); + hubbub_error err; - insert_element(treebuilder, &token->data.tag, true); + if (treebuilder->context.mode_state == IBS_INITIAL) { + err = reconstruct_active_formatting_list(treebuilder); + if (err != HUBBUB_OK) + return err; + } + + return insert_element(treebuilder, &token->data.tag, true); } /** @@ -1154,13 +1410,12 @@ void process_phrasing_in_body(hubbub_treebuilder *treebuilder, * \param treebuilder The treebuilder instance * \return True if processed, false otherwise */ -bool process_0body_in_body(hubbub_treebuilder *treebuilder) +hubbub_error process_0body_in_body(hubbub_treebuilder *treebuilder) { - bool processed = true; + hubbub_error err = HUBBUB_OK; if (!element_in_scope(treebuilder, BODY, false)) { /** \todo parse error */ - processed = true; } else { element_context *stack = treebuilder->context.element_stack; uint32_t node; @@ -1179,9 +1434,14 @@ bool process_0body_in_body(hubbub_treebuilder *treebuilder) /** \todo parse error */ } } + + if (treebuilder->context.mode == IN_BODY) + treebuilder->context.mode = AFTER_BODY; + + err = HUBBUB_REPROCESS; } - return processed; + return err; } /** @@ -1190,7 +1450,7 @@ bool process_0body_in_body(hubbub_treebuilder *treebuilder) * \param treebuilder The treebuilder instance * \param type The element type */ -void process_0container_in_body(hubbub_treebuilder *treebuilder, +hubbub_error process_0container_in_body(hubbub_treebuilder *treebuilder, element_type type) { if (!element_in_scope(treebuilder, type, false)) { @@ -1202,13 +1462,12 @@ void process_0container_in_body(hubbub_treebuilder *treebuilder, close_implied_end_tags(treebuilder, UNKNOWN); do { + hubbub_error e; hubbub_ns ns; void *node; - if (!element_stack_pop(treebuilder, &ns, &otype, - &node)) { - /** \todo errors */ - } + e = element_stack_pop(treebuilder, &ns, &otype, &node); + assert(e == HUBBUB_OK); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, @@ -1221,6 +1480,8 @@ void process_0container_in_body(hubbub_treebuilder *treebuilder, /** \todo parse error */ } } + + return HUBBUB_OK; } /** @@ -1228,8 +1489,9 @@ void process_0container_in_body(hubbub_treebuilder *treebuilder, * * \param treebuilder The treebuilder instance */ -void process_0form_in_body(hubbub_treebuilder *treebuilder) +hubbub_error process_0form_in_body(hubbub_treebuilder *treebuilder) { + hubbub_error err; void *node = treebuilder->context.form_element; uint32_t idx = 0; @@ -1257,12 +1519,16 @@ void process_0form_in_body(hubbub_treebuilder *treebuilder) /** \todo parse error */ } - element_stack_remove(treebuilder, idx, &ns, &otype, &node); + err = element_stack_remove(treebuilder, idx, + &ns, &otype, &node); + assert(err == HUBBUB_OK); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, node); } + + return HUBBUB_OK; } @@ -1271,8 +1537,9 @@ void process_0form_in_body(hubbub_treebuilder *treebuilder) * * \param treebuilder The treebuilder instance */ -void process_0p_in_body(hubbub_treebuilder *treebuilder) +hubbub_error process_0p_in_body(hubbub_treebuilder *treebuilder) { + hubbub_error err = HUBBUB_OK; uint32_t popped = 0; if (treebuilder->context.element_stack[ @@ -1285,9 +1552,8 @@ void process_0p_in_body(hubbub_treebuilder *treebuilder) element_type type; void *node; - if (!element_stack_pop(treebuilder, &ns, &type, &node)) { - /** \todo errors */ - } + err = element_stack_pop(treebuilder, &ns, &type, &node); + assert(err == HUBBUB_OK); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, node); @@ -1305,12 +1571,18 @@ void process_0p_in_body(hubbub_treebuilder *treebuilder) dummy.data.tag.n_attributes = 0; dummy.data.tag.attributes = NULL; - process_container_in_body(treebuilder, &dummy); + err = process_container_in_body(treebuilder, &dummy); + if (err != HUBBUB_OK) + return err; /* Reprocess the end tag. This is safe as we've just * inserted a

into the current scope */ - process_0p_in_body(treebuilder); + err = process_0p_in_body(treebuilder); + /* Cannot fail */ + assert(err == HUBBUB_OK); } + + return err; } /** @@ -1319,9 +1591,11 @@ void process_0p_in_body(hubbub_treebuilder *treebuilder) * \param treebuilder The treebuilder instance * \param type The element type */ -void process_0dd_dt_li_in_body(hubbub_treebuilder *treebuilder, +hubbub_error process_0dd_dt_li_in_body(hubbub_treebuilder *treebuilder, element_type type) { + hubbub_error err; + if (!element_in_scope(treebuilder, type, false)) { /** \todo parse error */ } else { @@ -1334,9 +1608,9 @@ void process_0dd_dt_li_in_body(hubbub_treebuilder *treebuilder, hubbub_ns ns; void *node; - if (!element_stack_pop(treebuilder, &ns, &otype, &node)) { - /** \todo errors */ - } + err = element_stack_pop(treebuilder, + &ns, &otype, &node); + assert(err == HUBBUB_OK); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, @@ -1349,6 +1623,8 @@ void process_0dd_dt_li_in_body(hubbub_treebuilder *treebuilder, /** \todo parse error */ } } + + return HUBBUB_OK; } /** @@ -1357,7 +1633,7 @@ void process_0dd_dt_li_in_body(hubbub_treebuilder *treebuilder, * \param treebuilder The treebuilder instance * \param type The element type */ -void process_0h_in_body(hubbub_treebuilder *treebuilder, +hubbub_error process_0h_in_body(hubbub_treebuilder *treebuilder, element_type type) { UNUSED(type); @@ -1375,13 +1651,12 @@ void process_0h_in_body(hubbub_treebuilder *treebuilder, close_implied_end_tags(treebuilder, UNKNOWN); do { + hubbub_error e; hubbub_ns ns; void *node; - if (!element_stack_pop(treebuilder, &ns, &otype, - &node)) { - /** \todo errors */ - } + e = element_stack_pop(treebuilder, &ns, &otype, &node); + assert(e == HUBBUB_OK); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, @@ -1398,6 +1673,8 @@ void process_0h_in_body(hubbub_treebuilder *treebuilder, } else { /** \todo parse error */ } + + return HUBBUB_OK; } /** @@ -1406,9 +1683,12 @@ void process_0h_in_body(hubbub_treebuilder *treebuilder, * \param treebuilder The treebuilder instance * \param type The element type */ -void process_0presentational_in_body(hubbub_treebuilder *treebuilder, +hubbub_error process_0presentational_in_body(hubbub_treebuilder *treebuilder, element_type type) { + hubbub_error err; + +/** \todo error recovery */ /* Welcome to the adoption agency */ while (true) { @@ -1429,9 +1709,11 @@ void process_0presentational_in_body(hubbub_treebuilder *treebuilder, uint32_t oindex; /* 1 */ - if (!aa_find_and_validate_formatting_element(treebuilder, - type, &entry)) - return; + err = aa_find_and_validate_formatting_element(treebuilder, + type, &entry); + assert(err == HUBBUB_OK || err == HUBBUB_REPROCESS); + if (err == HUBBUB_OK) + return err; assert(entry->details.type == type); @@ -1440,9 +1722,11 @@ void process_0presentational_in_body(hubbub_treebuilder *treebuilder, formatting_element = entry->stack_index; /* 2 & 3 */ - if (!aa_find_furthest_block(treebuilder, - entry, &furthest_block)) - return; + err = aa_find_furthest_block(treebuilder, + entry, &furthest_block); + assert(err == HUBBUB_OK || err == HUBBUB_REPROCESS); + if (err == HUBBUB_OK) + return err; /* 4 */ common_ancestor = formatting_element - 1; @@ -1452,9 +1736,11 @@ void process_0presentational_in_body(hubbub_treebuilder *treebuilder, bookmark.next = entry->next; /* 6 */ - aa_find_bookmark_location_reparenting_misnested(treebuilder, - formatting_element, &furthest_block, - &bookmark, &last_node); + err = aa_find_bookmark_location_reparenting_misnested( + treebuilder, formatting_element, + &furthest_block, &bookmark, &last_node); + if (err != HUBBUB_OK) + return err; /* 7 */ if (stack[common_ancestor].type == TABLE || @@ -1462,13 +1748,21 @@ void process_0presentational_in_body(hubbub_treebuilder *treebuilder, stack[common_ancestor].type == TFOOT || stack[common_ancestor].type == THEAD || stack[common_ancestor].type == TR) { - reparented = aa_insert_into_foster_parent(treebuilder, - stack[last_node].node); + err = aa_insert_into_foster_parent(treebuilder, + stack[last_node].node, &reparented); } else { - reparented = aa_reparent_node(treebuilder, + err = aa_reparent_node(treebuilder, stack[last_node].node, - stack[common_ancestor].node); + stack[common_ancestor].node, + &reparented); } + if (err != HUBBUB_OK) + return err; + + treebuilder->tree_handler->unref_node( + treebuilder->tree_handler->ctx, + stack[last_node].node); + /* If the reparented node is not the same as the one we were * previously using, then have it take the place of the other * one in the formatting list and stack. */ @@ -1494,20 +1788,26 @@ void process_0presentational_in_body(hubbub_treebuilder *treebuilder, } /* 8 */ - treebuilder->tree_handler->clone_node( + err = treebuilder->tree_handler->clone_node( treebuilder->tree_handler->ctx, entry->details.node, false, &fe_clone); + if (err != HUBBUB_OK) + return err; /* 9 */ - treebuilder->tree_handler->reparent_children( + err = treebuilder->tree_handler->reparent_children( treebuilder->tree_handler->ctx, stack[furthest_block].node, fe_clone); + if (err != HUBBUB_OK) + return err; /* 10 */ - treebuilder->tree_handler->append_child( + err = treebuilder->tree_handler->append_child( treebuilder->tree_handler->ctx, stack[furthest_block].node, fe_clone, &clone_appended); + if (err != HUBBUB_OK) + return err; if (clone_appended != fe_clone) { /* No longer interested in fe_clone */ @@ -1525,8 +1825,9 @@ void process_0presentational_in_body(hubbub_treebuilder *treebuilder, * stack index to use when inserting into the formatting list */ /* 12 */ - aa_remove_element_stack_item(treebuilder, formatting_element, - furthest_block); + err = aa_remove_element_stack_item(treebuilder, + formatting_element, furthest_block); + assert(err == HUBBUB_OK); /* Fix up furthest block index */ furthest_block--; @@ -1537,15 +1838,18 @@ void process_0presentational_in_body(hubbub_treebuilder *treebuilder, stack[furthest_block + 1].node = clone_appended; /* 11 */ - formatting_list_remove(treebuilder, entry, + err = formatting_list_remove(treebuilder, entry, &ons, &otype, &onode, &oindex); + assert(err == HUBBUB_OK); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, onode); - formatting_list_insert(treebuilder, + err = formatting_list_insert(treebuilder, bookmark.prev, bookmark.next, ons, otype, clone_appended, furthest_block + 1); + if (err != HUBBUB_OK) + return err; /* 13 */ } @@ -1557,9 +1861,11 @@ void process_0presentational_in_body(hubbub_treebuilder *treebuilder, * \param treebuilder The treebuilder instance * \param type Element type to search for * \param element Pointer to location to receive list entry - * \return True to continue processing, false to stop + * \return HUBBUB_REPROCESS to continue processing, + * HUBBUB_OK to stop. */ -bool aa_find_and_validate_formatting_element(hubbub_treebuilder *treebuilder, +hubbub_error aa_find_and_validate_formatting_element( + hubbub_treebuilder *treebuilder, element_type type, formatting_list_entry **element) { formatting_list_entry *entry; @@ -1570,11 +1876,12 @@ bool aa_find_and_validate_formatting_element(hubbub_treebuilder *treebuilder, element_in_scope(treebuilder, entry->details.type, false) != entry->stack_index)) { /** \todo parse error */ - return false; + return HUBBUB_OK; } if (entry->stack_index == 0) { /* Not in element stack => remove from formatting list */ + hubbub_error e; hubbub_ns ns; element_type type; void *node; @@ -1582,15 +1889,14 @@ bool aa_find_and_validate_formatting_element(hubbub_treebuilder *treebuilder, /** \todo parse error */ - if (!formatting_list_remove(treebuilder, entry, - &ns, &type, &node, &index)) { - /** \todo errors */ - } + e = formatting_list_remove(treebuilder, entry, + &ns, &type, &node, &index); + assert(e == HUBBUB_OK); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, node); - return false; + return HUBBUB_OK; } if (entry->stack_index != treebuilder->context.current_node) { @@ -1599,7 +1905,7 @@ bool aa_find_and_validate_formatting_element(hubbub_treebuilder *treebuilder, *element = entry; - return true; + return HUBBUB_REPROCESS; } /** @@ -1636,9 +1942,10 @@ formatting_list_entry *aa_find_formatting_element( * \param treebuilder The treebuilder instance * \param formatting_element The formatting element * \param furthest_block Pointer to location to receive furthest block - * \return True to continue processing (::furthest_block filled in). + * \return HUBBUB_REPROCESS to continue processing (::furthest_block filled in), + * HUBBUB_OK to stop. */ -bool aa_find_furthest_block(hubbub_treebuilder *treebuilder, +hubbub_error aa_find_furthest_block(hubbub_treebuilder *treebuilder, formatting_list_entry *formatting_element, uint32_t *furthest_block) { @@ -1653,6 +1960,7 @@ bool aa_find_furthest_block(hubbub_treebuilder *treebuilder, } if (fb > treebuilder->context.current_node) { + hubbub_error e; hubbub_ns ns; element_type type; void *node; @@ -1661,9 +1969,8 @@ bool aa_find_furthest_block(hubbub_treebuilder *treebuilder, /* Pop all elements off the stack up to, * and including, the formatting element */ do { - if (!element_stack_pop(treebuilder, &ns, &type, &node)) { - /** \todo errors */ - } + e = element_stack_pop(treebuilder, &ns, &type, &node); + assert(e == HUBBUB_OK); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, @@ -1671,49 +1978,19 @@ bool aa_find_furthest_block(hubbub_treebuilder *treebuilder, } while (treebuilder->context.current_node >= fe_index); /* Remove the formatting element from the list */ - if (!formatting_list_remove(treebuilder, formatting_element, - &ns, &type, &node, &index)) { - /* \todo errors */ - } + e = formatting_list_remove(treebuilder, formatting_element, + &ns, &type, &node, &index); + assert(e == HUBBUB_OK); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, node); - return false; + return HUBBUB_OK; } *furthest_block = fb; - return true; -} - -/** - * Adoption agency: remove a node from its parent - * - * \param treebuilder The treebuilder instance - * \param node Node to remove - */ -void aa_remove_from_parent(hubbub_treebuilder *treebuilder, void *node) -{ - /* Get parent */ - void *parent = NULL; - - treebuilder->tree_handler->get_parent(treebuilder->tree_handler->ctx, - node, false, &parent); - - if (parent != NULL) { - void *removed; - - treebuilder->tree_handler->remove_child( - treebuilder->tree_handler->ctx, - parent, node, &removed); - - treebuilder->tree_handler->unref_node( - treebuilder->tree_handler->ctx, removed); - - treebuilder->tree_handler->unref_node( - treebuilder->tree_handler->ctx, parent); - } + return HUBBUB_REPROCESS; } /** @@ -1722,26 +1999,25 @@ void aa_remove_from_parent(hubbub_treebuilder *treebuilder, void *node) * \param treebuilder The treebuilder instance * \param node The node to reparent * \param new_parent The new parent - * \return Pointer to reparented node + * \param reparented Pointer to location to receive reparented node + * \return HUBBUB_OK on success, appropriate error otherwise */ -void *aa_reparent_node(hubbub_treebuilder *treebuilder, void *node, - void *new_parent) +hubbub_error aa_reparent_node(hubbub_treebuilder *treebuilder, void *node, + void *new_parent, void **reparented) { - void *appended; + hubbub_error err; - aa_remove_from_parent(treebuilder, node); + err = remove_node_from_dom(treebuilder, node); + if (err != HUBBUB_OK) + return err; - treebuilder->tree_handler->append_child(treebuilder->tree_handler->ctx, - new_parent, node, &appended); - - treebuilder->tree_handler->unref_node(treebuilder->tree_handler->ctx, - node); - - return appended; + return treebuilder->tree_handler->append_child( + treebuilder->tree_handler->ctx, + new_parent, node, reparented); } /** - * Adoption agency: this is step 7 + * Adoption agency: this is step 6 * * \param treebuilder The treebuilder instance * \param formatting_element The stack index of the formatting element @@ -1750,11 +2026,12 @@ void *aa_reparent_node(hubbub_treebuilder *treebuilder, void *node, * \param bookmark Pointer to bookmark (pre-initialised) * \param last_node Pointer to location to receive index of last node */ -void aa_find_bookmark_location_reparenting_misnested( +hubbub_error aa_find_bookmark_location_reparenting_misnested( hubbub_treebuilder *treebuilder, uint32_t formatting_element, uint32_t *furthest_block, bookmark *bookmark, uint32_t *last_node) { + hubbub_error err; element_context *stack = treebuilder->context.element_stack; uint32_t node, last, fb; formatting_list_entry *node_entry; @@ -1777,8 +2054,9 @@ void aa_find_bookmark_location_reparenting_misnested( /* Node is not in list of active formatting elements */ if (node_entry == NULL) { - aa_remove_element_stack_item(treebuilder, + err = aa_remove_element_stack_item(treebuilder, node, treebuilder->context.current_node); + assert(err == HUBBUB_OK); /* Update furthest block index and the last node index, * as these are always below node in the stack */ @@ -1803,11 +2081,22 @@ void aa_find_bookmark_location_reparenting_misnested( } /* v */ - aa_clone_and_replace_entries(treebuilder, node_entry); + err = aa_clone_and_replace_entries(treebuilder, node_entry); + if (err != HUBBUB_OK) { + /** \todo error recovery */ + return err; + } /* vi */ - reparented = aa_reparent_node(treebuilder, - stack[last].node, stack[node].node); + err = aa_reparent_node(treebuilder, stack[last].node, + stack[node].node, &reparented); + if (err != HUBBUB_OK) + return err; + + treebuilder->tree_handler->unref_node( + treebuilder->tree_handler->ctx, + stack[last].node); + /* If the reparented node is not the same as the one we were * previously using, then have it take the place of the other * one in the formatting list and stack. */ @@ -1840,6 +2129,8 @@ void aa_find_bookmark_location_reparenting_misnested( *furthest_block = fb; *last_node = last; + + return HUBBUB_OK; } /** @@ -1852,7 +2143,7 @@ void aa_find_bookmark_location_reparenting_misnested( * Preconditions: index < limit, limit <= current_node * Postcondition: stack[limit] is empty */ -void aa_remove_element_stack_item(hubbub_treebuilder *treebuilder, +hubbub_error aa_remove_element_stack_item(hubbub_treebuilder *treebuilder, uint32_t index, uint32_t limit) { element_context *stack = treebuilder->context.element_stack; @@ -1888,6 +2179,8 @@ void aa_remove_element_stack_item(hubbub_treebuilder *treebuilder, /* Now, shuffle the stack up one, removing node in the process */ memmove(&stack[index], &stack[index + 1], (limit - index) * sizeof(element_context)); + + return HUBBUB_OK; } /** @@ -1897,23 +2190,28 @@ void aa_remove_element_stack_item(hubbub_treebuilder *treebuilder, * \param treebuilder The treebuilder instance * \param element The item in the formatting list containing the node */ -void aa_clone_and_replace_entries(hubbub_treebuilder *treebuilder, +hubbub_error aa_clone_and_replace_entries(hubbub_treebuilder *treebuilder, formatting_list_entry *element) { + hubbub_error err; hubbub_ns ons; element_type otype; uint32_t oindex; void *clone, *onode; /* Shallow clone of node */ - treebuilder->tree_handler->clone_node(treebuilder->tree_handler->ctx, + err = treebuilder->tree_handler->clone_node( + treebuilder->tree_handler->ctx, element->details.node, false, &clone); + if (err != HUBBUB_OK) + return err; /* Replace formatting list entry for node with clone */ - formatting_list_replace(treebuilder, element, + err = formatting_list_replace(treebuilder, element, element->details.ns, element->details.type, clone, element->stack_index, &ons, &otype, &onode, &oindex); + assert(err == HUBBUB_OK); treebuilder->tree_handler->unref_node(treebuilder->tree_handler->ctx, onode); @@ -1926,6 +2224,8 @@ void aa_clone_and_replace_entries(hubbub_treebuilder *treebuilder, treebuilder->tree_handler->unref_node(treebuilder->tree_handler->ctx, onode); + + return HUBBUB_OK; } /** @@ -1933,14 +2233,16 @@ void aa_clone_and_replace_entries(hubbub_treebuilder *treebuilder, * * \param treebuilder The treebuilder instance * \param node The node to insert - * \return Pointer to inserted node + * \param inserted Pointer to location to receive inserted node + * \return HUBBUB_OK on success, appropriate error otherwise */ -void *aa_insert_into_foster_parent(hubbub_treebuilder *treebuilder, void *node) +hubbub_error aa_insert_into_foster_parent(hubbub_treebuilder *treebuilder, + void *node, void **inserted) { + hubbub_error err; element_context *stack = treebuilder->context.element_stack; void *foster_parent = NULL; bool insert = false; - void *inserted; uint32_t cur_table = current_table(treebuilder); @@ -1971,28 +2273,29 @@ void *aa_insert_into_foster_parent(hubbub_treebuilder *treebuilder, void *node) } } - aa_remove_from_parent(treebuilder, node); + err = remove_node_from_dom(treebuilder, node); + if (err != HUBBUB_OK) + return err; if (insert) { - treebuilder->tree_handler->insert_before( + err = treebuilder->tree_handler->insert_before( treebuilder->tree_handler->ctx, foster_parent, node, stack[cur_table].node, - &inserted); + inserted); } else { - treebuilder->tree_handler->append_child( + err = treebuilder->tree_handler->append_child( treebuilder->tree_handler->ctx, foster_parent, node, - &inserted); + inserted); } - - treebuilder->tree_handler->unref_node(treebuilder->tree_handler->ctx, - node); + if (err != HUBBUB_OK) + return err; treebuilder->tree_handler->unref_node(treebuilder->tree_handler->ctx, foster_parent); - return inserted; + return HUBBUB_OK; } @@ -2002,7 +2305,7 @@ void *aa_insert_into_foster_parent(hubbub_treebuilder *treebuilder, void *node) * \param treebuilder The treebuilder instance * \param type The element type */ -void process_0applet_button_marquee_object_in_body( +hubbub_error process_0applet_button_marquee_object_in_body( hubbub_treebuilder *treebuilder, element_type type) { if (!element_in_scope(treebuilder, type, false)) { @@ -2014,13 +2317,12 @@ void process_0applet_button_marquee_object_in_body( close_implied_end_tags(treebuilder, UNKNOWN); do { + hubbub_error e; hubbub_ns ns; void *node; - if (!element_stack_pop(treebuilder, &ns, &otype, - &node)) { - /** \todo errors */ - } + e = element_stack_pop(treebuilder, &ns, &otype, &node); + assert(e == HUBBUB_OK); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, @@ -2035,6 +2337,8 @@ void process_0applet_button_marquee_object_in_body( clear_active_formatting_list_to_marker(treebuilder); } + + return HUBBUB_OK; } /** @@ -2042,8 +2346,9 @@ void process_0applet_button_marquee_object_in_body( * * \param treebuilder The treebuilder instance */ -void process_0br_in_body(hubbub_treebuilder *treebuilder) +hubbub_error process_0br_in_body(hubbub_treebuilder *treebuilder) { + hubbub_error err; hubbub_tag tag; /** \todo parse error */ @@ -2057,9 +2362,15 @@ void process_0br_in_body(hubbub_treebuilder *treebuilder) tag.n_attributes = 0; tag.attributes = NULL; - reconstruct_active_formatting_list(treebuilder); + if (treebuilder->context.mode_state == IBS_INITIAL) { + err = reconstruct_active_formatting_list(treebuilder); + if (err != HUBBUB_OK) + return err; - insert_element(treebuilder, &tag, false); + treebuilder->context.mode_state = IBS_DONE_FORMATTING_LIST; + } + + return insert_element(treebuilder, &tag, false); } /** @@ -2068,7 +2379,7 @@ void process_0br_in_body(hubbub_treebuilder *treebuilder) * \param treebuilder The treebuilder instance * \param type The element type */ -void process_0generic_in_body(hubbub_treebuilder *treebuilder, +hubbub_error process_0generic_in_body(hubbub_treebuilder *treebuilder, element_type type) { element_context *stack = treebuilder->context.element_stack; @@ -2082,13 +2393,13 @@ void process_0generic_in_body(hubbub_treebuilder *treebuilder, close_implied_end_tags(treebuilder, UNKNOWN); while (treebuilder->context.current_node >= node) { + hubbub_error e; hubbub_ns ns; void *node; - if (!element_stack_pop(treebuilder, - &ns, &otype, &node)) { - /** \todo errors */ - } + e = element_stack_pop(treebuilder, + &ns, &otype, &node); + assert(e == HUBBUB_OK); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, @@ -2111,5 +2422,7 @@ void process_0generic_in_body(hubbub_treebuilder *treebuilder, break; } } while (--node > 0); + + return HUBBUB_OK; } diff --git a/src/treebuilder/in_caption.c b/src/treebuilder/in_caption.c index 6e6eb6a..24f30e4 100644 --- a/src/treebuilder/in_caption.c +++ b/src/treebuilder/in_caption.c @@ -40,7 +40,7 @@ hubbub_error handle_in_caption(hubbub_treebuilder *treebuilder, err = HUBBUB_REPROCESS; } else { /* Process as if "in body" */ - handle_in_body(treebuilder, token); + err = handle_in_body(treebuilder, token); } } break; @@ -61,7 +61,7 @@ hubbub_error handle_in_caption(hubbub_treebuilder *treebuilder, /** \todo parse error */ } else { /* Process as if "in body" */ - handle_in_body(treebuilder, token); + err = handle_in_body(treebuilder, token); } } break; @@ -70,12 +70,13 @@ hubbub_error handle_in_caption(hubbub_treebuilder *treebuilder, case HUBBUB_TOKEN_DOCTYPE: case HUBBUB_TOKEN_EOF: /* Process as if "in body" */ - handle_in_body(treebuilder, token); + err = handle_in_body(treebuilder, token); break; } if (handled || err == HUBBUB_REPROCESS) { + hubbub_error e; hubbub_ns ns; element_type otype = UNKNOWN; void *node; @@ -84,14 +85,11 @@ hubbub_error handle_in_caption(hubbub_treebuilder *treebuilder, close_implied_end_tags(treebuilder, UNKNOWN); - while (otype != CAPTION) { /** \todo parse error */ - if (!element_stack_pop(treebuilder, &ns, &otype, - &node)) { - /** \todo errors */ - } + e = element_stack_pop(treebuilder, &ns, &otype, &node); + assert(e == HUBBUB_OK); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, diff --git a/src/treebuilder/in_cell.c b/src/treebuilder/in_cell.c index 6a6c918..0510126 100644 --- a/src/treebuilder/in_cell.c +++ b/src/treebuilder/in_cell.c @@ -21,6 +21,7 @@ */ static inline void close_cell(hubbub_treebuilder *treebuilder) { + hubbub_error e; hubbub_ns ns; element_type otype = UNKNOWN; void *node; @@ -39,9 +40,8 @@ static inline void close_cell(hubbub_treebuilder *treebuilder) /** \todo parse error */ while (otype != type) { - if (!element_stack_pop(treebuilder, &ns, &otype, &node)) { - /** \todo errors */ - } + e = element_stack_pop(treebuilder, &ns, &otype, &node); + assert(e == HUBBUB_OK); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, @@ -62,7 +62,8 @@ static inline void close_cell(hubbub_treebuilder *treebuilder) * \param token The token to process * \return True to reprocess the token, false otherwise */ -hubbub_error handle_in_cell(hubbub_treebuilder *treebuilder, const hubbub_token *token) +hubbub_error handle_in_cell(hubbub_treebuilder *treebuilder, + const hubbub_token *token) { hubbub_error err = HUBBUB_OK; @@ -91,6 +92,7 @@ hubbub_error handle_in_cell(hubbub_treebuilder *treebuilder, const hubbub_token if (type == TH || type == TD) { if (element_in_scope(treebuilder, type, true)) { + hubbub_error e; hubbub_ns ns; element_type otype = UNKNOWN; void *node; @@ -99,14 +101,13 @@ hubbub_error handle_in_cell(hubbub_treebuilder *treebuilder, const hubbub_token /** \todo parse error */ while (otype != type) { - if (!element_stack_pop(treebuilder, - &ns, &otype, &node)) { - /** \todo errors */ - } + e = element_stack_pop(treebuilder, + &ns, &otype, &node); + assert(e == HUBBUB_OK); treebuilder->tree_handler->unref_node( - treebuilder->tree_handler->ctx, - node); + treebuilder->tree_handler->ctx, + node); } clear_active_formatting_list_to_marker( diff --git a/src/treebuilder/in_column_group.c b/src/treebuilder/in_column_group.c index e489e6b..ba0a4e1 100644 --- a/src/treebuilder/in_column_group.c +++ b/src/treebuilder/in_column_group.c @@ -29,13 +29,11 @@ hubbub_error handle_in_column_group(hubbub_treebuilder *treebuilder, switch (token->type) { case HUBBUB_TOKEN_CHARACTER: - if (process_characters_expect_whitespace(treebuilder, - token, true)) { - err = HUBBUB_REPROCESS; - } + err = process_characters_expect_whitespace(treebuilder, + token, true); break; case HUBBUB_TOKEN_COMMENT: - process_comment_append(treebuilder, token, + err = process_comment_append(treebuilder, token, treebuilder->context.element_stack[ treebuilder->context.current_node].node); break; @@ -49,9 +47,10 @@ hubbub_error handle_in_column_group(hubbub_treebuilder *treebuilder, if (type == HTML) { /* Process as if "in body" */ - handle_in_body(treebuilder, token); + err = handle_in_body(treebuilder, token); } else if (type == COL) { - insert_element(treebuilder, &token->data.tag, false); + err = insert_element(treebuilder, &token->data.tag, + false); /** \todo ack sc flag */ } else { @@ -81,14 +80,14 @@ hubbub_error handle_in_column_group(hubbub_treebuilder *treebuilder, } if (handled || err == HUBBUB_REPROCESS) { + hubbub_error e; hubbub_ns ns; element_type otype; void *node; /* Pop the current node (which will be a colgroup) */ - if (!element_stack_pop(treebuilder, &ns, &otype, &node)) { - /** \todo errors */ - } + e = element_stack_pop(treebuilder, &ns, &otype, &node); + assert(e == HUBBUB_OK); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, diff --git a/src/treebuilder/in_foreign_content.c b/src/treebuilder/in_foreign_content.c index 1626e5b..a78e59f 100644 --- a/src/treebuilder/in_foreign_content.c +++ b/src/treebuilder/in_foreign_content.c @@ -325,9 +325,11 @@ static bool element_in_scope_in_non_html_ns(hubbub_treebuilder *treebuilder) /** * Process a token as if in the secondary insertion mode. */ -static void process_as_in_secondary(hubbub_treebuilder *treebuilder, +static hubbub_error process_as_in_secondary(hubbub_treebuilder *treebuilder, const hubbub_token *token) { + hubbub_error err; + /* Because we don't support calling insertion modes directly, * instead we set the current mode to the secondary mode, * call the token handler, and then reset the mode afterward @@ -335,7 +337,11 @@ static void process_as_in_secondary(hubbub_treebuilder *treebuilder, treebuilder->context.mode = treebuilder->context.second_mode; - hubbub_treebuilder_token_handler(token, treebuilder); + err = hubbub_treebuilder_token_handler(token, treebuilder); + if (err != HUBBUB_OK) { + treebuilder->context.mode = IN_FOREIGN_CONTENT; + return err; + } if (treebuilder->context.mode == treebuilder->context.second_mode) treebuilder->context.mode = IN_FOREIGN_CONTENT; @@ -344,6 +350,8 @@ static void process_as_in_secondary(hubbub_treebuilder *treebuilder, !element_in_scope_in_non_html_ns(treebuilder)) { treebuilder->context.mode = treebuilder->context.second_mode; } + + return HUBBUB_OK; } /** @@ -357,11 +365,13 @@ static void foreign_break_out(hubbub_treebuilder *treebuilder) while (stack[treebuilder->context.current_node].ns != HUBBUB_NS_HTML) { + hubbub_error e; hubbub_ns ns; element_type type; void *node; - element_stack_pop(treebuilder, &ns, &type, &node); + e = element_stack_pop(treebuilder, &ns, &type, &node); + assert(e == HUBBUB_OK); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, @@ -385,10 +395,10 @@ hubbub_error handle_in_foreign_content(hubbub_treebuilder *treebuilder, switch (token->type) { case HUBBUB_TOKEN_CHARACTER: - append_text(treebuilder, &token->data.character); + err = append_text(treebuilder, &token->data.character); break; case HUBBUB_TOKEN_COMMENT: - process_comment_append(treebuilder, token, + err = process_comment_append(treebuilder, token, treebuilder->context.element_stack[ treebuilder->context.current_node].node); break; @@ -416,7 +426,7 @@ hubbub_error handle_in_foreign_content(hubbub_treebuilder *treebuilder, (cur_node == FOREIGNOBJECT || cur_node == DESC || cur_node == TITLE))) { - process_as_in_secondary(treebuilder, token); + err = process_as_in_secondary(treebuilder, token); } else if (type == B || type == BIG || type == BLOCKQUOTE || type == BODY || type == BR || type == CENTER || type == CODE || type == DD || type == DIV || @@ -474,16 +484,16 @@ hubbub_error handle_in_foreign_content(hubbub_treebuilder *treebuilder, tag.ns = cur_node_ns; if (token->data.tag.self_closing) { - insert_element(treebuilder, &tag, false); + err = insert_element(treebuilder, &tag, false); /** \todo ack sc flag */ } else { - insert_element(treebuilder, &tag, true); + err = insert_element(treebuilder, &tag, true); } } } break; case HUBBUB_TOKEN_END_TAG: - process_as_in_secondary(treebuilder, token); + err = process_as_in_secondary(treebuilder, token); break; case HUBBUB_TOKEN_EOF: foreign_break_out(treebuilder); diff --git a/src/treebuilder/in_frameset.c b/src/treebuilder/in_frameset.c index 10d1a8f..928e4cc 100644 --- a/src/treebuilder/in_frameset.c +++ b/src/treebuilder/in_frameset.c @@ -28,13 +28,16 @@ hubbub_error handle_in_frameset(hubbub_treebuilder *treebuilder, switch (token->type) { case HUBBUB_TOKEN_CHARACTER: - if (process_characters_expect_whitespace(treebuilder, - token, true)) { - /** \todo parser error */ + err = process_characters_expect_whitespace(treebuilder, + token, true); + if (err == HUBBUB_REPROCESS) { + /** \todo parse error */ + /* Ignore the token */ + err = HUBBUB_OK; } break; case HUBBUB_TOKEN_COMMENT: - process_comment_append(treebuilder, token, + err = process_comment_append(treebuilder, token, treebuilder->context.element_stack[ treebuilder->context.current_node].node); break; @@ -47,11 +50,13 @@ hubbub_error handle_in_frameset(hubbub_treebuilder *treebuilder, &token->data.tag.name); if (type == HTML) { - handle_in_body(treebuilder, token); + err = handle_in_body(treebuilder, token); } else if (type == FRAMESET) { - insert_element(treebuilder, &token->data.tag, true); + err = insert_element(treebuilder, &token->data.tag, + true); } else if (type == FRAME) { - insert_element(treebuilder, &token->data.tag, false); + err = insert_element(treebuilder, &token->data.tag, + false); /** \todo ack sc flag */ } else if (type == NOFRAMES) { err = handle_in_head(treebuilder, token); @@ -66,6 +71,7 @@ hubbub_error handle_in_frameset(hubbub_treebuilder *treebuilder, &token->data.tag.name); if (type == FRAMESET) { + hubbub_error e; hubbub_ns ns; void *node; @@ -75,10 +81,8 @@ hubbub_error handle_in_frameset(hubbub_treebuilder *treebuilder, break; } - if (!element_stack_pop(treebuilder, &ns, &type, - &node)) { - /** \todo errors */ - } + e = element_stack_pop(treebuilder, &ns, &type, &node); + assert(e == HUBBUB_OK); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, diff --git a/src/treebuilder/in_head.c b/src/treebuilder/in_head.c index 32d2ce0..8eb95d1 100644 --- a/src/treebuilder/in_head.c +++ b/src/treebuilder/in_head.c @@ -23,7 +23,7 @@ /** * Process a meta tag as if "in head". * - * \param treebuilder The treebuilder instance + * \param treebuilder The treebuilder instance * \param token The token to process */ static hubbub_error process_meta_in_head(hubbub_treebuilder *treebuilder, @@ -33,13 +33,16 @@ static hubbub_error process_meta_in_head(hubbub_treebuilder *treebuilder, uint16_t charset_enc = 0; uint16_t content_type_enc = 0; size_t i; + hubbub_error err = HUBBUB_OK; - insert_element(treebuilder, &token->data.tag, false); + err = insert_element(treebuilder, &token->data.tag, false); + if (err != HUBBUB_OK) + return err; /** \todo ack sc flag */ if (treebuilder->tree_handler->encoding_change == NULL) - return HUBBUB_OK; + return err; /* Grab UTF-16 MIBenums */ if (utf16 == 0) { @@ -89,14 +92,11 @@ static hubbub_error process_meta_in_head(hubbub_treebuilder *treebuilder, name = parserutils_charset_mibenum_to_name(charset_enc); - /* 1 indicates the encoding should actually change */ - if (treebuilder->tree_handler->encoding_change( - treebuilder->tree_handler->ctx, name) == 1) { - return HUBBUB_ENCODINGCHANGE; - } + err = treebuilder->tree_handler->encoding_change( + treebuilder->tree_handler->ctx, name); } - return HUBBUB_OK; + return err; } /** @@ -118,7 +118,7 @@ hubbub_error handle_in_head(hubbub_treebuilder *treebuilder, token, true); break; case HUBBUB_TOKEN_COMMENT: - process_comment_append(treebuilder, token, + err = process_comment_append(treebuilder, token, treebuilder->context.element_stack[ treebuilder->context.current_node].node); break; @@ -132,30 +132,35 @@ hubbub_error handle_in_head(hubbub_treebuilder *treebuilder, if (type == HTML) { /* Process as if "in body" */ - handle_in_body(treebuilder, token); + err = handle_in_body(treebuilder, token); } else if (type == BASE || type == COMMAND || type == LINK) { - insert_element(treebuilder, &token->data.tag, false); + err = insert_element(treebuilder, &token->data.tag, + false); /** \todo ack sc flag */ } else if (type == META) { err = process_meta_in_head(treebuilder, token); } else if (type == TITLE) { - parse_generic_rcdata(treebuilder, token, true); + err = parse_generic_rcdata(treebuilder, token, true); } else if (type == NOFRAMES || type == STYLE) { - parse_generic_rcdata(treebuilder, token, false); + err = parse_generic_rcdata(treebuilder, token, false); } else if (type == NOSCRIPT) { if (treebuilder->context.enable_scripting) { - parse_generic_rcdata(treebuilder, token, false); + err = parse_generic_rcdata(treebuilder, token, + false); } else { - insert_element(treebuilder, &token->data.tag, - true); + err = insert_element(treebuilder, + &token->data.tag, true); + if (err != HUBBUB_OK) + return err; + treebuilder->context.mode = IN_HEAD_NOSCRIPT; } } else if (type == SCRIPT) { /** \todo need to ensure that the client callback * sets the parser-inserted/already-executed script * flags. */ - parse_generic_rcdata(treebuilder, token, false); + err = parse_generic_rcdata(treebuilder, token, false); } else if (type == HEAD) { /** \todo parse error */ } else { @@ -181,13 +186,13 @@ hubbub_error handle_in_head(hubbub_treebuilder *treebuilder, } if (handled || err == HUBBUB_REPROCESS) { + hubbub_error e; hubbub_ns ns; element_type otype; void *node; - if (!element_stack_pop(treebuilder, &ns, &otype, &node)) { - /** \todo errors */ - } + e = element_stack_pop(treebuilder, &ns, &otype, &node); + assert(e == HUBBUB_OK); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, diff --git a/src/treebuilder/in_head_noscript.c b/src/treebuilder/in_head_noscript.c index 6d30765..cf5061c 100644 --- a/src/treebuilder/in_head_noscript.c +++ b/src/treebuilder/in_head_noscript.c @@ -45,7 +45,7 @@ hubbub_error handle_in_head_noscript(hubbub_treebuilder *treebuilder, if (type == HTML) { /* Process as "in body" */ - handle_in_body(treebuilder, token); + err = handle_in_body(treebuilder, token); } else if (type == NOSCRIPT) { handled = true; } else if (type == LINK || type == META || type == NOFRAMES || @@ -82,13 +82,13 @@ hubbub_error handle_in_head_noscript(hubbub_treebuilder *treebuilder, } if (handled || err == HUBBUB_REPROCESS) { + hubbub_error e; hubbub_ns ns; element_type otype; void *node; - if (!element_stack_pop(treebuilder, &ns, &otype, &node)) { - /** \todo errors */ - } + e = element_stack_pop(treebuilder, &ns, &otype, &node); + assert(e == HUBBUB_OK); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, diff --git a/src/treebuilder/in_row.c b/src/treebuilder/in_row.c index 79d6f6c..0c23bab 100644 --- a/src/treebuilder/in_row.c +++ b/src/treebuilder/in_row.c @@ -24,13 +24,13 @@ static void table_clear_stack(hubbub_treebuilder *treebuilder) element_type cur_node = current_node(treebuilder); while (cur_node != TR && cur_node != HTML) { + hubbub_error e; hubbub_ns ns; element_type type; void *node; - if (!element_stack_pop(treebuilder, &ns, &type, &node)) { - /** \todo errors */ - } + e = element_stack_pop(treebuilder, &ns, &type, &node); + assert(e == HUBBUB_OK); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, @@ -51,6 +51,7 @@ static void table_clear_stack(hubbub_treebuilder *treebuilder) */ static hubbub_error act_as_if_end_tag_tr(hubbub_treebuilder *treebuilder) { + hubbub_error e; hubbub_ns ns; element_type otype; void *node; @@ -58,9 +59,9 @@ static hubbub_error act_as_if_end_tag_tr(hubbub_treebuilder *treebuilder) /** \todo fragment case */ table_clear_stack(treebuilder); - if (!element_stack_pop(treebuilder, &ns, &otype, &node)) { - /** \todo errors */ - } + + e = element_stack_pop(treebuilder, &ns, &otype, &node); + assert(e == HUBBUB_OK); treebuilder->tree_handler->unref_node(treebuilder->tree_handler->ctx, node); @@ -92,7 +93,11 @@ hubbub_error handle_in_row(hubbub_treebuilder *treebuilder, if (type == TH || type == TD) { table_clear_stack(treebuilder); - insert_element(treebuilder, &token->data.tag, true); + err = insert_element(treebuilder, &token->data.tag, + true); + if (err != HUBBUB_OK) + return err; + treebuilder->context.mode = IN_CELL; /* ref node for formatting list */ @@ -101,11 +106,30 @@ hubbub_error handle_in_row(hubbub_treebuilder *treebuilder, treebuilder->context.element_stack[ treebuilder->context.current_node].node); - formatting_list_append(treebuilder, + err = formatting_list_append(treebuilder, token->data.tag.ns, type, treebuilder->context.element_stack[ treebuilder->context.current_node].node, treebuilder->context.current_node); + if (err != HUBBUB_OK) { + hubbub_error e; + hubbub_ns ns; + element_type type; + void *node; + + /* Revert changes */ + + e = remove_node_from_dom(treebuilder, + treebuilder->context.element_stack[ + treebuilder->context.current_node].node); + assert(e == HUBBUB_OK); + + e = element_stack_pop(treebuilder, &ns, &type, + &node); + assert(e == HUBBUB_OK); + + return err; + } } else if (type == CAPTION || type == COL || type == COLGROUP || type == TBODY || type == TFOOT || type == THEAD || type == TR) { @@ -121,7 +145,10 @@ hubbub_error handle_in_row(hubbub_treebuilder *treebuilder, &token->data.tag.name); if (type == TR) { - (void)act_as_if_end_tag_tr(treebuilder); + /* We're done with this token, but act_as_if_end_tag_tr + * will return HUBBUB_REPROCESS. Therefore, ignore the + * return value. */ + (void) act_as_if_end_tag_tr(treebuilder); } else if (type == TABLE) { err = act_as_if_end_tag_tr(treebuilder); } else if (type == BODY || type == CAPTION || type == COL || diff --git a/src/treebuilder/in_select.c b/src/treebuilder/in_select.c index 06fe287..cfddf4a 100644 --- a/src/treebuilder/in_select.c +++ b/src/treebuilder/in_select.c @@ -32,10 +32,10 @@ hubbub_error handle_in_select(hubbub_treebuilder *treebuilder, switch (token->type) { case HUBBUB_TOKEN_CHARACTER: - append_text(treebuilder, &token->data.character); + err = append_text(treebuilder, &token->data.character); break; case HUBBUB_TOKEN_COMMENT: - process_comment_append(treebuilder, token, + err = process_comment_append(treebuilder, token, treebuilder->context.element_stack[ treebuilder->context.current_node].node); break; @@ -49,26 +49,27 @@ hubbub_error handle_in_select(hubbub_treebuilder *treebuilder, if (type == HTML) { /* Process as if "in body" */ - handle_in_body(treebuilder, token); + err = handle_in_body(treebuilder, token); } else if (type == OPTION) { if (current_node(treebuilder) == OPTION) { - if (!element_stack_pop(treebuilder, &ns, &otype, - &node)) { - /** \todo errors */ - } + hubbub_error e; + e = element_stack_pop(treebuilder, &ns, &otype, + &node); + assert(e == HUBBUB_OK); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, node); } - insert_element(treebuilder, &token->data.tag, true); + err = insert_element(treebuilder, &token->data.tag, + true); } else if (type == OPTGROUP) { if (current_node(treebuilder) == OPTION) { - if (!element_stack_pop(treebuilder, &ns, &otype, - &node)) { - /** \todo errors */ - } + hubbub_error e; + e = element_stack_pop(treebuilder, &ns, &otype, + &node); + assert(e == HUBBUB_OK); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, @@ -76,31 +77,36 @@ hubbub_error handle_in_select(hubbub_treebuilder *treebuilder, } if (current_node(treebuilder) == OPTGROUP) { - if (!element_stack_pop(treebuilder, &ns, &otype, - &node)) { - /** \todo errors */ - } + hubbub_error e; + e = element_stack_pop(treebuilder, &ns, &otype, + &node); + assert(e == HUBBUB_OK); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, node); } - insert_element(treebuilder, &token->data.tag, true); + err = insert_element(treebuilder, &token->data.tag, + true); } else if (type == SELECT || type == INPUT || type == TEXTAREA) { if (element_in_scope(treebuilder, SELECT, true)) { - element_stack_pop_until(treebuilder, SELECT); + hubbub_error e; + e = element_stack_pop_until(treebuilder, + SELECT); + assert(e == HUBBUB_OK); reset_insertion_mode(treebuilder); } else { /* fragment case */ /** \todo parse error */ } - if (type != SELECT) err = HUBBUB_REPROCESS; + if (type != SELECT) + err = HUBBUB_REPROCESS; } else if (type == SCRIPT) { - handle_in_head(treebuilder, token); + err = handle_in_head(treebuilder, token); } else { /** \todo parse error */ } @@ -114,10 +120,10 @@ hubbub_error handle_in_select(hubbub_treebuilder *treebuilder, if (type == OPTGROUP) { if (current_node(treebuilder) == OPTION && prev_node(treebuilder) == OPTGROUP) { - if (!element_stack_pop(treebuilder, &ns, &otype, - &node)) { - /** \todo errors */ - } + hubbub_error e; + e = element_stack_pop(treebuilder, &ns, &otype, + &node); + assert(e == HUBBUB_OK); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, @@ -125,10 +131,10 @@ hubbub_error handle_in_select(hubbub_treebuilder *treebuilder, } if (current_node(treebuilder) == OPTGROUP) { - if (!element_stack_pop(treebuilder, &ns, &otype, - &node)) { - /** \todo errors */ - } + hubbub_error e; + e = element_stack_pop(treebuilder, &ns, &otype, + &node); + assert(e == HUBBUB_OK); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, @@ -138,10 +144,10 @@ hubbub_error handle_in_select(hubbub_treebuilder *treebuilder, } } else if (type == OPTION) { if (current_node(treebuilder) == OPTION) { - if (!element_stack_pop(treebuilder, &ns, &otype, - &node)) { - /** \todo errors */ - } + hubbub_error e; + e = element_stack_pop(treebuilder, &ns, &otype, + &node); + assert(e == HUBBUB_OK); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, @@ -151,7 +157,10 @@ hubbub_error handle_in_select(hubbub_treebuilder *treebuilder, } } else if (type == SELECT) { if (element_in_scope(treebuilder, SELECT, true)) { - element_stack_pop_until(treebuilder, SELECT); + hubbub_error e; + e = element_stack_pop_until(treebuilder, + SELECT); + assert(e == HUBBUB_OK); reset_insertion_mode(treebuilder); } else { /* fragment case */ diff --git a/src/treebuilder/in_select_in_table.c b/src/treebuilder/in_select_in_table.c index 5ddce11..b22fbc1 100644 --- a/src/treebuilder/in_select_in_table.c +++ b/src/treebuilder/in_select_in_table.c @@ -43,9 +43,13 @@ hubbub_error handle_in_select_in_table(hubbub_treebuilder *treebuilder, element_in_scope(treebuilder, type, true)) || token->type == HUBBUB_TOKEN_START_TAG) { + hubbub_error e; + /** \todo fragment case */ - element_stack_pop_until(treebuilder, SELECT); + e = element_stack_pop_until(treebuilder, + SELECT); + assert(e == HUBBUB_OK); reset_insertion_mode(treebuilder); err = HUBBUB_REPROCESS; } diff --git a/src/treebuilder/in_table.c b/src/treebuilder/in_table.c index ac5e6c5..f5ffdb2 100644 --- a/src/treebuilder/in_table.c +++ b/src/treebuilder/in_table.c @@ -27,7 +27,10 @@ static inline void clear_stack_table_context(hubbub_treebuilder *treebuilder) void *node; while (type != TABLE && type != HTML) { - element_stack_pop(treebuilder, &ns, &type, &node); + hubbub_error e; + + e = element_stack_pop(treebuilder, &ns, &type, &node); + assert(e == HUBBUB_OK); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, @@ -35,18 +38,19 @@ static inline void clear_stack_table_context(hubbub_treebuilder *treebuilder) type = current_node(treebuilder); } - - return; } /** * Process an input start tag in the "in table" insertion mode. */ -static inline bool process_input_in_table(hubbub_treebuilder *treebuilder, +static inline hubbub_error process_input_in_table( + hubbub_treebuilder *treebuilder, const hubbub_token *token) { + hubbub_error err = HUBBUB_REPROCESS; size_t i; + for (i = 0; i < token->data.tag.n_attributes; i++) { hubbub_attribute *attr = &token->data.tag.attributes[i]; @@ -56,12 +60,10 @@ static inline bool process_input_in_table(hubbub_treebuilder *treebuilder, } /** \todo parse error */ - insert_element(treebuilder, &token->data.tag, true); - - return true; + err = insert_element(treebuilder, &token->data.tag, true); } - return false; + return err; } @@ -85,12 +87,13 @@ hubbub_error handle_in_table(hubbub_treebuilder *treebuilder, ].tainted) { handled = false; } else { - handled = !process_characters_expect_whitespace( + err = process_characters_expect_whitespace( treebuilder, token, true); + handled = (err == HUBBUB_OK); } break; case HUBBUB_TOKEN_COMMENT: - process_comment_append(treebuilder, token, + err = process_comment_append(treebuilder, token, treebuilder->context.element_stack[ treebuilder->context.current_node].node); break; @@ -107,19 +110,50 @@ hubbub_error handle_in_table(hubbub_treebuilder *treebuilder, if (type == CAPTION) { clear_stack_table_context(treebuilder); + treebuilder->tree_handler->ref_node( treebuilder->tree_handler->ctx, treebuilder->context.element_stack[ treebuilder->context.current_node].node); - formatting_list_append(treebuilder, + + err = formatting_list_append(treebuilder, token->data.tag.ns, type, treebuilder->context.element_stack[ treebuilder->context.current_node].node, treebuilder->context.current_node); + if (err != HUBBUB_OK) { + treebuilder->tree_handler->unref_node( + treebuilder->tree_handler->ctx, + treebuilder->context.element_stack[ + treebuilder->context.current_node].node); + + return err; + } + + err = insert_element(treebuilder, &token->data.tag, + true); + if (err != HUBBUB_OK) { + hubbub_error e; + hubbub_ns ns; + element_type type; + void *node; + uint32_t index; + + e = formatting_list_remove(treebuilder, + treebuilder->context.formatting_list_end, + &ns, &type, &node, &index); + assert(e == HUBBUB_OK); + + treebuilder->tree_handler->unref_node( + treebuilder->tree_handler->ctx, + node); + + return err; + } - insert_element(treebuilder, &token->data.tag, true); treebuilder->context.mode = IN_CAPTION; } else if (type == COLGROUP || type == COL) { + hubbub_error e; hubbub_tag tag = token->data.tag; if (type == COL) { @@ -133,10 +167,15 @@ hubbub_error handle_in_table(hubbub_treebuilder *treebuilder, } clear_stack_table_context(treebuilder); - insert_element(treebuilder, &tag, true); + + e = insert_element(treebuilder, &tag, true); + if (e != HUBBUB_OK) + return e; + treebuilder->context.mode = IN_COLUMN_GROUP; } else if (type == TBODY || type == TFOOT || type == THEAD || type == TD || type == TH || type == TR) { + hubbub_error e; hubbub_tag tag = token->data.tag; if (type == TD || type == TH || type == TR) { @@ -150,20 +189,28 @@ hubbub_error handle_in_table(hubbub_treebuilder *treebuilder, } clear_stack_table_context(treebuilder); - insert_element(treebuilder, &tag, true); + + e = insert_element(treebuilder, &tag, true); + if (e != HUBBUB_OK) + return e; + treebuilder->context.mode = IN_TABLE_BODY; } else if (type == TABLE) { + hubbub_error e; /** \todo parse error */ /* This should match "" handling */ - element_stack_pop_until(treebuilder, TABLE); + e = element_stack_pop_until(treebuilder, TABLE); + assert(e == HUBBUB_OK); + reset_insertion_mode(treebuilder); err = HUBBUB_REPROCESS; } else if (!tainted && (type == STYLE || type == SCRIPT)) { err = handle_in_head(treebuilder, token); } else if (!tainted && type == INPUT) { - handled = process_input_in_table(treebuilder, token); + err = process_input_in_table(treebuilder, token); + handled = (err == HUBBUB_OK); } else { handled = false; } @@ -175,9 +222,12 @@ hubbub_error handle_in_table(hubbub_treebuilder *treebuilder, &token->data.tag.name); if (type == TABLE) { + hubbub_error e; /** \todo fragment case */ - element_stack_pop_until(treebuilder, TABLE); + e = element_stack_pop_until(treebuilder, TABLE); + assert(e == HUBBUB_OK); + reset_insertion_mode(treebuilder); } else if (type == BODY || type == CAPTION || type == COL || type == COLGROUP || type == HTML || @@ -197,7 +247,7 @@ hubbub_error handle_in_table(hubbub_treebuilder *treebuilder, treebuilder->context.in_table_foster = true; /** \todo parse error */ - handle_in_body(treebuilder, token); + err = handle_in_body(treebuilder, token); treebuilder->context.in_table_foster = false; } diff --git a/src/treebuilder/in_table_body.c b/src/treebuilder/in_table_body.c index 985a893..b99dd08 100644 --- a/src/treebuilder/in_table_body.c +++ b/src/treebuilder/in_table_body.c @@ -25,13 +25,13 @@ static void table_clear_stack(hubbub_treebuilder *treebuilder) while (cur_node != TBODY && cur_node != TFOOT && cur_node != THEAD && cur_node != HTML) { + hubbub_error e; hubbub_ns ns; element_type type; void *node; - if (!element_stack_pop(treebuilder, &ns, &type, &node)) { - /** \todo errors */ - } + e = element_stack_pop(treebuilder, &ns, &type, &node); + assert(e == HUBBUB_OK); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, @@ -55,6 +55,7 @@ static hubbub_error table_sub_start_or_table_end(hubbub_treebuilder *treebuilder if (element_in_scope(treebuilder, TBODY, true) || element_in_scope(treebuilder, THEAD, true) || element_in_scope(treebuilder, TFOOT, true)) { + hubbub_error e; hubbub_ns ns; element_type otype; void *node; @@ -64,9 +65,8 @@ static hubbub_error table_sub_start_or_table_end(hubbub_treebuilder *treebuilder /* "Act as if an end tag with the same name as the current * node had been seen" -- this behaviour should be identical * to handling for (tbody/tfoot/thead) end tags in this mode */ - if (!element_stack_pop(treebuilder, &ns, &otype, &node)) { - /** \todo errors */ - } + e = element_stack_pop(treebuilder, &ns, &otype, &node); + assert(e == HUBBUB_OK); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, @@ -103,8 +103,11 @@ hubbub_error handle_in_table_body(hubbub_treebuilder *treebuilder, if (type == TR) { table_clear_stack(treebuilder); - insert_element(treebuilder, &token->data.tag, true); - treebuilder->context.mode = IN_ROW; + + err = insert_element(treebuilder, &token->data.tag, + true); + if (err == HUBBUB_OK) + treebuilder->context.mode = IN_ROW; } else if (type == TH || type == TD) { hubbub_tag tag; @@ -119,10 +122,13 @@ hubbub_error handle_in_table_body(hubbub_treebuilder *treebuilder, tag.attributes = NULL; table_clear_stack(treebuilder); - insert_element(treebuilder, &tag, true); - treebuilder->context.mode = IN_ROW; - err = HUBBUB_REPROCESS; + err = insert_element(treebuilder, &tag, true); + if (err == HUBBUB_OK) { + treebuilder->context.mode = IN_ROW; + + err = HUBBUB_REPROCESS; + } } else if (type == CAPTION || type == COL || type == COLGROUP || type == TBODY || type == TFOOT || type == THEAD) { @@ -142,15 +148,16 @@ hubbub_error handle_in_table_body(hubbub_treebuilder *treebuilder, /** \todo parse error */ /* Ignore the token */ } else { + hubbub_error e; hubbub_ns ns; element_type otype; void *node; table_clear_stack(treebuilder); - if (!element_stack_pop(treebuilder, &ns, - &otype, &node)) { - /** \todo errors */ - } + + e = element_stack_pop(treebuilder, &ns, + &otype, &node); + assert(e == HUBBUB_OK); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, diff --git a/src/treebuilder/initial.c b/src/treebuilder/initial.c index 6ead570..5f0796c 100644 --- a/src/treebuilder/initial.c +++ b/src/treebuilder/initial.c @@ -228,53 +228,50 @@ hubbub_error handle_initial(hubbub_treebuilder *treebuilder, switch (token->type) { case HUBBUB_TOKEN_CHARACTER: - if (process_characters_expect_whitespace(treebuilder, token, - false)) { + err = process_characters_expect_whitespace(treebuilder, token, + false); + if (err == HUBBUB_REPROCESS) { /** \todo parse error */ treebuilder->tree_handler->set_quirks_mode( treebuilder->tree_handler->ctx, HUBBUB_QUIRKS_MODE_FULL); treebuilder->context.mode = BEFORE_HTML; - err = HUBBUB_REPROCESS; } break; case HUBBUB_TOKEN_COMMENT: - process_comment_append(treebuilder, token, + err = process_comment_append(treebuilder, token, treebuilder->context.document); break; case HUBBUB_TOKEN_DOCTYPE: { - int success; void *doctype, *appended; const hubbub_doctype *cdoc; /** \todo parse error */ - success = treebuilder->tree_handler->create_doctype( + err = treebuilder->tree_handler->create_doctype( treebuilder->tree_handler->ctx, &token->data.doctype, &doctype); - if (success != 0) { - /** \todo errors */ - } + if (err != HUBBUB_OK) + return err; /* Append to Document node */ - success = treebuilder->tree_handler->append_child( + err = treebuilder->tree_handler->append_child( treebuilder->tree_handler->ctx, treebuilder->context.document, doctype, &appended); - if (success != 0) { - /** \todo errors */ - treebuilder->tree_handler->unref_node( - treebuilder->tree_handler->ctx, - doctype); - } treebuilder->tree_handler->unref_node( - treebuilder->tree_handler->ctx, appended); + treebuilder->tree_handler->ctx, + doctype); + + if (err != HUBBUB_OK) + return err; + treebuilder->tree_handler->unref_node( - treebuilder->tree_handler->ctx, doctype); + treebuilder->tree_handler->ctx, appended); cdoc = &token->data.doctype; diff --git a/src/treebuilder/internal.h b/src/treebuilder/internal.h index 2b20fbf..311996c 100644 --- a/src/treebuilder/internal.h +++ b/src/treebuilder/internal.h @@ -73,6 +73,8 @@ typedef struct formatting_list_entry typedef struct hubbub_treebuilder_context { insertion_mode mode; /**< The current insertion mode */ + uint32_t mode_state; /**< Insertion mode specific state */ + insertion_mode second_mode; /**< The secondary insertion mode */ #define ELEMENT_STACK_CHUNK 128 @@ -134,22 +136,25 @@ hubbub_error hubbub_treebuilder_token_handler( hubbub_error process_characters_expect_whitespace( hubbub_treebuilder *treebuilder, const hubbub_token *token, bool insert_into_current_node); -void process_comment_append(hubbub_treebuilder *treebuilder, +hubbub_error process_comment_append(hubbub_treebuilder *treebuilder, const hubbub_token *token, void *parent); -void parse_generic_rcdata(hubbub_treebuilder *treebuilder, +hubbub_error parse_generic_rcdata(hubbub_treebuilder *treebuilder, const hubbub_token *token, bool rcdata); uint32_t element_in_scope(hubbub_treebuilder *treebuilder, element_type type, bool in_table); -void reconstruct_active_formatting_list(hubbub_treebuilder *treebuilder); +hubbub_error reconstruct_active_formatting_list( + hubbub_treebuilder *treebuilder); void clear_active_formatting_list_to_marker( hubbub_treebuilder *treebuilder); -void insert_element(hubbub_treebuilder *treebuilder, +hubbub_error remove_node_from_dom(hubbub_treebuilder *treebuilder, + void *node); +hubbub_error insert_element(hubbub_treebuilder *treebuilder, const hubbub_tag *tag_name, bool push); void close_implied_end_tags(hubbub_treebuilder *treebuilder, element_type except); void reset_insertion_mode(hubbub_treebuilder *treebuilder); -void append_text(hubbub_treebuilder *treebuilder, +hubbub_error append_text(hubbub_treebuilder *treebuilder, const hubbub_string *string); element_type element_type_from_name(hubbub_treebuilder *treebuilder, @@ -160,30 +165,31 @@ bool is_scoping_element(element_type type); bool is_formatting_element(element_type type); bool is_phrasing_element(element_type type); -bool element_stack_push(hubbub_treebuilder *treebuilder, +hubbub_error element_stack_push(hubbub_treebuilder *treebuilder, hubbub_ns ns, element_type type, void *node); -bool element_stack_pop(hubbub_treebuilder *treebuilder, +hubbub_error element_stack_pop(hubbub_treebuilder *treebuilder, hubbub_ns *ns, element_type *type, void **node); -bool element_stack_pop_until(hubbub_treebuilder *treebuilder, +hubbub_error element_stack_pop_until(hubbub_treebuilder *treebuilder, element_type type); -bool element_stack_remove(hubbub_treebuilder *treebuilder, uint32_t index, - hubbub_ns *ns, element_type *type, void **removed); +hubbub_error element_stack_remove(hubbub_treebuilder *treebuilder, + uint32_t index, hubbub_ns *ns, element_type *type, + void **removed); uint32_t current_table(hubbub_treebuilder *treebuilder); element_type current_node(hubbub_treebuilder *treebuilder); element_type prev_node(hubbub_treebuilder *treebuilder); -bool formatting_list_append(hubbub_treebuilder *treebuilder, +hubbub_error formatting_list_append(hubbub_treebuilder *treebuilder, hubbub_ns ns, element_type type, void *node, uint32_t stack_index); -bool formatting_list_insert(hubbub_treebuilder *treebuilder, +hubbub_error formatting_list_insert(hubbub_treebuilder *treebuilder, formatting_list_entry *prev, formatting_list_entry *next, hubbub_ns ns, element_type type, void *node, uint32_t stack_index); -bool formatting_list_remove(hubbub_treebuilder *treebuilder, +hubbub_error formatting_list_remove(hubbub_treebuilder *treebuilder, formatting_list_entry *entry, hubbub_ns *ns, element_type *type, void **node, uint32_t *stack_index); -bool formatting_list_replace(hubbub_treebuilder *treebuilder, +hubbub_error formatting_list_replace(hubbub_treebuilder *treebuilder, formatting_list_entry *entry, hubbub_ns ns, element_type type, void *node, uint32_t stack_index, @@ -200,7 +206,8 @@ void adjust_foreign_attributes(hubbub_treebuilder *treebuilder, hubbub_tag *tag); /* in_body.c */ -void *aa_insert_into_foster_parent(hubbub_treebuilder *treebuilder, void *node); +hubbub_error aa_insert_into_foster_parent(hubbub_treebuilder *treebuilder, + void *node, void **inserted); #ifndef NDEBUG #include diff --git a/src/treebuilder/treebuilder.c b/src/treebuilder/treebuilder.c index ec5f825..33f8eef 100644 --- a/src/treebuilder/treebuilder.c +++ b/src/treebuilder/treebuilder.c @@ -374,9 +374,10 @@ hubbub_error hubbub_treebuilder_token_handler(const hubbub_token *token, * \param token The character token * \param insert_into_current_node Whether to insert whitespace into * current node - * \return True if the token needs reprocessing - * (token data updated to skip any leading whitespace), - * false if it contained only whitespace + * \return HUBBUB_REPROCESS if the token needs reprocessing + * (token data updated to skip any leading whitespace), + * HUBBUB_OK if it contained only whitespace, + * appropriate error otherwise */ hubbub_error process_characters_expect_whitespace( hubbub_treebuilder *treebuilder, @@ -393,12 +394,15 @@ hubbub_error process_characters_expect_whitespace( } if (c > 0 && insert_into_current_node) { + hubbub_error error; hubbub_string temp; temp.ptr = data; temp.len = c; - append_text(treebuilder, &temp); + error = append_text(treebuilder, &temp); + if (error != HUBBUB_OK) + return error; } /* Non-whitespace characters in token, so reprocess */ @@ -419,39 +423,41 @@ hubbub_error process_characters_expect_whitespace( * \param treebuilder The treebuilder instance * \param token The comment token * \param parent The node to append to + * \return HUBBUB_OK on success, appropriate error otherwise */ -void process_comment_append(hubbub_treebuilder *treebuilder, +hubbub_error process_comment_append(hubbub_treebuilder *treebuilder, const hubbub_token *token, void *parent) { + hubbub_error error = HUBBUB_OK; element_type type = current_node(treebuilder); - int success; void *comment, *appended; - success = treebuilder->tree_handler->create_comment( + error = treebuilder->tree_handler->create_comment( treebuilder->tree_handler->ctx, &token->data.comment, &comment); - if (success != 0) { - /** \todo errors */ - } + if (error != HUBBUB_OK) + return error; if (treebuilder->context.in_table_foster && (type == TABLE || type == TBODY || type == TFOOT || type == THEAD || type == TR)) { - appended = aa_insert_into_foster_parent(treebuilder, comment); + error = aa_insert_into_foster_parent(treebuilder, comment, + &appended); } else { - success = treebuilder->tree_handler->append_child( + error = treebuilder->tree_handler->append_child( treebuilder->tree_handler->ctx, parent, comment, &appended); - if (success != 0) { - /** \todo errors */ - } + } + if (error == HUBBUB_OK) { treebuilder->tree_handler->unref_node( - treebuilder->tree_handler->ctx, comment); + treebuilder->tree_handler->ctx, appended); } treebuilder->tree_handler->unref_node( - treebuilder->tree_handler->ctx, appended); + treebuilder->tree_handler->ctx, comment); + + return error; } /** @@ -460,26 +466,34 @@ void process_comment_append(hubbub_treebuilder *treebuilder, * \param treebuilder The treebuilder instance * \param token The current token * \param rcdata True for RCDATA, false for CDATA + * \return HUBBUB_OK on success, appropriate error otherwise */ -void parse_generic_rcdata(hubbub_treebuilder *treebuilder, +hubbub_error parse_generic_rcdata(hubbub_treebuilder *treebuilder, const hubbub_token *token, bool rcdata) { + hubbub_error error; element_type type; hubbub_tokeniser_optparams params; type = element_type_from_name(treebuilder, &token->data.tag.name); - insert_element(treebuilder, &token->data.tag, true); + error = insert_element(treebuilder, &token->data.tag, true); + if (error != HUBBUB_OK) + return error; params.content_model.model = rcdata ? HUBBUB_CONTENT_MODEL_RCDATA : HUBBUB_CONTENT_MODEL_CDATA; - hubbub_tokeniser_setopt(treebuilder->tokeniser, + error = hubbub_tokeniser_setopt(treebuilder->tokeniser, HUBBUB_TOKENISER_CONTENT_MODEL, ¶ms); + /* There is no way that setopt can fail. Ensure this. */ + assert(error == HUBBUB_OK); treebuilder->context.collect.mode = treebuilder->context.mode; treebuilder->context.collect.type = type; treebuilder->context.mode = GENERIC_RCDATA; + + return HUBBUB_OK; } /** @@ -496,7 +510,7 @@ uint32_t element_in_scope(hubbub_treebuilder *treebuilder, uint32_t node; if (treebuilder->context.element_stack == NULL) - return false; + return 0; assert((signed) treebuilder->context.current_node >= 0); @@ -531,19 +545,22 @@ uint32_t element_in_scope(hubbub_treebuilder *treebuilder, * Reconstruct the list of active formatting elements * * \param treebuilder Treebuilder instance containing list + * \return HUBBUB_OK on success, appropriate error otherwise. */ -void reconstruct_active_formatting_list(hubbub_treebuilder *treebuilder) +hubbub_error reconstruct_active_formatting_list(hubbub_treebuilder *treebuilder) { - formatting_list_entry *entry; + hubbub_error error = HUBBUB_OK; + formatting_list_entry *entry, *initial_entry; + uint32_t sp = treebuilder->context.current_node; if (treebuilder->context.formatting_list == NULL) - return; + return HUBBUB_OK; entry = treebuilder->context.formatting_list_end; /* Assumption: HTML and TABLE elements are not inserted into the list */ if (is_scoping_element(entry->details.type) || entry->stack_index != 0) - return; + return HUBBUB_OK; while (entry->prev != NULL) { entry = entry->prev; @@ -555,26 +572,23 @@ void reconstruct_active_formatting_list(hubbub_treebuilder *treebuilder) } } + /* Save initial entry for later */ + initial_entry = entry; + + /* Process formatting list entries, cloning nodes and + * inserting them into the DOM and element stack */ while (entry != NULL) { - int success; void *clone, *appended; - hubbub_ns prev_ns; - element_type prev_type; - void *prev_node; - uint32_t prev_stack_index; bool foster; - element_type type = current_node(treebuilder); - success = treebuilder->tree_handler->clone_node( + error = treebuilder->tree_handler->clone_node( treebuilder->tree_handler->ctx, entry->details.node, false, &clone); - if (success != 0) { - /** \todo handle errors */ - return; - } + if (error != HUBBUB_OK) + goto cleanup; foster = treebuilder->context.in_table_foster && (type == TABLE || type == TBODY || @@ -582,68 +596,130 @@ void reconstruct_active_formatting_list(hubbub_treebuilder *treebuilder) type == TR); if (foster) { - appended = aa_insert_into_foster_parent(treebuilder, - clone); - treebuilder->tree_handler->ref_node( - treebuilder->tree_handler->ctx, - appended); + error = aa_insert_into_foster_parent(treebuilder, + clone, &appended); } else { - success = treebuilder->tree_handler->append_child( + error = treebuilder->tree_handler->append_child( treebuilder->tree_handler->ctx, treebuilder->context.element_stack[ treebuilder->context.current_node].node, clone, &appended); + } - if (success != 0) { - /** \todo handle errors */ - treebuilder->tree_handler->unref_node( - treebuilder->tree_handler->ctx, - clone); - return; - } + /* No longer interested in clone */ + treebuilder->tree_handler->unref_node( + treebuilder->tree_handler->ctx, + clone); - if (appended != clone) { - /* Transfer the reference we hold on clone to - * appended. We're no longer interested in - * clone.*/ - treebuilder->tree_handler->unref_node( - treebuilder->tree_handler->ctx, - clone); - treebuilder->tree_handler->ref_node( - treebuilder->tree_handler->ctx, - appended); - } - } + if (error != HUBBUB_OK) + goto cleanup; + + error = element_stack_push(treebuilder, entry->details.ns, + entry->details.type, appended); + if (error != HUBBUB_OK) { + hubbub_error err; - /* At this point, appended's reference count will be 2 */ + err = remove_node_from_dom(treebuilder, appended); + assert(err == HUBBUB_OK); - if (!element_stack_push(treebuilder, - entry->details.ns, entry->details.type, - appended)) { - /** \todo handle memory exhaustion */ treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, appended); + + goto cleanup; } - if (!formatting_list_replace(treebuilder, entry, + entry = entry->next; + } + + /* Now, replace the formatting list entries */ + for (entry = initial_entry; entry != NULL; entry = entry->next) { + void *node; + hubbub_ns prev_ns; + element_type prev_type; + void *prev_node; + uint32_t prev_stack_index; + + node = treebuilder->context.element_stack[++sp].node; + + treebuilder->tree_handler->ref_node( + treebuilder->tree_handler->ctx, node); + + error = formatting_list_replace(treebuilder, entry, entry->details.ns, entry->details.type, - appended, treebuilder->context.current_node, + node, sp, &prev_ns, &prev_type, &prev_node, - &prev_stack_index)) { - /** \todo handle errors */ - treebuilder->tree_handler->unref_node( - treebuilder->tree_handler->ctx, - appended); - } + &prev_stack_index); + /* Cannot fail. Ensure this. */ + assert(error == HUBBUB_OK); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, prev_node); + } - entry = entry->next; + return HUBBUB_OK; + +cleanup: + /* An error occurred while cloning nodes and inserting them. + * We must restore the state on entry here. */ + while (treebuilder->context.current_node > sp) { + hubbub_ns ns; + element_type type; + void *node; + hubbub_error err; + + err = element_stack_pop(treebuilder, &ns, &type, &node); + assert(err == HUBBUB_OK); + + err = remove_node_from_dom(treebuilder, node); + assert(err == HUBBUB_OK); + + treebuilder->tree_handler->unref_node( + treebuilder->tree_handler->ctx, + node); + } + + return error; +} + +/** + * Remove a node from the DOM + * + * \param treebuilder Treebuilder instance + * \param node Node to remove + * \return HUBBUB_OK on success, appropriate error otherwise. + */ +hubbub_error remove_node_from_dom(hubbub_treebuilder *treebuilder, void *node) +{ + hubbub_error err; + void *parent = NULL; + void *removed; + + err = treebuilder->tree_handler->get_parent( + treebuilder->tree_handler->ctx, + node, false, &parent); + if (err != HUBBUB_OK) + return err; + + if (parent != NULL) { + err = treebuilder->tree_handler->remove_child( + treebuilder->tree_handler->ctx, + parent, node, &removed); + if (err != HUBBUB_OK) + return err; + + treebuilder->tree_handler->unref_node( + treebuilder->tree_handler->ctx, + parent); + + treebuilder->tree_handler->unref_node( + treebuilder->tree_handler->ctx, + removed); } + + return HUBBUB_OK; } /** @@ -661,14 +737,15 @@ void clear_active_formatting_list_to_marker(hubbub_treebuilder *treebuilder) element_type type; void *node; uint32_t stack_index; + hubbub_error error; if (is_scoping_element(entry->details.type)) done = true; - if (!formatting_list_remove(treebuilder, entry, - &ns, &type, &node, &stack_index)) { - /** \todo handle errors */ - } + error = formatting_list_remove(treebuilder, entry, + &ns, &type, &node, &stack_index); + /* Can't fail. Ensure this. */ + assert(error == HUBBUB_OK); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, @@ -686,56 +763,82 @@ void clear_active_formatting_list_to_marker(hubbub_treebuilder *treebuilder) * \param treebuilder The treebuilder instance * \param tag The element to insert * \param push Whether to push the element onto the stack + * \return HUBBUB_OK on success, appropriate error otherwise. */ -void insert_element(hubbub_treebuilder *treebuilder, const hubbub_tag *tag, - bool push) +hubbub_error insert_element(hubbub_treebuilder *treebuilder, + const hubbub_tag *tag, bool push) { element_type type = current_node(treebuilder); - int success; + hubbub_error error; void *node, *appended; - success = treebuilder->tree_handler->create_element( + error = treebuilder->tree_handler->create_element( treebuilder->tree_handler->ctx, tag, &node); - if (success != 0) { - /** \todo errors */ - } + if (error != HUBBUB_OK) + return error; if (treebuilder->context.in_table_foster && (type == TABLE || type == TBODY || type == TFOOT || type == THEAD || type == TR)) { - appended = aa_insert_into_foster_parent(treebuilder, node); + error = aa_insert_into_foster_parent(treebuilder, node, + &appended); } else { - success = treebuilder->tree_handler->append_child( + error = treebuilder->tree_handler->append_child( treebuilder->tree_handler->ctx, treebuilder->context.element_stack[ treebuilder->context.current_node].node, node, &appended); - if (success != 0) { - /** \todo errors */ - } - - treebuilder->tree_handler->unref_node( - treebuilder->tree_handler->ctx, node); } + /* No longer interested in node */ + treebuilder->tree_handler->unref_node( + treebuilder->tree_handler->ctx, node); + + if (error != HUBBUB_OK) + return error; + type = element_type_from_name(treebuilder, &tag->name); if (treebuilder->context.form_element != NULL && is_form_associated(type)) { /* Consideration of @form is left to the client */ - treebuilder->tree_handler->form_associate( + error = treebuilder->tree_handler->form_associate( treebuilder->tree_handler->ctx, treebuilder->context.form_element, appended); + if (error != HUBBUB_OK) { + hubbub_error err; + + err = remove_node_from_dom(treebuilder, appended); + assert(err == HUBBUB_OK); + + treebuilder->tree_handler->unref_node( + treebuilder->tree_handler->ctx, + appended); + + return error; + } } if (push) { - if (!element_stack_push(treebuilder, tag->ns, type, appended)) { - /** \todo errors */ + error = element_stack_push(treebuilder, + tag->ns, type, appended); + if (error != HUBBUB_OK) { + hubbub_error err; + + err = remove_node_from_dom(treebuilder, appended); + assert(err == HUBBUB_OK); + + treebuilder->tree_handler->unref_node( + treebuilder->tree_handler->ctx, + appended); + return error; } } else { treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, appended); } + + return HUBBUB_OK; } /** @@ -756,6 +859,7 @@ void close_implied_end_tags(hubbub_treebuilder *treebuilder, while (type == DD || type == DT || type == LI || type == OPTION || type == OPTGROUP || type == P || type == RP || type == RT) { + hubbub_error error; hubbub_ns ns; element_type otype; void *node; @@ -763,9 +867,8 @@ void close_implied_end_tags(hubbub_treebuilder *treebuilder, if (except != UNKNOWN && type == except) break; - if (!element_stack_pop(treebuilder, &ns, &otype, &node)) { - /** \todo errors */ - } + error = element_stack_pop(treebuilder, &ns, &otype, &node); + assert(error == HUBBUB_OK); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, @@ -844,40 +947,42 @@ void reset_insertion_mode(hubbub_treebuilder *treebuilder) * * \param treebuilder The treebuilder instance * \param string The string to append + * \return HUBBUB_OK on success, appropriate error otherwise */ -void append_text(hubbub_treebuilder *treebuilder, +hubbub_error append_text(hubbub_treebuilder *treebuilder, const hubbub_string *string) { element_type type = current_node(treebuilder); - int success; + hubbub_error error = HUBBUB_OK; void *text, *appended; - success = treebuilder->tree_handler->create_text( + error = treebuilder->tree_handler->create_text( treebuilder->tree_handler->ctx, string, &text); - if (success != 0) { - /** \todo errors */ - } + if (error != HUBBUB_OK) + return error; if (treebuilder->context.in_table_foster && (type == TABLE || type == TBODY || type == TFOOT || type == THEAD || type == TR)) { - appended = aa_insert_into_foster_parent(treebuilder, text); + error = aa_insert_into_foster_parent(treebuilder, text, + &appended); } else { - success = treebuilder->tree_handler->append_child( + error = treebuilder->tree_handler->append_child( treebuilder->tree_handler->ctx, treebuilder->context.element_stack[ treebuilder->context.current_node].node, text, &appended); - if (success != 0) { - /** \todo errors */ - } - + } + + if (error == HUBBUB_OK) { treebuilder->tree_handler->unref_node( - treebuilder->tree_handler->ctx, text); + treebuilder->tree_handler->ctx, appended); } treebuilder->tree_handler->unref_node( - treebuilder->tree_handler->ctx, appended); + treebuilder->tree_handler->ctx, text); + + return error; } /** @@ -974,9 +1079,9 @@ bool is_form_associated(element_type type) * \param ns The namespace of element being pushed * \param type The type of element being pushed * \param node The node to push - * \return True on success, false on memory exhaustion + * \return HUBBUB_OK on success, appropriate error otherwise. */ -bool element_stack_push(hubbub_treebuilder *treebuilder, +hubbub_error element_stack_push(hubbub_treebuilder *treebuilder, hubbub_ns ns, element_type type, void *node) { uint32_t slot = treebuilder->context.current_node + 1; @@ -990,7 +1095,7 @@ bool element_stack_push(hubbub_treebuilder *treebuilder, treebuilder->alloc_pw); if (temp == NULL) - return false; + return HUBBUB_NOMEM; treebuilder->context.element_stack = temp; treebuilder->context.stack_alloc += ELEMENT_STACK_CHUNK; @@ -1002,7 +1107,7 @@ bool element_stack_push(hubbub_treebuilder *treebuilder, treebuilder->context.current_node = slot; - return true; + return HUBBUB_OK; } /** @@ -1012,9 +1117,9 @@ bool element_stack_push(hubbub_treebuilder *treebuilder, * \param ns Pointer to location to receive element namespace * \param type Pointer to location to receive element type * \param node Pointer to location to receive node - * \return True on success, false on memory exhaustion. + * \return HUBBUB_OK on success, appropriate error otherwise. */ -bool element_stack_pop(hubbub_treebuilder *treebuilder, +hubbub_error element_stack_pop(hubbub_treebuilder *treebuilder, hubbub_ns *ns, element_type *type, void **node) { element_context *stack = treebuilder->context.element_stack; @@ -1055,26 +1160,26 @@ bool element_stack_pop(hubbub_treebuilder *treebuilder, treebuilder->context.current_node = slot - 1; assert((signed) treebuilder->context.current_node >= 0); - return true; + return HUBBUB_OK; } /** * Pop elements until an element of type "element" has been popped. * - * \return True on success, false on memory exhaustion. + * \return HUBBUB_OK on success, appropriate error otherwise. */ -bool element_stack_pop_until(hubbub_treebuilder *treebuilder, +hubbub_error element_stack_pop_until(hubbub_treebuilder *treebuilder, element_type type) { element_type otype = UNKNOWN; void *node; hubbub_ns ns; + hubbub_error error; while (otype != type) { - if (!element_stack_pop(treebuilder, &ns, &otype, &node)) { - /** \todo error -- never happens */ - return false; - } + error = element_stack_pop(treebuilder, &ns, &otype, &node); + /* No error can occur here. Ensure this. */ + assert(error == HUBBUB_OK); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, node); @@ -1082,7 +1187,7 @@ bool element_stack_pop_until(hubbub_treebuilder *treebuilder, assert((signed) treebuilder->context.current_node >= 0); } - return true; + return HUBBUB_OK; } /** @@ -1093,10 +1198,11 @@ bool element_stack_pop_until(hubbub_treebuilder *treebuilder, * \param ns Pointer to location to receive namespace * \param type Pointer to location to receive type * \param removed Pointer to location to receive removed node - * \return true on success, false on memory exhaustion + * \return HUBBUB_OK on success, appropriate error otherwise. */ -bool element_stack_remove(hubbub_treebuilder *treebuilder, uint32_t index, - hubbub_ns *ns, element_type *type, void **removed) +hubbub_error element_stack_remove(hubbub_treebuilder *treebuilder, + uint32_t index, hubbub_ns *ns, element_type *type, + void **removed) { element_context *stack = treebuilder->context.element_stack; uint32_t n; @@ -1136,7 +1242,7 @@ bool element_stack_remove(hubbub_treebuilder *treebuilder, uint32_t index, treebuilder->context.current_node--; - return true; + return HUBBUB_OK; } /** @@ -1193,9 +1299,9 @@ element_type prev_node(hubbub_treebuilder *treebuilder) * \param type Type of node being inserted * \param node Node being inserted * \param stack_index Index into stack of open elements - * \return True on success, false on memory exhaustion + * \return HUBBUB_OK on success, appropriate error otherwise */ -bool formatting_list_append(hubbub_treebuilder *treebuilder, +hubbub_error formatting_list_append(hubbub_treebuilder *treebuilder, hubbub_ns ns, element_type type, void *node, uint32_t stack_index) { @@ -1204,7 +1310,7 @@ bool formatting_list_append(hubbub_treebuilder *treebuilder, entry = treebuilder->alloc(NULL, sizeof(formatting_list_entry), treebuilder->alloc_pw); if (entry == NULL) - return false; + return HUBBUB_NOMEM; entry->details.ns = ns; entry->details.type = type; @@ -1221,7 +1327,7 @@ bool formatting_list_append(hubbub_treebuilder *treebuilder, treebuilder->context.formatting_list_end = entry; - return true; + return HUBBUB_OK; } /** @@ -1234,9 +1340,9 @@ bool formatting_list_append(hubbub_treebuilder *treebuilder, * \param type Type of node being inserted * \param node Node being inserted * \param stack_index Index into stack of open elements - * \return True on success, false on memory exhaustion + * \return HUBBUB_OK on success, appropriate error otherwise */ -bool formatting_list_insert(hubbub_treebuilder *treebuilder, +hubbub_error formatting_list_insert(hubbub_treebuilder *treebuilder, formatting_list_entry *prev, formatting_list_entry *next, hubbub_ns ns, element_type type, void *node, uint32_t stack_index) @@ -1254,7 +1360,7 @@ bool formatting_list_insert(hubbub_treebuilder *treebuilder, entry = treebuilder->alloc(NULL, sizeof(formatting_list_entry), treebuilder->alloc_pw); if (entry == NULL) - return false; + return HUBBUB_NOMEM; entry->details.ns = ns; entry->details.type = type; @@ -1274,7 +1380,7 @@ bool formatting_list_insert(hubbub_treebuilder *treebuilder, else treebuilder->context.formatting_list_end = entry; - return true; + return HUBBUB_OK; } @@ -1287,9 +1393,9 @@ bool formatting_list_insert(hubbub_treebuilder *treebuilder, * \param type Pointer to location to receive type of node * \param node Pointer to location to receive node * \param stack_index Pointer to location to receive stack index - * \return True on success, false on memory exhaustion + * \return HUBBUB_OK on success, appropriate error otherwise. */ -bool formatting_list_remove(hubbub_treebuilder *treebuilder, +hubbub_error formatting_list_remove(hubbub_treebuilder *treebuilder, formatting_list_entry *entry, hubbub_ns *ns, element_type *type, void **node, uint32_t *stack_index) @@ -1311,7 +1417,7 @@ bool formatting_list_remove(hubbub_treebuilder *treebuilder, treebuilder->alloc(entry, 0, treebuilder->alloc_pw); - return true; + return HUBBUB_OK; } /** @@ -1327,9 +1433,9 @@ bool formatting_list_remove(hubbub_treebuilder *treebuilder, * \param otype Pointer to location to receive old type * \param onode Pointer to location to receive old node * \param ostack_index Pointer to location to receive old stack index - * \return True on success, false on memory exhaustion + * \return HUBBUB_OK on success, appropriate error otherwise */ -bool formatting_list_replace(hubbub_treebuilder *treebuilder, +hubbub_error formatting_list_replace(hubbub_treebuilder *treebuilder, formatting_list_entry *entry, hubbub_ns ns, element_type type, void *node, uint32_t stack_index, @@ -1348,7 +1454,7 @@ bool formatting_list_replace(hubbub_treebuilder *treebuilder, entry->details.node = node; entry->stack_index = stack_index; - return true; + return HUBBUB_OK; } diff --git a/test/tree-buf.c b/test/tree-buf.c index 658e8e8..923573d 100644 --- a/test/tree-buf.c +++ b/test/tree-buf.c @@ -74,25 +74,25 @@ node_t *Document; static void node_print(buf_t *buf, node_t *node, unsigned depth); -static int create_comment(void *ctx, const hubbub_string *data, void **result); -static int create_doctype(void *ctx, const hubbub_doctype *doctype, +static hubbub_error create_comment(void *ctx, const hubbub_string *data, void **result); +static hubbub_error create_doctype(void *ctx, const hubbub_doctype *doctype, void **result); -static int create_element(void *ctx, const hubbub_tag *tag, void **result); -static int create_text(void *ctx, const hubbub_string *data, void **result); -static int ref_node(void *ctx, void *node); -static int unref_node(void *ctx, void *node); -static int append_child(void *ctx, void *parent, void *child, void **result); -static int insert_before(void *ctx, void *parent, void *child, void *ref_child, +static hubbub_error create_element(void *ctx, const hubbub_tag *tag, void **result); +static hubbub_error create_text(void *ctx, const hubbub_string *data, void **result); +static hubbub_error ref_node(void *ctx, void *node); +static hubbub_error unref_node(void *ctx, void *node); +static hubbub_error append_child(void *ctx, void *parent, void *child, void **result); +static hubbub_error insert_before(void *ctx, void *parent, void *child, void *ref_child, void **result); -static int remove_child(void *ctx, void *parent, void *child, void **result); -static int clone_node(void *ctx, void *node, bool deep, void **result); -static int reparent_children(void *ctx, void *node, void *new_parent); -static int get_parent(void *ctx, void *node, bool element_only, void **result); -static int has_children(void *ctx, void *node, bool *result); -static int form_associate(void *ctx, void *form, void *node); -static int add_attributes(void *ctx, void *node, +static hubbub_error remove_child(void *ctx, void *parent, void *child, void **result); +static hubbub_error clone_node(void *ctx, void *node, bool deep, void **result); +static hubbub_error reparent_children(void *ctx, void *node, void *new_parent); +static hubbub_error get_parent(void *ctx, void *node, bool element_only, void **result); +static hubbub_error has_children(void *ctx, void *node, bool *result); +static hubbub_error form_associate(void *ctx, void *form, void *node); +static hubbub_error add_attributes(void *ctx, void *node, const hubbub_attribute *attributes, uint32_t n_attributes); -static int set_quirks_mode(void *ctx, hubbub_quirks_mode mode); +static hubbub_error set_quirks_mode(void *ctx, hubbub_quirks_mode mode); static void delete_node(node_t *node); static void delete_attr(attr_t *attr); @@ -278,7 +278,7 @@ int main(int argc, char **argv) /*** Tree construction functions ***/ -int create_comment(void *ctx, const hubbub_string *data, void **result) +hubbub_error create_comment(void *ctx, const hubbub_string *data, void **result) { node_t *node = calloc(1, sizeof *node); @@ -291,10 +291,11 @@ int create_comment(void *ctx, const hubbub_string *data, void **result) *result = node; - return 0; + return HUBBUB_OK; } -int create_doctype(void *ctx, const hubbub_doctype *doctype, void **result) +hubbub_error create_doctype(void *ctx, const hubbub_doctype *doctype, + void **result) { node_t *node = calloc(1, sizeof *node); @@ -320,10 +321,10 @@ int create_doctype(void *ctx, const hubbub_doctype *doctype, void **result) *result = node; - return 0; + return HUBBUB_OK; } -int create_element(void *ctx, const hubbub_tag *tag, void **result) +hubbub_error create_element(void *ctx, const hubbub_tag *tag, void **result) { node_t *node = calloc(1, sizeof *node); @@ -360,10 +361,10 @@ int create_element(void *ctx, const hubbub_tag *tag, void **result) *result = node; - return 0; + return HUBBUB_OK; } -int create_text(void *ctx, const hubbub_string *data, void **result) +hubbub_error create_text(void *ctx, const hubbub_string *data, void **result) { node_t *node = calloc(1, sizeof *node); @@ -376,10 +377,10 @@ int create_text(void *ctx, const hubbub_string *data, void **result) *result = node; - return 0; + return HUBBUB_OK; } -int ref_node(void *ctx, void *node) +hubbub_error ref_node(void *ctx, void *node) { node_t *n = node; @@ -388,10 +389,10 @@ int ref_node(void *ctx, void *node) if (node != (void *) 1) n->refcnt++; - return 0; + return HUBBUB_OK; } -int unref_node(void *ctx, void *node) +hubbub_error unref_node(void *ctx, void *node) { node_t *n = node; @@ -409,10 +410,10 @@ int unref_node(void *ctx, void *node) } } - return 0; + return HUBBUB_OK; } -int append_child(void *ctx, void *parent, void *child, void **result) +hubbub_error append_child(void *ctx, void *parent, void *child, void **result) { node_t *tparent = parent; node_t *tchild = child; @@ -467,12 +468,12 @@ int append_child(void *ctx, void *parent, void *child, void **result) ref_node(ctx, *result); - return 0; + return HUBBUB_OK; } /* insert 'child' before 'ref_child', under 'parent' */ -int insert_before(void *ctx, void *parent, void *child, void *ref_child, - void **result) +hubbub_error insert_before(void *ctx, void *parent, void *child, + void *ref_child, void **result) { node_t *tparent = parent; node_t *tchild = child; @@ -515,10 +516,10 @@ int insert_before(void *ctx, void *parent, void *child, void *ref_child, ref_node(ctx, *result); - return 0; + return HUBBUB_OK; } -int remove_child(void *ctx, void *parent, void *child, void **result) +hubbub_error remove_child(void *ctx, void *parent, void *child, void **result) { node_t *tparent = parent; node_t *tchild = child; @@ -545,10 +546,10 @@ int remove_child(void *ctx, void *parent, void *child, void **result) ref_node(ctx, *result); - return 0; + return HUBBUB_OK; } -int clone_node(void *ctx, void *node, bool deep, void **result) +hubbub_error clone_node(void *ctx, void *node, bool deep, void **result) { node_t *old_node = node; node_t *new_node = calloc(1, sizeof *new_node); @@ -622,11 +623,11 @@ int clone_node(void *ctx, void *node, bool deep, void **result) last = n; } - return 0; + return HUBBUB_OK; } /* Take all of the child nodes of "node" and append them to "new_parent" */ -int reparent_children(void *ctx, void *node, void *new_parent) +hubbub_error reparent_children(void *ctx, void *node, void *new_parent) { node_t *parent = new_parent; node_t *old_parent = node; @@ -658,10 +659,10 @@ int reparent_children(void *ctx, void *node, void *new_parent) kids = kids->next; } - return 0; + return HUBBUB_OK; } -int get_parent(void *ctx, void *node, bool element_only, void **result) +hubbub_error get_parent(void *ctx, void *node, bool element_only, void **result) { UNUSED(element_only); @@ -670,28 +671,28 @@ int get_parent(void *ctx, void *node, bool element_only, void **result) if (*result != NULL) ref_node(ctx, *result); - return 0; + return HUBBUB_OK; } -int has_children(void *ctx, void *node, bool *result) +hubbub_error has_children(void *ctx, void *node, bool *result) { UNUSED(ctx); *result = ((node_t *)node)->child ? true : false; - return 0; + return HUBBUB_OK; } -int form_associate(void *ctx, void *form, void *node) +hubbub_error form_associate(void *ctx, void *form, void *node) { UNUSED(ctx); UNUSED(form); UNUSED(node); - return 0; + return HUBBUB_OK; } -int add_attributes(void *ctx, void *vnode, +hubbub_error add_attributes(void *ctx, void *vnode, const hubbub_attribute *attributes, uint32_t n_attributes) { node_t *node = vnode; @@ -722,15 +723,15 @@ int add_attributes(void *ctx, void *vnode, } - return 0; + return HUBBUB_OK; } -int set_quirks_mode(void *ctx, hubbub_quirks_mode mode) +hubbub_error set_quirks_mode(void *ctx, hubbub_quirks_mode mode) { UNUSED(ctx); UNUSED(mode); - return 0; + return HUBBUB_OK; } diff --git a/test/tree.c b/test/tree.c index 8738dcf..dee0893 100644 --- a/test/tree.c +++ b/test/tree.c @@ -29,25 +29,31 @@ static uintptr_t node_counter; node_ref_alloc += NODE_REF_CHUNK; \ } -static int create_comment(void *ctx, const hubbub_string *data, void **result); -static int create_doctype(void *ctx, const hubbub_doctype *doctype, +static hubbub_error create_comment(void *ctx, const hubbub_string *data, void **result); -static int create_element(void *ctx, const hubbub_tag *tag, void **result); -static int create_text(void *ctx, const hubbub_string *data, void **result); -static int ref_node(void *ctx, void *node); -static int unref_node(void *ctx, void *node); -static int append_child(void *ctx, void *parent, void *child, void **result); -static int insert_before(void *ctx, void *parent, void *child, void *ref_child, +static hubbub_error create_doctype(void *ctx, const hubbub_doctype *doctype, void **result); -static int remove_child(void *ctx, void *parent, void *child, void **result); -static int clone_node(void *ctx, void *node, bool deep, void **result); -static int reparent_children(void *ctx, void *node, void *new_parent); -static int get_parent(void *ctx, void *node, bool element_only, void **result); -static int has_children(void *ctx, void *node, bool *result); -static int form_associate(void *ctx, void *form, void *node); -static int add_attributes(void *ctx, void *node, +static hubbub_error create_element(void *ctx, const hubbub_tag *tag, + void **result); +static hubbub_error create_text(void *ctx, const hubbub_string *data, + void **result); +static hubbub_error ref_node(void *ctx, void *node); +static hubbub_error unref_node(void *ctx, void *node); +static hubbub_error append_child(void *ctx, void *parent, void *child, + void **result); +static hubbub_error insert_before(void *ctx, void *parent, void *child, + void *ref_child, void **result); +static hubbub_error remove_child(void *ctx, void *parent, void *child, + void **result); +static hubbub_error clone_node(void *ctx, void *node, bool deep, void **result); +static hubbub_error reparent_children(void *ctx, void *node, void *new_parent); +static hubbub_error get_parent(void *ctx, void *node, bool element_only, + void **result); +static hubbub_error has_children(void *ctx, void *node, bool *result); +static hubbub_error form_associate(void *ctx, void *form, void *node); +static hubbub_error add_attributes(void *ctx, void *node, const hubbub_attribute *attributes, uint32_t n_attributes); -static int set_quirks_mode(void *ctx, hubbub_quirks_mode mode); +static hubbub_error set_quirks_mode(void *ctx, hubbub_quirks_mode mode); static hubbub_tree_handler tree_handler = { create_comment, @@ -181,7 +187,7 @@ int main(int argc, char **argv) #undef DO_TEST } -int create_comment(void *ctx, const hubbub_string *data, void **result) +hubbub_error create_comment(void *ctx, const hubbub_string *data, void **result) { printf("Creating (%" PRIuPTR ") [comment '%.*s']\n", ++node_counter, (int) data->len, data->ptr); @@ -195,10 +201,11 @@ int create_comment(void *ctx, const hubbub_string *data, void **result) *result = (void *) node_counter; - return 0; + return HUBBUB_OK; } -int create_doctype(void *ctx, const hubbub_doctype *doctype, void **result) +hubbub_error create_doctype(void *ctx, const hubbub_doctype *doctype, + void **result) { printf("Creating (%" PRIuPTR ") [doctype '%.*s']\n", ++node_counter, (int) doctype->name.len, doctype->name.ptr); @@ -220,10 +227,10 @@ int create_doctype(void *ctx, const hubbub_doctype *doctype, void **result) *result = (void *) node_counter; - return 0; + return HUBBUB_OK; } -int create_element(void *ctx, const hubbub_tag *tag, void **result) +hubbub_error create_element(void *ctx, const hubbub_tag *tag, void **result) { printf("Creating (%" PRIuPTR ") [element '%.*s']\n", ++node_counter, (int) tag->name.len, tag->name.ptr); @@ -243,10 +250,10 @@ int create_element(void *ctx, const hubbub_tag *tag, void **result) *result = (void *) node_counter; - return 0; + return HUBBUB_OK; } -int create_text(void *ctx, const hubbub_string *data, void **result) +hubbub_error create_text(void *ctx, const hubbub_string *data, void **result) { printf("Creating (%" PRIuPTR ") [text '%.*s']\n", ++node_counter, (int) data->len, data->ptr); @@ -260,41 +267,41 @@ int create_text(void *ctx, const hubbub_string *data, void **result) *result = (void *) node_counter; - return 0; + return HUBBUB_OK; } -int ref_node(void *ctx, void *node) +hubbub_error ref_node(void *ctx, void *node) { UNUSED(ctx); printf("Referencing %" PRIuPTR " (=%u)\n", (uintptr_t) node, ++node_ref[(uintptr_t) node]); - return 0; + return HUBBUB_OK; } -int unref_node(void *ctx, void *node) +hubbub_error unref_node(void *ctx, void *node) { UNUSED(ctx); printf("Unreferencing %" PRIuPTR " (=%u)\n", (uintptr_t) node, --node_ref[(uintptr_t) node]); - return 0; + return HUBBUB_OK; } -int append_child(void *ctx, void *parent, void *child, void **result) +hubbub_error append_child(void *ctx, void *parent, void *child, void **result) { printf("Appending %" PRIuPTR " to %" PRIuPTR "\n", (uintptr_t) child, (uintptr_t) parent); ref_node(ctx, child); *result = (void *) child; - return 0; + return HUBBUB_OK; } -int insert_before(void *ctx, void *parent, void *child, void *ref_child, - void **result) +hubbub_error insert_before(void *ctx, void *parent, void *child, + void *ref_child, void **result) { printf("Inserting %" PRIuPTR " in %" PRIuPTR " before %" PRIuPTR "\n", (uintptr_t) child, (uintptr_t) parent, (uintptr_t) ref_child); @@ -302,20 +309,20 @@ int insert_before(void *ctx, void *parent, void *child, void *ref_child, *result = (void *) child; - return 0; + return HUBBUB_OK; } -int remove_child(void *ctx, void *parent, void *child, void **result) +hubbub_error remove_child(void *ctx, void *parent, void *child, void **result) { printf("Removing %" PRIuPTR " from %" PRIuPTR "\n", (uintptr_t) child, (uintptr_t) parent); ref_node(ctx, child); *result = (void *) child; - return 0; + return HUBBUB_OK; } -int clone_node(void *ctx, void *node, bool deep, void **result) +hubbub_error clone_node(void *ctx, void *node, bool deep, void **result) { printf("%sCloning %" PRIuPTR " -> %" PRIuPTR "\n", deep ? "Deep-" : "", (uintptr_t) node, ++node_counter); @@ -327,20 +334,20 @@ int clone_node(void *ctx, void *node, bool deep, void **result) *result = (void *) node_counter; - return 0; + return HUBBUB_OK; } -int reparent_children(void *ctx, void *node, void *new_parent) +hubbub_error reparent_children(void *ctx, void *node, void *new_parent) { UNUSED(ctx); printf("Reparenting children of %" PRIuPTR " to %" PRIuPTR "\n", (uintptr_t) node, (uintptr_t) new_parent); - return 0; + return HUBBUB_OK; } -int get_parent(void *ctx, void *node, bool element_only, void **result) +hubbub_error get_parent(void *ctx, void *node, bool element_only, void **result) { printf("Retrieving parent of %" PRIuPTR " (%s)\n", (uintptr_t) node, element_only ? "element only" : ""); @@ -348,10 +355,10 @@ int get_parent(void *ctx, void *node, bool element_only, void **result) ref_node(ctx, (void *) 1); *result = (void *) 1; - return 0; + return HUBBUB_OK; } -int has_children(void *ctx, void *node, bool *result) +hubbub_error has_children(void *ctx, void *node, bool *result) { UNUSED(ctx); @@ -359,20 +366,20 @@ int has_children(void *ctx, void *node, bool *result) *result = false; - return 0; + return HUBBUB_OK; } -int form_associate(void *ctx, void *form, void *node) +hubbub_error form_associate(void *ctx, void *form, void *node) { UNUSED(ctx); printf("Associating %" PRIuPTR " with form %" PRIuPTR "\n", (uintptr_t) node, (uintptr_t) form); - return 0; + return HUBBUB_OK; } -int add_attributes(void *ctx, void *node, +hubbub_error add_attributes(void *ctx, void *node, const hubbub_attribute *attributes, uint32_t n_attributes) { UNUSED(ctx); @@ -388,15 +395,15 @@ int add_attributes(void *ctx, void *node, assert(memchr(attr->value.ptr, 0xff, attr->value.len) == NULL); } - return 0; + return HUBBUB_OK; } -int set_quirks_mode(void *ctx, hubbub_quirks_mode mode) +hubbub_error set_quirks_mode(void *ctx, hubbub_quirks_mode mode) { UNUSED(ctx); printf("Quirks mode = %u\n", mode); - return 0; + return HUBBUB_OK; } diff --git a/test/tree2.c b/test/tree2.c index 5da41ef..d6ae196 100644 --- a/test/tree2.c +++ b/test/tree2.c @@ -74,25 +74,25 @@ node_t *Document; static void node_print(buf_t *buf, node_t *node, unsigned depth); -static int create_comment(void *ctx, const hubbub_string *data, void **result); -static int create_doctype(void *ctx, const hubbub_doctype *doctype, +static hubbub_error create_comment(void *ctx, const hubbub_string *data, void **result); +static hubbub_error create_doctype(void *ctx, const hubbub_doctype *doctype, void **result); -static int create_element(void *ctx, const hubbub_tag *tag, void **result); -static int create_text(void *ctx, const hubbub_string *data, void **result); -static int ref_node(void *ctx, void *node); -static int unref_node(void *ctx, void *node); -static int append_child(void *ctx, void *parent, void *child, void **result); -static int insert_before(void *ctx, void *parent, void *child, void *ref_child, +static hubbub_error create_element(void *ctx, const hubbub_tag *tag, void **result); +static hubbub_error create_text(void *ctx, const hubbub_string *data, void **result); +static hubbub_error ref_node(void *ctx, void *node); +static hubbub_error unref_node(void *ctx, void *node); +static hubbub_error append_child(void *ctx, void *parent, void *child, void **result); +static hubbub_error insert_before(void *ctx, void *parent, void *child, void *ref_child, void **result); -static int remove_child(void *ctx, void *parent, void *child, void **result); -static int clone_node(void *ctx, void *node, bool deep, void **result); -static int reparent_children(void *ctx, void *node, void *new_parent); -static int get_parent(void *ctx, void *node, bool element_only, void **result); -static int has_children(void *ctx, void *node, bool *result); -static int form_associate(void *ctx, void *form, void *node); -static int add_attributes(void *ctx, void *node, +static hubbub_error remove_child(void *ctx, void *parent, void *child, void **result); +static hubbub_error clone_node(void *ctx, void *node, bool deep, void **result); +static hubbub_error reparent_children(void *ctx, void *node, void *new_parent); +static hubbub_error get_parent(void *ctx, void *node, bool element_only, void **result); +static hubbub_error has_children(void *ctx, void *node, bool *result); +static hubbub_error form_associate(void *ctx, void *form, void *node); +static hubbub_error add_attributes(void *ctx, void *node, const hubbub_attribute *attributes, uint32_t n_attributes); -static int set_quirks_mode(void *ctx, hubbub_quirks_mode mode); +static hubbub_error set_quirks_mode(void *ctx, hubbub_quirks_mode mode); static void delete_node(node_t *node); static void delete_attr(attr_t *attr); @@ -358,7 +358,7 @@ int main(int argc, char **argv) /*** Tree construction functions ***/ -int create_comment(void *ctx, const hubbub_string *data, void **result) +hubbub_error create_comment(void *ctx, const hubbub_string *data, void **result) { node_t *node = calloc(1, sizeof *node); @@ -371,10 +371,11 @@ int create_comment(void *ctx, const hubbub_string *data, void **result) *result = node; - return 0; + return HUBBUB_OK; } -int create_doctype(void *ctx, const hubbub_doctype *doctype, void **result) +hubbub_error create_doctype(void *ctx, const hubbub_doctype *doctype, + void **result) { node_t *node = calloc(1, sizeof *node); @@ -400,10 +401,10 @@ int create_doctype(void *ctx, const hubbub_doctype *doctype, void **result) *result = node; - return 0; + return HUBBUB_OK; } -int create_element(void *ctx, const hubbub_tag *tag, void **result) +hubbub_error create_element(void *ctx, const hubbub_tag *tag, void **result) { node_t *node = calloc(1, sizeof *node); @@ -440,10 +441,10 @@ int create_element(void *ctx, const hubbub_tag *tag, void **result) *result = node; - return 0; + return HUBBUB_OK; } -int create_text(void *ctx, const hubbub_string *data, void **result) +hubbub_error create_text(void *ctx, const hubbub_string *data, void **result) { node_t *node = calloc(1, sizeof *node); @@ -456,10 +457,10 @@ int create_text(void *ctx, const hubbub_string *data, void **result) *result = node; - return 0; + return HUBBUB_OK; } -int ref_node(void *ctx, void *node) +hubbub_error ref_node(void *ctx, void *node) { node_t *n = node; @@ -468,10 +469,10 @@ int ref_node(void *ctx, void *node) if (node != (void *) 1) n->refcnt++; - return 0; + return HUBBUB_OK; } -int unref_node(void *ctx, void *node) +hubbub_error unref_node(void *ctx, void *node) { node_t *n = node; @@ -482,17 +483,19 @@ int unref_node(void *ctx, void *node) n->refcnt--; - printf("Unreferencing node %p (%d)\n", node, n->refcnt); + printf("Unreferencing node %p (%d) [%d : %s]\n", node, + n->refcnt, n->type, + n->type == ELEMENT ? n->data.element.name : ""); if (n->refcnt == 0 && n->parent == NULL) { delete_node(n); } } - return 0; + return HUBBUB_OK; } -int append_child(void *ctx, void *parent, void *child, void **result) +hubbub_error append_child(void *ctx, void *parent, void *child, void **result) { node_t *tparent = parent; node_t *tchild = child; @@ -546,12 +549,12 @@ int append_child(void *ctx, void *parent, void *child, void **result) ref_node(ctx, *result); - return 0; + return HUBBUB_OK; } /* insert 'child' before 'ref_child', under 'parent' */ -int insert_before(void *ctx, void *parent, void *child, void *ref_child, - void **result) +hubbub_error insert_before(void *ctx, void *parent, void *child, + void *ref_child, void **result) { node_t *tparent = parent; node_t *tchild = child; @@ -594,10 +597,10 @@ int insert_before(void *ctx, void *parent, void *child, void *ref_child, ref_node(ctx, *result); - return 0; + return HUBBUB_OK; } -int remove_child(void *ctx, void *parent, void *child, void **result) +hubbub_error remove_child(void *ctx, void *parent, void *child, void **result) { node_t *tparent = parent; node_t *tchild = child; @@ -624,10 +627,10 @@ int remove_child(void *ctx, void *parent, void *child, void **result) ref_node(ctx, *result); - return 0; + return HUBBUB_OK; } -int clone_node(void *ctx, void *node, bool deep, void **result) +hubbub_error clone_node(void *ctx, void *node, bool deep, void **result) { node_t *old_node = node; node_t *new_node = calloc(1, sizeof *new_node); @@ -701,11 +704,11 @@ int clone_node(void *ctx, void *node, bool deep, void **result) last = n; } - return 0; + return HUBBUB_OK; } /* Take all of the child nodes of "node" and append them to "new_parent" */ -int reparent_children(void *ctx, void *node, void *new_parent) +hubbub_error reparent_children(void *ctx, void *node, void *new_parent) { node_t *parent = new_parent; node_t *old_parent = node; @@ -737,10 +740,10 @@ int reparent_children(void *ctx, void *node, void *new_parent) kids = kids->next; } - return 0; + return HUBBUB_OK; } -int get_parent(void *ctx, void *node, bool element_only, void **result) +hubbub_error get_parent(void *ctx, void *node, bool element_only, void **result) { UNUSED(element_only); @@ -749,28 +752,28 @@ int get_parent(void *ctx, void *node, bool element_only, void **result) if (*result != NULL) ref_node(ctx, *result); - return 0; + return HUBBUB_OK; } -int has_children(void *ctx, void *node, bool *result) +hubbub_error has_children(void *ctx, void *node, bool *result) { UNUSED(ctx); *result = ((node_t *)node)->child ? true : false; - return 0; + return HUBBUB_OK; } -int form_associate(void *ctx, void *form, void *node) +hubbub_error form_associate(void *ctx, void *form, void *node) { UNUSED(ctx); UNUSED(form); UNUSED(node); - return 0; + return HUBBUB_OK; } -int add_attributes(void *ctx, void *vnode, +hubbub_error add_attributes(void *ctx, void *vnode, const hubbub_attribute *attributes, uint32_t n_attributes) { node_t *node = vnode; @@ -801,15 +804,15 @@ int add_attributes(void *ctx, void *vnode, } - return 0; + return HUBBUB_OK; } -int set_quirks_mode(void *ctx, hubbub_quirks_mode mode) +hubbub_error set_quirks_mode(void *ctx, hubbub_quirks_mode mode) { UNUSED(ctx); UNUSED(mode); - return 0; + return HUBBUB_OK; } -- cgit v1.2.3