From ec1018714f31913d68fb440ec9f9a885366df12d Mon Sep 17 00:00:00 2001 From: John Mark Bell Date: Tue, 11 Mar 2008 23:04:35 +0000 Subject: More treebuilder (really 8.2.4.8 this time) Add tree handler entrypoint for creating elements with verbatim names svn path=/trunk/hubbub/; revision=3940 --- include/hubbub/functypes.h | 6 ++ include/hubbub/tree.h | 1 + src/treebuilder/treebuilder.c | 175 ++++++++++++++++++++++++++++++++++++++++++ test/tree.c | 19 +++++ 4 files changed, 201 insertions(+) diff --git a/include/hubbub/functypes.h b/include/hubbub/functypes.h index ce95303..ddc307a 100644 --- a/include/hubbub/functypes.h +++ b/include/hubbub/functypes.h @@ -52,6 +52,12 @@ typedef int (*hubbub_tree_create_doctype)(void *ctx, const hubbub_string *qname, typedef int (*hubbub_tree_create_element)(void *ctx, const hubbub_tag *tag, void **result); +/** + * Type of tree element node creation function (verbatim name) + */ +typedef int (*hubbub_tree_create_element_verbatim)(void *ctx, + const uint8_t *name, size_t name_len, void **result); + /** * Type of tree text node creation function */ diff --git a/include/hubbub/tree.h b/include/hubbub/tree.h index 5b82592..cc66acf 100644 --- a/include/hubbub/tree.h +++ b/include/hubbub/tree.h @@ -17,6 +17,7 @@ typedef struct hubbub_tree_handler { hubbub_tree_create_comment create_comment; hubbub_tree_create_doctype create_doctype; hubbub_tree_create_element create_element; + hubbub_tree_create_element_verbatim create_element_verbatim; hubbub_tree_create_text create_text; hubbub_tree_ref_node ref_node; hubbub_tree_unref_node unref_node; diff --git a/src/treebuilder/treebuilder.c b/src/treebuilder/treebuilder.c index deb2493..bf3ac41 100644 --- a/src/treebuilder/treebuilder.c +++ b/src/treebuilder/treebuilder.c @@ -119,6 +119,8 @@ static void hubbub_treebuilder_token_handler(const hubbub_token *token, static bool handle_initial(hubbub_treebuilder *treebuilder, const hubbub_token *token); +static bool handle_before_html(hubbub_treebuilder *treebuilder, + const hubbub_token *token); /** \todo Uncomment the static keyword here once these functions are actually used */ @@ -393,6 +395,8 @@ void hubbub_treebuilder_token_handler(const hubbub_token *token, reprocess = handle_initial(treebuilder, token); break; case BEFORE_HTML: + reprocess = handle_before_html(treebuilder, token); + break; case BEFORE_HEAD: case IN_HEAD: case IN_HEAD_NOSCRIPT: @@ -543,6 +547,177 @@ bool handle_initial(hubbub_treebuilder *treebuilder, const hubbub_token *token) return reprocess; } +/** + * Handle token in "before html" insertion mode + * + * \param treebuilder The treebuilder instance + * \param token The token to handle + * \return True to reprocess token, false otherwise + */ +bool handle_before_html(hubbub_treebuilder *treebuilder, + const hubbub_token *token) +{ + bool reprocess = false; + + switch (token->type) { + case HUBBUB_TOKEN_DOCTYPE: + /** \todo parse error */ + break; + case HUBBUB_TOKEN_COMMENT: + { + int success; + void *comment, *appended; + + success = treebuilder->tree_handler->create_comment( + treebuilder->tree_handler->ctx, + &token->data.comment, &comment); + if (success != 0) { + /** \todo errors */ + } + + /* Append to Document node */ + success = treebuilder->tree_handler->append_child( + treebuilder->tree_handler->ctx, + treebuilder->context.document, + comment, &appended); + if (success != 0) { + /** \todo errors */ + treebuilder->tree_handler->unref_node( + treebuilder->tree_handler->ctx, + comment); + } + + treebuilder->tree_handler->unref_node( + treebuilder->tree_handler->ctx, appended); + treebuilder->tree_handler->unref_node( + treebuilder->tree_handler->ctx, comment); + } + break; + case HUBBUB_TOKEN_CHARACTER: + { + const uint8_t *data = treebuilder->input_buffer + + token->data.character.data_off; + size_t len = token->data.character.len; + size_t c; + + /** \todo UTF-16 */ + + for (c = 0; c < len; c++) { + if (data[c] != 0x09 && data[c] != 0x0A && + data[c] != 0x0B && data[c] != 0x0C && + data[c] != 0x20) + break; + } + /* Non-whitespace characters in token, so reprocess */ + if (c != len) { + /* Update token data to strip leading whitespace */ + ((hubbub_token *) token)->data.character.data_off += + len - c; + ((hubbub_token *) token)->data.character.len -= c; + + treebuilder->context.mode = BEFORE_HEAD; + reprocess = true; + } + } + break; + case HUBBUB_TOKEN_START_TAG: + { + element_type type = element_type_from_name(treebuilder, + &token->data.tag.name); + + treebuilder->context.mode = BEFORE_HEAD; + + if (type == HTML) { + int success; + void *html, *appended; + + success = treebuilder->tree_handler->create_element( + treebuilder->tree_handler->ctx, + &token->data.tag, &html); + if (success != 0) { + /** \todo errors */ + } + + success = 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); + } + + /* 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 + * the stack, this does not hold so we must insert + * manually. */ + treebuilder->context.element_stack[0].type = HTML; + treebuilder->context.element_stack[0].node = html; + treebuilder->context.current_node = 0; + + /** \todo cache selection algorithm */ + + treebuilder->tree_handler->unref_node( + treebuilder->tree_handler->ctx, + appended); + } else { + reprocess = true; + } + } + break; + case HUBBUB_TOKEN_END_TAG: + case HUBBUB_TOKEN_EOF: + treebuilder->context.mode = BEFORE_HEAD; + reprocess = true; + break; + } + + if (reprocess == true) { + /* Need to manufacture html element */ + int success; + void *html, *appended; + + /** \todo UTF-16 */ + success = treebuilder->tree_handler->create_element_verbatim( + treebuilder->tree_handler->ctx, + (const uint8_t *) "html", SLEN("html"), &html); + if (success != 0) { + /** \todo errors */ + } + + success = 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); + } + + /* 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 + * the stack, this does not hold so we must insert + * manually. */ + treebuilder->context.element_stack[0].type = HTML; + treebuilder->context.element_stack[0].node = html; + treebuilder->context.current_node = 0; + + /** \todo cache selection algorithm */ + + treebuilder->tree_handler->unref_node( + treebuilder->tree_handler->ctx, + appended); + } + + return reprocess; +} + /** * Determine if an element is in (table) scope * diff --git a/test/tree.c b/test/tree.c index 76cf438..04ce026 100644 --- a/test/tree.c +++ b/test/tree.c @@ -37,6 +37,8 @@ static int create_doctype(void *ctx, const hubbub_string *qname, const hubbub_string *public_id, const hubbub_string *system_id, void **result); static int create_element(void *ctx, const hubbub_tag *tag, void **result); +static int create_element_verbatim(void *ctx, const uint8_t *name, size_t len, + 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); @@ -51,6 +53,7 @@ static hubbub_tree_handler tree_handler = { create_comment, create_doctype, create_element, + create_element_verbatim, create_text, ref_node, unref_node, @@ -232,6 +235,22 @@ int create_element(void *ctx, const hubbub_tag *tag, void **result) return 0; } +int create_element_verbatim(void *ctx, const uint8_t *name, size_t len, + void **result) +{ + printf("Creating (%u) [element verbatim '%.*s']\n", + ++node_counter, len, name); + + GROW_REF + node_ref[node_counter] = 0; + + ref_node(ctx, (void *) node_counter); + + *result = (void *) node_counter; + + return 0; +} + int create_text(void *ctx, const hubbub_string *data, void **result) { printf("Creating (%u) [text '%.*s']\n", ++node_counter, -- cgit v1.2.3