diff options
author | Vincent Sanders <vince@netsurf-browser.org> | 2012-07-13 17:33:15 -0600 |
---|---|---|
committer | Vincent Sanders <vince@netsurf-browser.org> | 2012-07-13 17:37:22 -0600 |
commit | d7289f67012f14471f4ccab911c3a976af52625a (patch) | |
tree | 3192bb49922eb7f5fd1d3fb80640d1fb15bfb0da /render/hubbub_binding.c | |
parent | 019be7616caf377f5b233c98206bc0c5d45a9793 (diff) | |
download | netsurf-d7289f67012f14471f4ccab911c3a976af52625a.tar.gz netsurf-d7289f67012f14471f4ccab911c3a976af52625a.tar.bz2 |
remove parser binding layer
Diffstat (limited to 'render/hubbub_binding.c')
-rw-r--r-- | render/hubbub_binding.c | 1325 |
1 files changed, 0 insertions, 1325 deletions
diff --git a/render/hubbub_binding.c b/render/hubbub_binding.c deleted file mode 100644 index 2f9899fad..000000000 --- a/render/hubbub_binding.c +++ /dev/null @@ -1,1325 +0,0 @@ -/* - * Copyright 2008 Andrew Sidwell <takkaria@netsurf-browser.org> - * Copyright 2008 John-Mark Bell <jmb@netsurf-browser.org> - * - * This file is part of NetSurf, http://www.netsurf-browser.org/ - * - * NetSurf is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * NetSurf is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <assert.h> -#include <stdbool.h> -#include <string.h> - -#include <libxml/HTMLparser.h> -#include <libxml/HTMLtree.h> - -#include <hubbub/parser.h> -#include <hubbub/tree.h> - -#include "render/form.h" -#include "render/parser_binding.h" - -#include "utils/config.h" -#include "utils/log.h" -#include "utils/talloc.h" -#include "utils/utils.h" - -/** - * Private data attached to each DOM node - */ -typedef struct hubbub_private { - binding_private base; - - uint32_t refcnt; -} hubbub_private; - -typedef struct hubbub_ctx { - hubbub_parser *parser; - - htmlDocPtr document; - bool owns_doc; - - binding_quirks_mode quirks; - - const char *encoding; - binding_encoding_source encoding_source; - -#define NUM_NAMESPACES (6) - xmlNsPtr namespaces[NUM_NAMESPACES]; -#undef NUM_NAMESPACES - - hubbub_tree_handler tree_handler; - - struct form *forms; -} hubbub_ctx; - -static struct { - const char *prefix; - const char *url; -} namespaces[] = { - { NULL, NULL }, - { NULL, "http://www.w3.org/1999/xhtml" }, - { "math", "http://www.w3.org/1998/Math/MathML" }, - { "svg", "http://www.w3.org/2000/svg" }, - { "xlink", "http://www.w3.org/1999/xlink" }, - /** \todo Oh dear. LibXML2 refuses to create any namespace with a - * prefix of "xml". That sucks, royally. */ - { "xml", "http://www.w3.org/XML/1998/namespace" }, - { "xmlns", "http://www.w3.org/2000/xmlns/" } -}; - -static hubbub_private *create_private(uint32_t refcnt); -static hubbub_private *copy_private(const hubbub_private *p, uint32_t refcnt); -static void destroy_private(hubbub_private *p); -static inline char *c_string_from_hubbub_string(hubbub_ctx *ctx, - const hubbub_string *str); -static void create_namespaces(hubbub_ctx *ctx, xmlNode *root); -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 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 hubbub_error set_quirks_mode(void *ctx, hubbub_quirks_mode mode); -static hubbub_error change_encoding(void *ctx, const char *charset); - -static struct form *parse_form_element(xmlNode *node, const char *docenc); -static struct form_control *parse_input_element(xmlNode *node); -static struct form_control *parse_button_element(xmlNode *node); -static struct form_control *parse_select_element(xmlNode *node); -static struct form_control *parse_textarea_element(xmlNode *node); - -static hubbub_tree_handler tree_handler = { - create_comment, - create_doctype, - create_element, - create_text, - ref_node, - unref_node, - append_child, - insert_before, - remove_child, - clone_node, - reparent_children, - get_parent, - has_children, - form_associate, - add_attributes, - set_quirks_mode, - change_encoding, - NULL -}; - -static void *ns_talloc_based_realloc(void *ptr, size_t len, void *pw) -{ - /* talloc_realloc_size(pw, ptr, 0) == talloc_free(ptr) */ - return talloc_realloc_size(pw, ptr, len); -} - -binding_error binding_create_tree(void *arena, const char *charset, void **ctx) -{ - hubbub_ctx *c; - hubbub_parser_optparams params; - uint32_t i; - hubbub_error error; - - c = malloc(sizeof(hubbub_ctx)); - if (c == NULL) - return BINDING_NOMEM; - - c->parser = NULL; - c->encoding = charset; - c->encoding_source = charset != NULL ? ENCODING_SOURCE_HEADER - : ENCODING_SOURCE_DETECTED; - c->document = NULL; - c->owns_doc = true; - c->quirks = BINDING_QUIRKS_MODE_NONE; - c->forms = NULL; - - error = hubbub_parser_create(charset, true, ns_talloc_based_realloc, - arena, &c->parser); - if (error != HUBBUB_OK) { - free(c); - if (error == HUBBUB_BADENCODING) - return BINDING_BADENCODING; - else - return BINDING_NOMEM; /* Assume OOM */ - } - - c->document = htmlNewDocNoDtD(NULL, NULL); - if (c->document == NULL) { - hubbub_parser_destroy(c->parser); - free(c); - return BINDING_NOMEM; - } - c->document->_private = create_private(0); - if (c->document->_private == NULL) { - xmlFreeDoc(c->document); - hubbub_parser_destroy(c->parser); - free(c); - return BINDING_NOMEM; - } - - for (i = 0; i < sizeof(c->namespaces) / sizeof(c->namespaces[0]); i++) { - c->namespaces[i] = NULL; - } - - c->tree_handler = tree_handler; - c->tree_handler.ctx = (void *) c; - - params.tree_handler = &c->tree_handler; - hubbub_parser_setopt(c->parser, HUBBUB_PARSER_TREE_HANDLER, ¶ms); - - ref_node(c, c->document); - params.document_node = c->document; - hubbub_parser_setopt(c->parser, HUBBUB_PARSER_DOCUMENT_NODE, ¶ms); - - *ctx = (void *) c; - - return BINDING_OK; -} - -binding_error binding_destroy_tree(void *ctx) -{ - hubbub_ctx *c = (hubbub_ctx *) ctx; - - if (ctx == NULL) - return BINDING_OK; - - if (c->parser != NULL) - hubbub_parser_destroy(c->parser); - - if (c->owns_doc) - binding_destroy_document(c->document); - - c->parser = NULL; - c->encoding = NULL; - c->document = NULL; - - free(c); - - return BINDING_OK; -} - -binding_error binding_parse_chunk(void *ctx, const uint8_t *data, size_t len) -{ - hubbub_ctx *c = (hubbub_ctx *) ctx; - hubbub_error err; - - err = hubbub_parser_parse_chunk(c->parser, (uint8_t *) data, len); - if (err == HUBBUB_ENCODINGCHANGE) - return BINDING_ENCODINGCHANGE; - - return err == HUBBUB_NOMEM ? BINDING_NOMEM : BINDING_OK; -} - -binding_error binding_parse_completed(void *ctx) -{ - hubbub_ctx *c = (hubbub_ctx *) ctx; - hubbub_error error; - - error = hubbub_parser_completed(c->parser); - - return error == HUBBUB_NOMEM ? BINDING_NOMEM : BINDING_OK; -} - -const char *binding_get_encoding(void *ctx, binding_encoding_source *source) -{ - hubbub_ctx *c = (hubbub_ctx *) ctx; - - *source = c->encoding_source; - - return c->encoding != NULL ? c->encoding : "Windows-1252"; -} - -xmlDocPtr binding_get_document(void *ctx, binding_quirks_mode *quirks) -{ - hubbub_ctx *c = (hubbub_ctx *) ctx; - xmlDocPtr doc = c->document; - - c->owns_doc = false; - - *quirks = c->quirks; - - return doc; -} - -struct form *binding_get_forms(void *ctx) -{ - hubbub_ctx *c = (hubbub_ctx *) ctx; - - return c->forms; -} - -struct form_control *binding_get_control_for_node(void *ctx, xmlNodePtr node) -{ - hubbub_ctx *c = (hubbub_ctx *) ctx; - struct form *f; - struct form_control *ctl = NULL; - - for (f = c->forms; f != NULL; f = f->prev) { - for (ctl = f->controls; ctl != NULL; ctl = ctl->next) { - if (ctl->node == node) - return ctl; - } - } - - /* No control found. This implies that it's not associated - * with any form. In this case, we create a control for it - * on the fly. */ - if (strcasecmp((const char *) node->name, "input") == 0) { - ctl = parse_input_element(node); - } else if (strcasecmp((const char *) node->name, "button") == 0) { - ctl = parse_button_element(node); - } else if (strcasecmp((const char *) node->name, "select") == 0) { - ctl = parse_select_element(node); - } else if (strcasecmp((const char *) node->name, "textarea") == 0) { - ctl = parse_textarea_element(node); - } - - return ctl; -} - -void binding_destroy_document(xmlDocPtr doc) -{ - xmlNode *n = (xmlNode *) doc; - - while (n != NULL) { - destroy_private(n->_private); - - if (n->children != NULL) { - n = n->children; - } else if (n->next != NULL) { - n = n->next; - } else { - while (n->parent != NULL && n->parent->next == NULL) - n = n->parent; - - if (n->parent != NULL) - n = n->parent->next; - else - n = NULL; - } - } - - xmlFreeDoc(doc); -} - -/*****************************************************************************/ - -hubbub_private *create_private(uint32_t refcnt) -{ - hubbub_private *pvt = calloc(1, sizeof(*pvt)); - - if (pvt != NULL) - pvt->refcnt = refcnt; - - return pvt; -} - -hubbub_private *copy_private(const hubbub_private *p, uint32_t refcnt) -{ - hubbub_private *pvt = calloc(1, sizeof(*pvt)); - - if (pvt != NULL) { - pvt->refcnt = refcnt; - - if (p->base.nclasses > 0) { - pvt->base.classes = - malloc(p->base.nclasses * sizeof(lwc_string *)); - if (pvt->base.classes == NULL) { - free(pvt); - return NULL; - } - - while (pvt->base.nclasses < p->base.nclasses) { - pvt->base.classes[pvt->base.nclasses] = - lwc_string_ref(p->base.classes[ - pvt->base.nclasses]); - pvt->base.nclasses++; - } - } - - if (p->base.localname != NULL) - pvt->base.localname = lwc_string_ref(p->base.localname); - - if (p->base.id != NULL) - pvt->base.id = lwc_string_ref(p->base.id); - } - - return pvt; -} - -void destroy_private(hubbub_private *p) -{ - if (p->base.localname != NULL) - lwc_string_unref(p->base.localname); - - if (p->base.id != NULL) - lwc_string_unref(p->base.id); - - while (p->base.nclasses > 0) - lwc_string_unref(p->base.classes[--p->base.nclasses]); - - if (p->base.classes != NULL) - free(p->base.classes); - - free(p); -} - -char *c_string_from_hubbub_string(hubbub_ctx *ctx, const hubbub_string *str) -{ - return strndup((const char *) str->ptr, (int) str->len); -} - -void create_namespaces(hubbub_ctx *ctx, xmlNode *root) -{ - uint32_t i; - - for (i = 1; i < sizeof(namespaces) / sizeof(namespaces[0]); i++) { - ctx->namespaces[i - 1] = xmlNewNs(root, - BAD_CAST namespaces[i].url, - BAD_CAST namespaces[i].prefix); - - if (ctx->namespaces[i - 1] == NULL) { - LOG(("Failed creating namespace %s\n", - namespaces[i].prefix)); - } - } -} - -hubbub_error create_comment(void *ctx, const hubbub_string *data, void **result) -{ - hubbub_ctx *c = (hubbub_ctx *) ctx; - char *content; - xmlNodePtr n; - - content = c_string_from_hubbub_string(c, data); - if (content == NULL) - return HUBBUB_NOMEM; - - n = xmlNewDocComment(c->document, BAD_CAST content); - if (n == NULL) { - free(content); - return HUBBUB_NOMEM; - } - n->_private = create_private(1); - if (n->_private == NULL) { - xmlFreeNode(n); - free(content); - return HUBBUB_NOMEM; - } - - free(content); - - *result = (void *) n; - - return HUBBUB_OK; -} - -hubbub_error create_doctype(void *ctx, const hubbub_doctype *doctype, - void **result) -{ - hubbub_ctx *c = (hubbub_ctx *) ctx; - char *name, *public = NULL, *system = NULL; - xmlDtdPtr n; - - name = c_string_from_hubbub_string(c, &doctype->name); - if (name == NULL) - return HUBBUB_NOMEM; - - if (!doctype->public_missing) { - public = c_string_from_hubbub_string(c, &doctype->public_id); - if (public == NULL) { - free(name); - return HUBBUB_NOMEM; - } - } - - if (!doctype->system_missing) { - system = c_string_from_hubbub_string(c, &doctype->system_id); - if (system == NULL) { - free(public); - free(name); - return HUBBUB_NOMEM; - } - } - - n = xmlNewDtd(c->document, BAD_CAST name, - BAD_CAST (public ? public : ""), - BAD_CAST (system ? system : "")); - if (n == NULL) { - free(system); - free(public); - free(name); - return HUBBUB_NOMEM; - } - n->_private = create_private(1); - if (n->_private == NULL) { - xmlFreeDtd(n); - free(system); - free(public); - free(name); - return HUBBUB_NOMEM; - } - - *result = (void *) n; - - free(system); - free(public); - free(name); - - return HUBBUB_OK; -} - -hubbub_error create_element(void *ctx, const hubbub_tag *tag, void **result) -{ - hubbub_ctx *c = (hubbub_ctx *) ctx; - lwc_string *iname; - xmlNodePtr n; - - if (lwc_intern_string((const char *) tag->name.ptr, tag->name.len, - &iname) != lwc_error_ok) { - return HUBBUB_NOMEM; - } - - if (c->namespaces[0] != NULL) { - n = xmlNewDocNode(c->document, c->namespaces[tag->ns - 1], - BAD_CAST lwc_string_data(iname), NULL); - } else { - n = xmlNewDocNode(c->document, NULL, - BAD_CAST lwc_string_data(iname), NULL); - - /* We're creating the root node of the document. Therefore, - * create the namespaces and set this node's namespace */ - if (n != NULL && c->namespaces[0] == NULL) { - create_namespaces(c, (void *) n); - - xmlSetNs(n, c->namespaces[tag->ns - 1]); - } - } - if (n == NULL) { - lwc_string_unref(iname); - return HUBBUB_NOMEM; - } - n->_private = create_private(1); - if (n->_private == NULL) { - xmlFreeNode(n); - lwc_string_unref(iname); - return HUBBUB_NOMEM; - } - - if (tag->n_attributes > 0 && add_attributes(ctx, (void *) n, - tag->attributes, tag->n_attributes) != HUBBUB_OK) { - destroy_private(n->_private); - xmlFreeNode(n); - lwc_string_unref(iname); - return HUBBUB_NOMEM; - } - - if (lwc_string_length(iname) == SLEN("form") && - strcasecmp(lwc_string_data(iname), "form") == 0) { - struct form *form = parse_form_element(n, c->encoding); - - /* Memory exhaustion */ - if (form == NULL) { - destroy_private(n->_private); - xmlFreeNode(n); - lwc_string_unref(iname); - return HUBBUB_NOMEM; - } - - /* Insert into list */ - form->prev = c->forms; - c->forms = form; - } - - ((binding_private *) n->_private)->localname = iname; - - *result = (void *) n; - - return HUBBUB_OK; -} - -hubbub_error create_text(void *ctx, const hubbub_string *data, void **result) -{ - hubbub_ctx *c = (hubbub_ctx *) ctx; - xmlNodePtr n; - - n = xmlNewDocTextLen(c->document, BAD_CAST data->ptr, (int) data->len); - if (n == NULL) { - return HUBBUB_NOMEM; - } - n->_private = create_private(1); - if (n->_private == NULL) { - xmlFreeNode(n); - return HUBBUB_NOMEM; - } - - *result = (void *) n; - - return HUBBUB_OK; -} - -hubbub_error ref_node(void *ctx, void *node) -{ - hubbub_ctx *c = (hubbub_ctx *) ctx; - hubbub_private *pvt; - - if (node == c->document) { - xmlDoc *n = (xmlDoc *) node; - pvt = n->_private; - - pvt->refcnt++; - } else { - xmlNode *n = (xmlNode *) node; - pvt = n->_private; - - pvt->refcnt++; - } - - return HUBBUB_OK; -} - -hubbub_error unref_node(void *ctx, void *node) -{ - hubbub_ctx *c = (hubbub_ctx *) ctx; - hubbub_private *pvt; - - if (node == c->document) { - xmlDoc *n = (xmlDoc *) node; - pvt = n->_private; - - assert(pvt->refcnt != 0 && "Node has refcount of zero"); - - pvt->refcnt--; - } else { - xmlNode *n = (xmlNode *) node; - pvt = n->_private; - - assert(pvt->refcnt != 0 && "Node has refcount of zero"); - - pvt->refcnt--; - - if (pvt->refcnt == 0 && n->parent == NULL) { - destroy_private(pvt); - xmlFreeNode(n); - } - } - - return HUBBUB_OK; -} - -hubbub_error append_child(void *ctx, void *parent, void *child, void **result) -{ - xmlNode *chld = (xmlNode *) child; - xmlNode *p = (xmlNode *) parent; - - /** \todo Text node merging logic as per - * http://www.whatwg.org/specs/web-apps/current-work/multipage/ \ - * tree-construction.html#insert-a-character - * - * Doesn't actually matter for us until we have scripting. Thus, - * this is something which can wait until libdom. - */ - if (chld->type == XML_TEXT_NODE && p->last != NULL && - p->last->type == XML_TEXT_NODE) { - /* Need to clone the child, as libxml will free it if it - * merges the content with a pre-existing text node. */ - chld = xmlCopyNode(chld, 0); - if (chld == NULL) - return HUBBUB_NOMEM; - - *result = xmlAddChild(p, chld); - - assert(*result != (void *) chld); - } else { - *result = xmlAddChild(p, chld); - } - - if (*result == NULL) - return HUBBUB_NOMEM; - - ref_node(ctx, *result); - - return HUBBUB_OK; -} - -hubbub_error insert_before(void *ctx, void *parent, void *child, - void *ref_child, void **result) -{ - xmlNode *chld = (xmlNode *) child; - xmlNode *ref = (xmlNode *) ref_child; - - if (chld->type == XML_TEXT_NODE && ref->prev != NULL && - ref->prev->type == XML_TEXT_NODE) { - /* Clone text node, as it'll be freed by libxml */ - chld = xmlCopyNode(chld, 0); - if (chld == NULL) - return HUBBUB_NOMEM; - - *result = xmlAddNextSibling(ref->prev, chld); - - assert(*result != (void *) chld); - } else { - *result = xmlAddPrevSibling(ref, chld); - } - - if (*result == NULL) - return HUBBUB_NOMEM; - - ref_node(ctx, *result); - - return HUBBUB_OK; -} - -hubbub_error remove_child(void *ctx, void *parent, void *child, void **result) -{ - xmlNode *chld = (xmlNode *) child; - - xmlUnlinkNode(chld); - - *result = child; - - ref_node(ctx, *result); - - return HUBBUB_OK; -} - -hubbub_error clone_node(void *ctx, void *node, bool deep, void **result) -{ - xmlNode *n = (xmlNode *) node; - xmlNode *clonedtree; - - /* Shallow clone node */ - clonedtree = xmlCopyNode(n, 2); - if (clonedtree == NULL) - return HUBBUB_NOMEM; - - clonedtree->_private = copy_private(n->_private, 1); - if (clonedtree->_private == NULL) { - xmlFreeNode(clonedtree); - return HUBBUB_NOMEM; - } - - /* Iteratively clone children too, if required */ - if (deep && n->children != NULL) { - xmlNode *parent = clonedtree, *copy; - - n = n->children; - - while (n != node) { - copy = xmlCopyNode(n, 2); - if (copy == NULL) - goto error; - - copy->_private = copy_private(n->_private, 0); - if (copy->_private == NULL) { - xmlFreeNode(copy); - goto error; - } - - xmlAddChild(parent, copy); - - if (n->children != NULL) { - parent = copy; - n = n->children; - } else if (n->next != NULL) { - n = n->next; - } else { - while (n->parent != node && - n->parent->next == NULL) { - parent = parent->parent; - n = n->parent; - } - - if (n->parent != node) { - parent = parent->parent; - n = n->parent->next; - } else - n = node; - } - } - } - - *result = clonedtree; - - return HUBBUB_OK; - -error: - n = clonedtree; - - while (n != NULL) { - destroy_private(n->_private); - - if (n->children != NULL) { - n = n->children; - } else if (n->next != NULL) { - n = n->next; - } else { - while (n->parent != NULL && n->parent->next == NULL) { - n = n->parent; - } - - if (n->parent != NULL) - n = n->parent->next; - else - n = NULL; - } - } - - xmlFreeNode(clonedtree); - - return HUBBUB_NOMEM; -} - -hubbub_error reparent_children(void *ctx, void *node, void *new_parent) -{ - xmlNode *n = (xmlNode *) node; - xmlNode *p = (xmlNode *) new_parent; - xmlNode *child; - - for (child = n->children; child != NULL; ) { - xmlNode *next = child->next; - - xmlUnlinkNode(child); - - if (xmlAddChild(p, child) == NULL) - return HUBBUB_NOMEM; - - child = next; - } - - return HUBBUB_OK; -} - -hubbub_error get_parent(void *ctx, void *node, bool element_only, void **result) -{ - xmlNode *n = (xmlNode *) node; - - *result = (void *) n->parent; - - if (*result != NULL && element_only && - ((xmlNode *) *result)->type != XML_ELEMENT_NODE) { - *result = NULL; - } - - if (*result != NULL) - ref_node(ctx, *result); - - return HUBBUB_OK; -} - -hubbub_error has_children(void *ctx, void *node, bool *result) -{ - xmlNode *n = (xmlNode *) node; - - *result = n->children != NULL; - - return HUBBUB_OK; -} - -hubbub_error form_associate(void *ctx, void *form, void *node) -{ - hubbub_ctx *c = (hubbub_ctx *) ctx; - xmlNode *n = (xmlNode *) node; - struct form *f; - struct form_control *control = NULL; - xmlChar *id = NULL; - - /* Find form object to associate with: - * - * 1) If node possesses an @form, use the form with a matching @id - * 2) Otherwise, use the form provided - */ - id = xmlGetProp(n, (const xmlChar *) "form"); - for (f = c->forms; f != NULL; f = f->prev) { - if (id == NULL && f->node == form) { - break; - } else if (id != NULL) { - xmlNode *fn = (xmlNode *) f->node; - xmlChar *fid = xmlGetProp(fn, (const xmlChar *) "id"); - - if (fid != NULL && strcmp((char *) id, - (char *) fid) == 0) { - xmlFree(fid); - break; - } else if (fid != NULL) { - xmlFree(fid); - } - } - } - if (id != NULL) - xmlFree(id); - - /* None found -- give up */ - if (f == NULL) - return HUBBUB_OK; - - /* Will be one of: button, fieldset, input, label, - * output, select, textarea. - * - * We ignore fieldset, label and output. - */ - if (strcasecmp((const char *) n->name, "input") == 0) { - control = parse_input_element(n); - } else if (strcasecmp((const char *) n->name, "button") == 0) { - control = parse_button_element(n); - } else if (strcasecmp((const char *) n->name, "select") == 0) { - control = parse_select_element(n); - } else if (strcasecmp((const char *) n->name, "textarea") == 0) { - control = parse_textarea_element(n); - } else - return HUBBUB_OK; - - /* Memory exhaustion */ - if (control == NULL) - return HUBBUB_NOMEM; - - /* Add the control to the form */ - form_add_control(f, control); - - return HUBBUB_OK; -} - -static hubbub_error parse_class_attr(lwc_string *value, - lwc_string ***classes, uint32_t *nclasses) -{ - const char *pv; - lwc_string **cls = NULL; - uint32_t count = 0; - - /* Count number of classes */ - for (pv = lwc_string_data(value); *pv != '\0'; ) { - if (*pv != ' ') { - while (*pv != ' ' && *pv != '\0') - pv++; - count++; - } else { - while (*pv == ' ') - pv++; - } - } - - /* If there are some, unpack them */ - if (count > 0) { - cls = malloc(count * sizeof(lwc_string *)); - if (cls == NULL) - return HUBBUB_NOMEM; - - for (pv = lwc_string_data(value), count = 0; *pv != '\0'; ) { - if (*pv != ' ') { - const char *s = pv; - while (*pv != ' ' && *pv != '\0') - pv++; - if (lwc_intern_string(s, pv - s, - &cls[count]) != lwc_error_ok) - goto error; - count++; - } else { - while (*pv == ' ') - pv++; - } - } - } - - *classes = cls; - *nclasses = count; - - return HUBBUB_OK; -error: - while (count > 0) - lwc_string_unref(cls[--count]); - - free(cls); - - return HUBBUB_NOMEM; -} - -hubbub_error add_attributes(void *ctx, void *node, - const hubbub_attribute *attributes, uint32_t n_attributes) -{ - hubbub_ctx *c = (hubbub_ctx *) ctx; - xmlNode *n = (xmlNode *) node; - binding_private *p = n->_private; - uint32_t attr; - - for (attr = 0; attr < n_attributes; attr++) { - xmlAttr *prop; - lwc_string *name, *value; - - if (lwc_intern_string((const char *) attributes[attr].name.ptr, - attributes[attr].name.len, - &name) != lwc_error_ok) - return HUBBUB_NOMEM; - - if (lwc_intern_string((const char *) attributes[attr].value.ptr, - attributes[attr].value.len, - &value) != lwc_error_ok) { - lwc_string_unref(name); - return HUBBUB_NOMEM; - } - - if (attributes[attr].ns != HUBBUB_NS_NULL && - c->namespaces[0] != NULL) { - prop = xmlNewNsProp(n, - c->namespaces[attributes[attr].ns - 1], - BAD_CAST lwc_string_data(name), - BAD_CAST lwc_string_data(value)); - } else { - prop = xmlNewProp(n, BAD_CAST lwc_string_data(name), - BAD_CAST lwc_string_data(value)); - } - - /* Handle @id / @class */ - if (p->id == NULL && lwc_string_length(name) == SLEN("id") && - strcasecmp(lwc_string_data(name), "id") == 0) { - p->id = lwc_string_ref(value); - } else if (p->nclasses == 0 && - lwc_string_length(name) == SLEN("class") && - strcasecmp(lwc_string_data(name), - "class") == 0) { - hubbub_error error; - - error = parse_class_attr(value, &p->classes, - &p->nclasses); - if (error != HUBBUB_OK) { - lwc_string_unref(value); - lwc_string_unref(name); - return error; - } - } - - lwc_string_unref(value); - lwc_string_unref(name); - - if (prop == NULL) { - return HUBBUB_NOMEM; - } - } - - return HUBBUB_OK; -} - -hubbub_error set_quirks_mode(void *ctx, hubbub_quirks_mode mode) -{ - hubbub_ctx *c = (hubbub_ctx *) ctx; - - switch (mode) { - case HUBBUB_QUIRKS_MODE_NONE: - c->quirks = BINDING_QUIRKS_MODE_NONE; - break; - case HUBBUB_QUIRKS_MODE_LIMITED: - c->quirks = BINDING_QUIRKS_MODE_LIMITED; - break; - case HUBBUB_QUIRKS_MODE_FULL: - c->quirks = BINDING_QUIRKS_MODE_FULL; - break; - } - - return HUBBUB_OK; -} - -hubbub_error change_encoding(void *ctx, const char *charset) -{ - hubbub_ctx *c = (hubbub_ctx *) ctx; - uint32_t source; - const char *name; - - /* If we have an encoding here, it means we are *certain* */ - if (c->encoding != NULL) { - return HUBBUB_OK; - } - - /* Find the confidence otherwise (can only be from a BOM) */ - name = hubbub_parser_read_charset(c->parser, &source); - - if (source == HUBBUB_CHARSET_CONFIDENT) { - c->encoding_source = ENCODING_SOURCE_DETECTED; - c->encoding = (char *) charset; - return HUBBUB_OK; - } - - /* So here we have something of confidence tentative... */ - /* http://www.whatwg.org/specs/web-apps/current-work/#change */ - - /* 2. "If the new encoding is identical or equivalent to the encoding - * that is already being used to interpret the input stream, then set - * the confidence to confident and abort these steps." */ - - /* Whatever happens, the encoding should be set here; either for - * reprocessing with a different charset, or for confirming that the - * charset is in fact correct */ - c->encoding = charset; - c->encoding_source = ENCODING_SOURCE_META; - - /* Equal encodings will have the same string pointers */ - return (charset == name) ? HUBBUB_OK : HUBBUB_ENCODINGCHANGE; -} - -struct form *parse_form_element(xmlNode *node, const char *docenc) -{ - struct form *form; - form_method method; - xmlChar *action, *meth, *charset, *target; - - action = xmlGetProp(node, (const xmlChar *) "action"); - charset = xmlGetProp(node, (const xmlChar *) "accept-charset"); - target = xmlGetProp(node, (const xmlChar *) "target"); - - method = method_GET; - meth = xmlGetProp(node, (const xmlChar *) "method"); - if (meth != NULL) { - if (strcasecmp((char *) meth, "post") == 0) { - xmlChar *enctype; - - method = method_POST_URLENC; - - enctype = xmlGetProp(node, (const xmlChar *) "enctype"); - if (enctype != NULL) { - if (strcasecmp((char *) enctype, - "multipart/form-data") == 0) - method = method_POST_MULTIPART; - - xmlFree(enctype); - } - } - xmlFree(meth); - } - - form = form_new(node, (char *) action, (char *) target, method, - (char *) charset, docenc); - - if (target != NULL) - xmlFree(target); - if (charset != NULL) - xmlFree(charset); - if (action != NULL) - xmlFree(action); - - return form; -} - -struct form_control *parse_input_element(xmlNode *node) -{ - struct form_control *control = NULL; - xmlChar *type = xmlGetProp(node, (const xmlChar *) "type"); - xmlChar *name; - - if (type != NULL && strcasecmp((char *) type, "password") == 0) { - control = form_new_control(node, GADGET_PASSWORD); - } else if (type != NULL && strcasecmp((char *) type, "file") == 0) { - control = form_new_control(node, GADGET_FILE); - } else if (type != NULL && strcasecmp((char *) type, "hidden") == 0) { - control = form_new_control(node, GADGET_HIDDEN); - } else if (type != NULL && strcasecmp((char *) type, "checkbox") == 0) { - control = form_new_control(node, GADGET_CHECKBOX); - } else if (type != NULL && strcasecmp((char *) type, "radio") == 0) { - control = form_new_control(node, GADGET_RADIO); - } else if (type != NULL && strcasecmp((char *) type, "submit") == 0) { - control = form_new_control(node, GADGET_SUBMIT); - } else if (type != NULL && strcasecmp((char *) type, "reset") == 0) { - control = form_new_control(node, GADGET_RESET); - } else if (type != NULL && strcasecmp((char *) type, "button") == 0) { - control = form_new_control(node, GADGET_BUTTON); - } else if (type != NULL && strcasecmp((char *) type, "image") == 0) { - control = form_new_control(node, GADGET_IMAGE); - } else { - control = form_new_control(node, GADGET_TEXTBOX); - } - - xmlFree(type); - - if (control == NULL) - return NULL; - - if (control->type == GADGET_CHECKBOX || control->type == GADGET_RADIO) { - control->selected = - xmlHasProp(node, (const xmlChar *) "checked") != NULL; - } - - if (control->type == GADGET_PASSWORD || - control->type == GADGET_TEXTBOX) { - xmlChar *len = xmlGetProp(node, (const xmlChar *) "maxlength"); - if (len != NULL) { - if (len[0] != '\0') - control->maxlength = atoi((char *) len); - xmlFree(len); - } - } - - if (control->type != GADGET_FILE && control->type != GADGET_IMAGE) { - xmlChar *value = xmlGetProp(node, (const xmlChar *) "value"); - if (value != NULL) { - control->value = strdup((char *) value); - - xmlFree(value); - - if (control->value == NULL) { - form_free_control(control); - return NULL; - } - - control->length = strlen(control->value); - } - - if (control->type == GADGET_TEXTBOX || - control->type == GADGET_PASSWORD) { - if (control->value == NULL) { - control->value = strdup(""); - if (control->value == NULL) { - form_free_control(control); - return NULL; - } - - control->length = 0; - } - - control->initial_value = strdup(control->value); - if (control->initial_value == NULL) { - form_free_control(control); - return NULL; - } - } - } - - name = xmlGetProp(node, (const xmlChar *) "name"); - if (name != NULL) { - control->name = strdup((char *) name); - - xmlFree(name); - - if (control->name == NULL) { - form_free_control(control); - return NULL; - } - } - - return control; -} - -struct form_control *parse_button_element(xmlNode *node) -{ - struct form_control *control; - xmlChar *type = xmlGetProp(node, (const xmlChar *) "type"); - xmlChar *name; - xmlChar *value; - - if (type == NULL || strcasecmp((char *) type, "submit") == 0) { - control = form_new_control(node, GADGET_SUBMIT); - } else if (strcasecmp((char *) type, "reset") == 0) { - control = form_new_control(node, GADGET_RESET); - } else { - control = form_new_control(node, GADGET_BUTTON); - } - - xmlFree(type); - - if (control == NULL) - return NULL; - - value = xmlGetProp(node, (const xmlChar *) "value"); - if (value != NULL) { - control->value = strdup((char *) value); - - xmlFree(value); - - if (control->value == NULL) { - form_free_control(control); - return NULL; - } - } - - name = xmlGetProp(node, (const xmlChar *) "name"); - if (name != NULL) { - control->name = strdup((char *) name); - - xmlFree(name); - - if (control->name == NULL) { - form_free_control(control); - return NULL; - } - } - - return control; -} - -struct form_control *parse_select_element(xmlNode *node) -{ - struct form_control *control = form_new_control(node, GADGET_SELECT); - xmlChar *name; - - if (control == NULL) - return NULL; - - control->data.select.multiple = - xmlHasProp(node, (const xmlChar *) "multiple") != NULL; - - name = xmlGetProp(node, (const xmlChar *) "name"); - if (name != NULL) { - control->name = strdup((char *) name); - - xmlFree(name); - - if (control->name == NULL) { - form_free_control(control); - return NULL; - } - } - - return control; -} - -struct form_control *parse_textarea_element(xmlNode *node) -{ - struct form_control *control = form_new_control(node, GADGET_TEXTAREA); - xmlChar *name; - - if (control == NULL) - return NULL; - - name = xmlGetProp(node, (const xmlChar *) "name"); - if (name != NULL) { - control->name = strdup((char *) name); - - xmlFree(name); - - if (control->name == NULL) { - form_free_control(control); - return NULL; - } - } - - return control; -} - |