diff --git a/render/box.h b/render/box.h index 285dfddd2..b0c7d2ed7 100644 --- a/render/box.h +++ b/render/box.h @@ -337,7 +337,7 @@ bool box_handle_scrollbars(struct content *c, struct box *box, bool box_vscrollbar_present(const struct box *box); bool box_hscrollbar_present(const struct box *box); -bool xml_to_box(xmlNode *n, struct html_content *c, +bool xml_to_box(dom_node *n, struct html_content *c, box_construct_complete_cb cb); bool box_normalise_block(struct box *block, struct html_content *c); diff --git a/render/box_construct.c b/render/box_construct.c index efb886e9f..7176350eb 100644 --- a/render/box_construct.c +++ b/render/box_construct.c @@ -195,14 +195,70 @@ static const box_type box_map[] = { BOX_NONE /*CSS_DISPLAY_NONE*/ }; -static inline struct box *box_for_node(const dom_node *n) +/** \todo: initialise/finalise */ +/** Key for box userdata on DOM elements (== '__ns_box') */ +static dom_string *kstr_box_key; +static dom_string *kstr_title; +static dom_string *kstr_id; +static dom_string *kstr_colspan; +static dom_string *kstr_rowspan; +static dom_string *kstr_style; +static dom_string *kstr_href; +static dom_string *kstr_name; +static dom_string *kstr_target; +static dom_string *kstr_alt; +static dom_string *kstr_src; +static dom_string *kstr_codebase; +static dom_string *kstr_classid; +static dom_string *kstr_data; +static dom_string *kstr_rows; +static dom_string *kstr_cols; +static dom_string *kstr_border; +static dom_string *kstr_frameborder; +static dom_string *kstr_bordercolor; +static dom_string *kstr_noresize; +static dom_string *kstr_scrolling; +static dom_string *kstr_marginwidth; +static dom_string *kstr_marginheight; +static dom_string *kstr_type; +static dom_string *kstr_value; +static dom_string *kstr_selected; + +static inline struct box *box_for_node(dom_node *n) { - return ((binding_private *) n->_private)->box; + struct box *box = NULL; + dom_exception err; + + err = dom_node_get_user_data(n, kstr_box_key, &box); + if (err != DOM_NO_ERR) + return NULL; + + return box; } -static inline bool box_is_root(const dom_done *n) +static inline bool box_is_root(dom_node *n) { - return n->parent == NULL || n->parent->type == XML_HTML_DOCUMENT_NODE; + dom_node *parent; + dom_node_type type; + dom_exception err; + + err = dom_node_get_parent_node(n, &parent); + if (err != DOM_NO_ERR) + return false; + + if (parent != NULL) { + err = dom_node_get_node_type(parent, &type); + + dom_node_unref(parent); + + if (err != DOM_NO_ERR) + return false; + + if (type != DOM_DOCUMENT_NODE) + return false; + } + + return true; } /** @@ -213,36 +269,105 @@ static inline bool box_is_root(const dom_done *n) * \param content Containing content * \param convert_children Whether to consider children of \a n * \return Next node to process, or NULL if complete + * + * \note \a n will be unreferenced */ -static dom_node *next_node(dome_node *n, html_content *content, +static dom_node *next_node(dom_node *n, html_content *content, bool convert_children) { dom_node *next = NULL; + bool has_children; + dom_exception err; - if (convert_children && n->children != NULL) { - next = n->children; - } else if (n->next != NULL) { - if (box_for_node(n) != NULL) - box_construct_element_after(n, content); + err = dom_node_has_child_nodes(n, &has_children); + if (err != DOM_NO_ERR) { + dom_node_unref(n); + return NULL; + } - next = n->next; + if (convert_children && has_children) { + err = dom_node_get_first_child(n, &next); + if (err != DOM_NO_ERR) { + dom_node_unref(n); + return NULL; + } } else { - if (box_for_node(n) != NULL) - box_construct_element_after(n, content); - - while (box_is_root(n) == false && n->parent->next == NULL) { - n = n->parent; - - if (box_for_node(n) != NULL) - box_construct_element_after(n, content); + err = dom_node_get_next_sibling(n, &next); + if (err != DOM_NO_ERR) { + dom_node_unref(n); + return NULL; } - if (box_is_root(n) == false) { - if (box_for_node(n->parent) != NULL) { - box_construct_element_after(n->parent, content); + if (next != NULL) { + if (box_for_node(n) != NULL) + box_construct_element_after(n, content); + dom_node_unref(n); + } else { + if (box_for_node(n) != NULL) + box_construct_element_after(n, content); + + while (box_is_root(n) == false) { + dom_node *parent = NULL; + dom_node *parent_next = NULL; + + err = dom_node_get_parent_node(n, &parent); + if (err != DOM_NO_ERR) { + dom_node_unref(n); + return NULL; + } + + assert(parent != NULL); + + err = dom_node_get_next_sibling(parent, + &parent_next); + if (err != DOM_NO_ERR) { + dom_node_unref(parent); + dom_node_unref(n); + return NULL; + } + + if (parent_next != NULL) { + dom_node_unref(parent_next); + break; + } + + dom_node_unref(n); + n = parent; + parent = NULL; + + if (box_for_node(n) != NULL) { + box_construct_element_after( + n, content); + } } - next = n->parent->next; + if (box_is_root(n) == false) { + dom_node *parent = NULL; + + err = dom_node_get_parent_node(n, &parent); + if (err != DOM_NO_ERR) { + dom_node_unref(n); + return NULL; + } + + assert(parent != NULL); + + err = dom_node_get_next_sibling(parent, &next); + if (err != DOM_NO_ERR) { + dom_node_unref(parent); + dom_node_unref(n); + return NULL; + } + + if (box_for_node(parent) != NULL) { + box_construct_element_after(parent, + content); + } + + dom_node_unref(parent); + } + + dom_node_unref(n); } } @@ -264,21 +389,36 @@ void convert_xml_to_box(struct box_construct_ctx *ctx) convert_children = true; assert(ctx->n != NULL); - assert(ctx->n->type == XML_ELEMENT_NODE); if (box_construct_element(ctx, &convert_children) == false) { ctx->cb(ctx->content, false); + dom_node_unref(ctx->n); free(ctx); return; } /* Find next element to process, converting text nodes as we go */ next = next_node(ctx->n, ctx->content, convert_children); - while (next != NULL && next->type != XML_ELEMENT_NODE) { - if (next->type == XML_TEXT_NODE) { + while (next != NULL) { + dom_node_type type; + dom_exception err; + + err = dom_node_get_node_type(next, &type); + if (err != DOM_NO_ERR) { + ctx->cb(ctx->content, false); + dom_node_unref(next); + free(ctx); + return; + } + + if (type == DOM_ELEMENT_NODE) + break; + + if (type == DOM_TEXT_NODE) { ctx->n = next; if (box_construct_text(ctx) == false) { ctx->cb(ctx->content, false); + dom_node_unref(ctx->n); free(ctx); return; } @@ -309,6 +449,8 @@ void convert_xml_to_box(struct box_construct_ctx *ctx) ctx->cb(ctx->content, true); } + assert(ctx->n == NULL); + free(ctx); return; } @@ -488,7 +630,7 @@ static void box_construct_generate(dom_node *n, html_content *content, * \param n Current DOM node to convert * \param props Property object to populate */ -static void box_extract_properties(const dom_node *n, +static void box_extract_properties(dom_node *n, struct box_construct_props *props) { memset(props, 0, sizeof(*props)); @@ -497,22 +639,52 @@ static void box_extract_properties(const dom_node *n, /* Extract properties from containing DOM node */ if (props->node_is_root == false) { + dom_node *current_node = n; + dom_node *parent_node = NULL; struct box *parent_box; + dom_exception err; /* Find ancestor node containing parent box */ - while (n->parent != NULL && box_for_node(n->parent) == NULL) - n = n->parent; + while (true) { + err = dom_node_get_parent_node(current_node, + &parent_node); + if (err != DOM_NO_ERR || parent_node == NULL) + break; - parent_box = box_for_node(n->parent); + parent_box = box_for_node(parent_node); - props->parent_style = parent_box->style; - props->href = parent_box->href; - props->target = parent_box->target; - props->title = parent_box->title; + if (parent_box != NULL) { + props->parent_style = parent_box->style; + props->href = parent_box->href; + props->target = parent_box->target; + props->title = parent_box->title; + dom_node_unref(parent_node); + break; + } else { + if (current_node != n) + dom_node_unref(current_node); + current_node = parent_node; + parent_node = NULL; + } + } + /* Find containing block (may be parent) */ - for (n = n->parent; n != NULL; n = n->parent) { - struct box *b = box_for_node(n); + while (true) { + struct box *b; + + err = dom_node_get_parent_node(current_node, + &parent_node); + if (err != DOM_NO_ERR || parent_node == NULL) { + if (current_node != n) + dom_node_unref(current_node); + break; + } + + if (current_node != n) + dom_node_unref(current_node); + + b = box_for_node(parent_node); /* Children of nodes that created an inline box * will generate boxes which are attached as @@ -523,7 +695,12 @@ static void box_extract_properties(const dom_node *n, if (b != NULL && b->type != BOX_INLINE && b->type != BOX_BR) { props->containing_block = b; + + dom_node_unref(parent_node); break; + } else { + current_node = parent_node; + parent_node = NULL; } } } @@ -547,16 +724,16 @@ static void box_extract_properties(const dom_node *n, bool box_construct_element(struct box_construct_ctx *ctx, bool *convert_children) { - xmlChar *title0, *s; + dom_string *title0, *s; lwc_string *id = NULL; - struct box *box = NULL; + struct box *box = NULL, *old_box; css_select_results *styles = NULL; struct element_entry *element; lwc_string *bgimage_uri; + dom_exception err; struct box_construct_props props; assert(ctx->n != NULL); - assert(ctx->n->type == XML_ELEMENT_NODE); box_extract_properties(ctx->n, &props); @@ -572,10 +749,14 @@ bool box_construct_element(struct box_construct_ctx *ctx, return false; /* Extract title attribute, if present */ - if ((title0 = xmlGetProp(ctx->n, (const xmlChar *) "title")) != NULL) { - char *t = squash_whitespace((char *) title0); + err = dom_element_get_attribute(ctx->n, kstr_title, &title0); + if (err != DOM_NO_ERR) + return false; - xmlFree(title0); + if (title0 != NULL) { + char *t = squash_whitespace(dom_string_data(title0)); + + dom_string_unref(title0); if (t == NULL) return false; @@ -589,14 +770,16 @@ bool box_construct_element(struct box_construct_ctx *ctx, } /* Extract id attribute, if present */ - s = xmlGetProp(ctx->n, (const xmlChar *) "id"); - if (s) { - lwc_error lerror = lwc_intern_string((const char *) s, - strlen((const char *) s), &id); - xmlFree(s); + err = dom_element_get_attribute(ctx->n, kstr_id, &s); + if (err != DOM_NO_ERR) + return false; - if (lerror != lwc_error_ok) + if (s != NULL) { + err = dom_string_intern(s, &id); + if (err != DOM_NO_ERR) id = NULL; + + dom_string_unref(s); } box = box_create(styles, styles->styles[CSS_PSEUDO_ELEMENT_NONE], false, @@ -610,18 +793,30 @@ bool box_construct_element(struct box_construct_ctx *ctx, ctx->root_box = box; /* Deal with colspan/rowspan */ - if ((s = xmlGetProp(ctx->n, (const xmlChar *) "colspan")) != NULL) { - if ('0' <= s[0] && s[0] <= '9') - box->columns = strtol((char *) s, NULL, 10); + err = dom_element_get_attribute(ctx->n, kstr_colspan, &s); + if (err != DOM_NO_ERR) + return false; - xmlFree(s); + if (s != NULL) { + const char *val = dom_string_data(s); + + if ('0' <= val[0] && val[0] <= '9') + box->columns = strtol(val, NULL, 10); + + dom_string_unref(s); } - if ((s = xmlGetProp(ctx->n, (const xmlChar *) "rowspan")) != NULL) { - if ('0' <= s[0] && s[0] <= '9') - box->rows = strtol((char *) s, NULL, 10); + err = dom_element_get_attribute(ctx->n, kstr_rowspan, &s); + if (err != DOM_NO_ERR) + return false; - xmlFree(s); + if (s != NULL) { + const char *val = dom_string_data(s); + + if ('0' <= val[0] && val[0] <= '9') + box->rows = strtol(val, NULL, 10); + + dom_string_unref(s); } /* Set box type from computed display */ @@ -649,10 +844,17 @@ bool box_construct_element(struct box_construct_ctx *ctx, box_construct_generate(ctx->n, ctx->content, box, box->styles->styles[CSS_PSEUDO_ELEMENT_BEFORE]); + err = dom_node_get_node_name(ctx->n, &s); + if (err != DOM_NO_ERR || s == NULL) + return false; + /* Special elements */ - element = bsearch((const char *) ctx->n->name, element_table, + element = bsearch(dom_string_data(s), element_table, ELEMENT_TABLE_COUNT, sizeof(element_table[0]), (int (*)(const void *, const void *)) strcmp); + + dom_string_unref(s); + if (element != NULL) { /* A special convert function exists for this element */ if (element->convert(ctx->n, ctx->content, box, @@ -683,7 +885,9 @@ bool box_construct_element(struct box_construct_ctx *ctx, } /* Attach box to DOM node */ - ((binding_private *) ctx->n->_private)->box = box; + err = dom_node_set_user_data(ctx->n, kstr_box_key, box, NULL, &old_box); + if (err != DOM_NO_ERR) + return false; if (props.inline_container == NULL && (box->type == BOX_INLINE || @@ -799,8 +1003,14 @@ void box_construct_element_after(dom_node *n, html_content *content) if (box->type == BOX_INLINE || box->type == BOX_BR) { /* Insert INLINE_END into containing block */ struct box *inline_end; + bool has_children; + dom_exception err; - if (n->children == NULL || + err = dom_node_has_child_nodes(n, &has_children); + if (err != DOM_NO_ERR) + return; + + if (has_children == false || (box->flags & CONVERT_CHILDREN) == 0) { /* No children, or didn't want children converted */ return; @@ -851,19 +1061,29 @@ bool box_construct_text(struct box_construct_ctx *ctx) { struct box_construct_props props; struct box *box = NULL; + dom_string *content; + dom_exception err; assert(ctx->n != NULL); - assert(ctx->n->type == XML_TEXT_NODE); box_extract_properties(ctx->n, &props); assert(props.containing_block != NULL); + err = dom_characterdata_get_data(ctx->n, &content); + if (err != DOM_NO_ERR || content == NULL) + return false; + if (css_computed_white_space(props.parent_style) == CSS_WHITE_SPACE_NORMAL || css_computed_white_space(props.parent_style) == CSS_WHITE_SPACE_NOWRAP) { - char *text = squash_whitespace((char *) ctx->n->content); + char *text; + + text = squash_whitespace(dom_string_data(content)); + + dom_string_unref(content); + if (text == NULL) return false; @@ -963,7 +1183,7 @@ bool box_construct_text(struct box_construct_ctx *ctx) } } else { /* white-space: pre */ - char *text = cnv_space2nbsp((char *) ctx->n->content); + char *text = cnv_space2nbsp(dom_string_data(content)); char *current; enum css_white_space_e white_space = css_computed_white_space(props.parent_style); @@ -973,6 +1193,8 @@ bool box_construct_text(struct box_construct_ctx *ctx) white_space == CSS_WHITE_SPACE_PRE_LINE || white_space == CSS_WHITE_SPACE_PRE_WRAP); + dom_string_unref(content); + if (text == NULL) return false; @@ -1091,7 +1313,8 @@ bool box_construct_text(struct box_construct_ctx *ctx) css_select_results *box_get_style(html_content *c, const css_computed_style *parent_style, dom_node *n) { - char *s; + dom_string *s; + dom_exception err; int pseudo_element; css_error error; css_stylesheet *inline_style = NULL; @@ -1099,15 +1322,20 @@ css_select_results *box_get_style(html_content *c, nscss_select_ctx ctx; /* Firstly, construct inline stylesheet, if any */ - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "style"))) { + err = dom_element_get_attribute(n, kstr_style, &s); + if (err != DOM_NO_ERR) + return NULL; + + if (s != NULL) { inline_style = nscss_create_inline_style( - (uint8_t *) s, strlen(s), + (const uint8_t *) dom_string_data(s), + dom_string_byte_length(s), c->encoding, nsurl_access(content_get_url(&c->base)), c->quirks != BINDING_QUIRKS_MODE_NONE, box_style_alloc, NULL); - xmlFree(s); + dom_string_unref(s); if (inline_style == NULL) return NULL; @@ -1282,12 +1510,14 @@ bool box_a(BOX_SPECIAL_PARAMS) { bool ok; nsurl *url; - xmlChar *s; + dom_string *s; + dom_exception err; - if ((s = xmlGetProp(n, (const xmlChar *) "href"))) { - ok = box_extract_link((const char *) s, + err = dom_element_get_attribute(n, kstr_href, &s); + if (err == DOM_NO_ERR && s != NULL) { + ok = box_extract_link(dom_string_data(s), content->base_url, &url); - xmlFree(s); + dom_string_unref(s); if (!ok) return false; if (url) { @@ -1298,16 +1528,15 @@ bool box_a(BOX_SPECIAL_PARAMS) } /* name and id share the same namespace */ - s = xmlGetProp(n, (const xmlChar *) "name"); - if (s) { - lwc_error lerror; + err = dom_element_get_attribute(n, kstr_name, &s); + if (err == DOM_NO_ERR && s != NULL) { lwc_string *lwc_name; - lerror = lwc_intern_string((const char *) s, - strlen((const char *) s), &lwc_name); - xmlFree(s); + err = dom_string_intern(s, &lwc_name); - if (lerror == lwc_error_ok) { + dom_string_unref(s); + + if (err == DOM_NO_ERR) { /* name replaces existing id * TODO: really? */ if (box->id != NULL) @@ -1318,27 +1547,29 @@ bool box_a(BOX_SPECIAL_PARAMS) } /* target frame [16.3] */ - if ((s = xmlGetProp(n, (const xmlChar *) "target"))) { - if (!strcasecmp((const char *) s, "_blank")) + err = dom_element_get_attribute(n, kstr_target, &s); + if (err == DOM_NO_ERR && s != NULL) { + if (!strcasecmp(dom_string_data(s), "_blank")) box->target = TARGET_BLANK; - else if (!strcasecmp((const char *) s, "_top")) + else if (!strcasecmp(dom_string_data(s), "_top")) box->target = TARGET_TOP; - else if (!strcasecmp((const char *) s, "_parent")) + else if (!strcasecmp(dom_string_data(s), "_parent")) box->target = TARGET_PARENT; - else if (!strcasecmp((const char *) s, "_self")) + else if (!strcasecmp(dom_string_data(s), "_self")) /* the default may have been overridden by a * , so this is different to 0 */ box->target = TARGET_SELF; else { /* 6.16 says that frame names must begin with [a-zA-Z] * This doesn't match reality, so just take anything */ - box->target = talloc_strdup(content, (const char *) s); + box->target = talloc_strdup(content, + dom_string_data(s)); if (!box->target) { - xmlFree(s); + dom_string_unref(s); return false; } } - xmlFree(s); + dom_string_unref(s); } return true; @@ -1352,9 +1583,9 @@ bool box_a(BOX_SPECIAL_PARAMS) bool box_image(BOX_SPECIAL_PARAMS) { bool ok; - char *s; + dom_string *s; + dom_exception err; nsurl *url; - xmlChar *alt, *src; enum css_width_e wtype; enum css_height_e htype; css_fixed value = 0; @@ -1362,18 +1593,19 @@ bool box_image(BOX_SPECIAL_PARAMS) css_unit hunit = CSS_UNIT_PX; if (box->style && css_computed_display(box->style, - n->parent == NULL) == CSS_DISPLAY_NONE) + box_is_root(n)) == CSS_DISPLAY_NONE) return true; /* handle alt text */ - if ((alt = xmlGetProp(n, (const xmlChar *) "alt"))) { - s = squash_whitespace((const char *) alt); - xmlFree(alt); - if (!s) + err = dom_element_get_attribute(n, kstr_alt, &s); + if (err == DOM_NO_ERR && s != NULL) { + char *alt = squash_whitespace(dom_string_data(s)); + dom_string_unref(s); + if (alt == NULL) return false; - box->text = talloc_strdup(content, s); - free(s); - if (!box->text) + box->text = talloc_strdup(content, alt); + free(alt); + if (box->text == NULL) return false; box->length = strlen(box->text); } @@ -1389,12 +1621,19 @@ bool box_image(BOX_SPECIAL_PARAMS) box->usemap++; /* get image URL */ - if (!(src = xmlGetProp(n, (const xmlChar *) "src"))) + err = dom_element_get_attribute(n, kstr_src, &s); + if (err != DOM_NO_ERR || s == NULL) return true; - if (!box_extract_link((char *) src, content->base_url, &url)) + + if (box_extract_link(dom_string_data(s), content->base_url, + &url) == false) { + dom_string_unref(s); return false; - xmlFree(src); - if (!url) + } + + dom_string_unref(s); + + if (url == NULL) return true; /* start fetch */ @@ -1442,73 +1681,85 @@ bool box_object(BOX_SPECIAL_PARAMS) { struct object_params *params; struct object_param *param; - xmlChar *codebase, *classid, *data; + dom_string *codebase, *classid, *data; dom_node *c; + dom_exception err; if (box->style && css_computed_display(box->style, - n->parent == NULL) == CSS_DISPLAY_NONE) + box_is_root(n)) == CSS_DISPLAY_NONE) return true; - if (!box_get_attribute(n, "usemap", content, &box->usemap)) + if (box_get_attribute(n, "usemap", content, &box->usemap) == false) return false; if (box->usemap && box->usemap[0] == '#') box->usemap++; params = talloc(content, struct object_params); - if (!params) + if (params == NULL) return false; talloc_set_destructor(params, box_object_talloc_destructor); - params->data = 0; - params->type = 0; - params->codetype = 0; - params->codebase = 0; - params->classid = 0; - params->params = 0; + params->data = NULL; + params->type = NULL; + params->codetype = NULL; + params->codebase = NULL; + params->classid = NULL; + params->params = NULL; /* codebase, classid, and data are URLs * (codebase is the base for the other two) */ - if ((codebase = xmlGetProp(n, (const xmlChar *) "codebase"))) { - if (!box_extract_link((char *) codebase, content->base_url, - ¶ms->codebase)) + err = dom_element_get_attribute(n, kstr_codebase, &codebase); + if (err == DOM_NO_ERR && codebase != NULL) { + if (box_extract_link(dom_string_data(codebase), + content->base_url, + ¶ms->codebase) == false) { + dom_string_unref(codebase); return false; - xmlFree(codebase); + } + dom_string_unref(codebase); } - if (!params->codebase) + if (params->codebase == NULL) params->codebase = nsurl_ref(content->base_url); - if ((classid = xmlGetProp(n, (const xmlChar *) "classid"))) { - if (!box_extract_link((char *) classid, params->codebase, - ¶ms->classid)) + err = dom_element_get_attribute(n, kstr_classid, &classid); + if (err == DOM_NO_ERR && classid != NULL) { + if (box_extract_link(dom_string_data(classid), params->codebase, + ¶ms->classid) == false) { + dom_string_unref(classid); return false; - xmlFree(classid); + } + dom_string_unref(classid); } - if ((data = xmlGetProp(n, (const xmlChar *) "data"))) { - if (!box_extract_link((char *) data, params->codebase, - ¶ms->data)) + err = dom_element_get_attribute(n, kstr_data, &data); + if (err == DOM_NO_ERR && data != NULL) { + if (box_extract_link(dom_string_data(data), params->codebase, + ¶ms->data)) { + dom_string_unref(data); return false; - xmlFree(data); + } + dom_string_unref(data); } - if (!params->classid && !params->data) + if (params->classid == NULL && params->data == NULL) /* nothing to embed; ignore */ return true; /* Don't include ourself */ - if (params->classid && nsurl_compare(content->base_url, + if (params->classid != NULL && nsurl_compare(content->base_url, params->classid, NSURL_COMPLETE)) return true; - if (params->data && nsurl_compare(content->base_url, + if (params->data != NULL && nsurl_compare(content->base_url, params->data, NSURL_COMPLETE)) return true; /* codetype and type are MIME types */ - if (!box_get_attribute(n, "codetype", params, ¶ms->codetype)) + if (box_get_attribute(n, "codetype", params, + ¶ms->codetype) == false) return false; - if (!box_get_attribute(n, "type", params, ¶ms->type)) + if (box_get_attribute(n, "type", params, ¶ms->type) == false) return false; /* classid && !data => classid is used (consult codetype) @@ -1555,40 +1806,92 @@ bool box_object(BOX_SPECIAL_PARAMS) } /* add parameters to linked list */ - for (c = n->children; c; c = c->next) { - if (c->type != XML_ELEMENT_NODE) - continue; - if (strcmp((const char *) c->name, "param") != 0) - /* The first non-param child is the start of the alt - * html. Therefore, we should break out of this loop. */ - break; + err = dom_node_get_first_child(n, &c); + if (err != DOM_NO_ERR) + return false; - param = talloc(params, struct object_param); - if (!param) - return false; - param->name = 0; - param->value = 0; - param->type = 0; - param->valuetype = 0; - param->next = 0; + while (c != NULL) { + dom_node *next; + dom_node_type type; - if (!box_get_attribute(c, "name", param, ¶m->name)) + err = dom_node_get_node_type(c, &type); + if (err != DOM_NO_ERR) { + dom_node_unref(c); return false; - if (!box_get_attribute(c, "value", param, ¶m->value)) - return false; - if (!box_get_attribute(c, "type", param, ¶m->type)) - return false; - if (!box_get_attribute(c, "valuetype", param, - ¶m->valuetype)) - return false; - if (!param->valuetype) { - param->valuetype = talloc_strdup(param, "data"); - if (!param->valuetype) - return false; } - param->next = params->params; - params->params = param; + if (type == DOM_ELEMENT_NODE) { + dom_string *name; + + err = dom_node_get_node_name(c, &name); + if (err != DOM_NO_ERR) { + dom_node_unref(c); + return false; + } + + if (strcmp(dom_string_data(name), "param") != 0) { + /* The first non-param child is the start of + * the alt html. Therefore, we should break + * out of this loop. */ + dom_node_unref(c); + break; + } + + param = talloc(params, struct object_param); + if (param == NULL) { + dom_node_unref(c); + return false; + } + param->name = NULL; + param->value = NULL; + param->type = NULL; + param->valuetype = NULL; + param->next = NULL; + + if (box_get_attribute(c, "name", param, + ¶m->name) == false) { + dom_node_unref(c); + return false; + } + + if (box_get_attribute(c, "value", param, + ¶m->value) == false) { + dom_node_unref(c); + return false; + } + + if (box_get_attribute(c, "type", param, + ¶m->type) == false) { + dom_node_unref(c); + return false; + } + + if (box_get_attribute(c, "valuetype", param, + ¶m->valuetype) == false) { + dom_node_unref(c); + return false; + } + + if (param->valuetype == NULL) { + param->valuetype = talloc_strdup(param, "data"); + if (param->valuetype == NULL) { + dom_node_unref(c); + return false; + } + } + + param->next = params->params; + params->params = param; + } + + err = dom_node_get_next_sibling(c, &next); + if (err != DOM_NO_ERR) { + dom_node_unref(c); + return false; + } + + dom_node_unref(c); + c = next; } box->object_params = params; @@ -1657,62 +1960,71 @@ bool box_create_frameset(struct content_html_frames *f, dom_node *n, html_content *content) { unsigned int row, col, index, i; unsigned int rows = 1, cols = 1; - char *s; + dom_string *s; + dom_exception err; nsurl *url; struct frame_dimension *row_height = 0, *col_width = 0; - dom_node *c; + dom_node *c, *next; struct content_html_frames *frame; bool default_border = true; colour default_border_colour = 0x000000; /* parse rows and columns */ - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "rows"))) { - row_height = box_parse_multi_lengths(s, &rows); - xmlFree(s); - if (!row_height) + err = dom_element_get_attribute(n, kstr_rows, &s); + if (err == DOM_NO_ERR && s != NULL) { + row_height = box_parse_multi_lengths(dom_string_data(s), &rows); + dom_string_unref(s); + if (row_height == NULL) return false; } else { row_height = calloc(1, sizeof(struct frame_dimension)); - if (!row_height) + if (row_height == NULL) return false; row_height->value = 100; row_height->unit = FRAME_DIMENSION_PERCENT; } - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "cols"))) { - col_width = box_parse_multi_lengths(s, &cols); - xmlFree(s); - if (!col_width) + err = dom_element_get_attribute(n, kstr_cols, &s); + if (err == DOM_NO_ERR && s != NULL) { + col_width = box_parse_multi_lengths(dom_string_data(s), &cols); + dom_string_unref(s); + if (col_width == NULL) return false; } else { col_width = calloc(1, sizeof(struct frame_dimension)); - if (!col_width) + if (col_width == NULL) return false; col_width->value = 100; col_width->unit = FRAME_DIMENSION_PERCENT; } /* common extension: border="0|1" to control all children */ - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "border"))) { - if ((s[0] == '0') && (s[1] == '\0')) + err = dom_element_get_attribute(n, kstr_border, &s); + if (err == DOM_NO_ERR && s != NULL) { + if ((dom_string_data(s)[0] == '0') && + (dom_string_data(s)[1] == '\0')) default_border = false; - xmlFree(s); + dom_string_unref(s); } + /* common extension: frameborder="yes|no" to control all children */ - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "frameborder"))) { - if (!strcasecmp(s, "no")) + err = dom_element_get_attribute(n, kstr_frameborder, &s); + if (err == DOM_NO_ERR && s != NULL) { + if (strcasecmp(dom_string_data(s), "no") == 0) default_border = false; - xmlFree(s); + dom_string_unref(s); } + /* common extension: bordercolor="#RRGGBB|" to control *all children */ - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "bordercolor"))) { + err = dom_element_get_attribute(n, kstr_bordercolor, &s); + if (err == DOM_NO_ERR && s != NULL) { css_color color; - if (nscss_parse_colour((const char *) s, &color)) + if (nscss_parse_colour(dom_string_data(s), &color)) default_border_colour = nscss_color_to_ns(color); - xmlFree(s); + dom_string_unref(s); } /* update frameset and create default children */ @@ -1747,15 +2059,46 @@ bool box_create_frameset(struct content_html_frames *f, dom_node *n, free(row_height); /* create the frameset windows */ - c = n->children; - for (row = 0; c && row < rows; row++) { - for (col = 0; c && col < cols; col++) { - while (c && !(c->type == XML_ELEMENT_NODE && ( - strcmp((const char *) c->name, "frame") == 0 || - strcmp((const char *) c->name, "frameset") == 0 - ))) - c = c->next; - if (!c) + err = dom_node_get_first_child(n, &c); + if (err != DOM_NO_ERR) + return false; + + for (row = 0; c != NULL && row < rows; row++) { + for (col = 0; c != NULL && col < cols; col++) { + while (c != NULL) { + dom_node_type type; + dom_string *name; + + err = dom_node_get_node_type(c, &type); + if (err != DOM_NO_ERR) { + dom_node_unref(c); + return false; + } + + err = dom_node_get_node_name(c, &name); + if (err != DOM_NO_ERR) { + dom_node_unref(c); + return false; + } + + if (type != DOM_ELEMENT_NODE || + (strcmp(dom_string_data(name), + "frame") != 0 && + strcmp(dom_string_data(name), + "frameset") != 0)) { + err = dom_node_get_next_sibling(c, + &next); + if (err != DOM_NO_ERR) { + dom_node_unref(c); + return false; + } + + dom_node_unref(c); + c = next; + } + } + + if (c == NULL) break; /* get current frame */ @@ -1763,24 +2106,45 @@ bool box_create_frameset(struct content_html_frames *f, dom_node *n, frame = &f->children[index]; /* nest framesets */ - if (strcmp((const char *) c->name, "frameset") == 0) { + err = dom_node_get_node_name(c, &s); + if (err != DOM_NO_ERR) { + dom_node_unref(c); + return false; + } + + if (strcmp(dom_string_data(s), "frameset") == 0) { + dom_string_unref(s); frame->border = 0; - if (!box_create_frameset(frame, c, content)) + if (box_create_frameset(frame, c, + content) == false) { + dom_node_unref(c); return false; - c = c->next; + } + + err = dom_node_get_next_sibling(c, &next); + if (err != DOM_NO_ERR) { + dom_node_unref(c); + return false; + } + + dom_node_unref(c); + c = next; continue; } + dom_string_unref(s); + /* get frame URL (not required) */ url = NULL; - if ((s = (char *) xmlGetProp(c, - (const xmlChar *) "src"))) { - box_extract_link(s, content->base_url, &url); - xmlFree(s); + err = dom_element_get_attribute(c, kstr_src, &s); + if (err == DOM_NO_ERR && s != NULL) { + box_extract_link(dom_string_data(s), + content->base_url, &url); + dom_string_unref(s); } /* copy url */ - if (url) { + if (url != NULL) { /* no self-references */ if (nsurl_compare(content->base_url, url, NSURL_COMPLETE) == false) @@ -1789,51 +2153,70 @@ bool box_create_frameset(struct content_html_frames *f, dom_node *n, } /* fill in specified values */ - if ((s = (char *) xmlGetProp(c, - (const xmlChar *) "name"))) { - frame->name = talloc_strdup(content, s); - xmlFree(s); + err = dom_element_get_attribute(c, kstr_name, &s); + if (err == DOM_NO_ERR && s != NULL) { + frame->name = talloc_strdup(content, + dom_string_data(s)); + dom_string_unref(s); } - frame->no_resize = xmlHasProp(c, - (const xmlChar *) "noresize") != NULL; - if ((s = (char *) xmlGetProp(c, - (const xmlChar *) "frameborder"))) { - i = atoi(s); + + dom_element_has_attribute(c, kstr_noresize, + &frame->no_resize); + + err = dom_element_get_attribute(c, kstr_frameborder, + &s); + if (err == DOM_NO_ERR && s != NULL) { + i = atoi(dom_string_data(s)); frame->border = (i != 0); - xmlFree(s); + dom_string_unref(s); } - if ((s = (char *) xmlGetProp(c, - (const xmlChar *) "scrolling"))) { - if (!strcasecmp(s, "yes")) + + err = dom_element_get_attribute(c, kstr_scrolling, &s); + if (err == DOM_NO_ERR && s != NULL) { + if (strcasecmp(dom_string_data(s), "yes") == 0) frame->scrolling = SCROLLING_YES; - else if (!strcasecmp(s, "no")) + else if (strcasecmp(dom_string_data(s), + "no") == 0) frame->scrolling = SCROLLING_NO; - xmlFree(s); + dom_string_unref(s); } - if ((s = (char *) xmlGetProp(c, - (const xmlChar *) "marginwidth"))) { - frame->margin_width = atoi(s); - xmlFree(s); + + err = dom_element_get_attribute(c, kstr_marginwidth, + &s); + if (err == DOM_NO_ERR && s != NULL) { + frame->margin_width = atoi(dom_string_data(s)); + dom_string_unref(s); } - if ((s = (char *) xmlGetProp(c, - (const xmlChar *) "marginheight"))) { - frame->margin_height = atoi(s); - xmlFree(s); + + err = dom_element_get_attribute(c, kstr_marginheight, + &s); + if (err == DOM_NO_ERR && s != NULL) { + frame->margin_height = atoi(dom_string_data(s)); + dom_string_unref(s); } - if ((s = (char *) xmlGetProp(c, (const xmlChar *) - "bordercolor"))) { + + err = dom_element_get_attribute(c, kstr_bordercolor, + &s); + if (err == DOM_NO_ERR && s != NULL) { css_color color; - if (nscss_parse_colour((const char *) s, + if (nscss_parse_colour(dom_string_data(s), &color)) frame->border_colour = nscss_color_to_ns(color); - xmlFree(s); + dom_string_unref(s); } /* advance */ - c = c->next; + err = dom_node_get_next_sibling(c, &next); + if (err != DOM_NO_ERR) { + dom_node_unref(c); + return false; + } + + dom_node_unref(c); + c = next; } } @@ -1865,12 +2248,13 @@ static int box_iframes_talloc_destructor(struct content_html_iframe *f) bool box_iframe(BOX_SPECIAL_PARAMS) { nsurl *url; - char *s; + dom_string *s; + dom_exception err; struct content_html_iframe *iframe; int i; if (box->style && css_computed_display(box->style, - n->parent == NULL) == CSS_DISPLAY_NONE) + box_is_root(n)) == CSS_DISPLAY_NONE) return true; if (box->style && css_computed_visibility(box->style) == @@ -1881,15 +2265,16 @@ bool box_iframe(BOX_SPECIAL_PARAMS) return true; /* get frame URL */ - if (!(s = (char *) xmlGetProp(n, - (const xmlChar *) "src"))) + err = dom_element_get_attribute(n, kstr_src, &s); + if (err != DOM_NO_ERR || s == NULL) return true; - if (!box_extract_link(s, content->base_url, &url)) { - xmlFree(s); + if (box_extract_link(dom_string_data(s), content->base_url, + &url) == false) { + dom_string_unref(s); return false; } - xmlFree(s); - if (!url) + dom_string_unref(s); + if (url == NULL) return true; /* don't include ourself */ @@ -1900,7 +2285,7 @@ bool box_iframe(BOX_SPECIAL_PARAMS) /* create a new iframe */ iframe = talloc(content, struct content_html_iframe); - if (!iframe) { + if (iframe == NULL) { nsurl_unref(url); return false; } @@ -1920,37 +2305,48 @@ bool box_iframe(BOX_SPECIAL_PARAMS) content->iframe = iframe; /* fill in specified values */ - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "name"))) { - iframe->name = talloc_strdup(content, s); - xmlFree(s); + err = dom_element_get_attribute(n, kstr_name, &s); + if (err == DOM_NO_ERR && s != NULL) { + iframe->name = talloc_strdup(content, dom_string_data(s)); + dom_string_unref(s); } - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "frameborder"))) { - i = atoi(s); + + err = dom_element_get_attribute(n, kstr_frameborder, &s); + if (err == DOM_NO_ERR && s != NULL) { + i = atoi(dom_string_data(s)); iframe->border = (i != 0); - xmlFree(s); + dom_string_unref(s); } - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "bordercolor"))) { + + err = dom_element_get_attribute(n, kstr_bordercolor, &s); + if (err == DOM_NO_ERR && s != NULL) { css_color color; - if (nscss_parse_colour(s, &color)) + if (nscss_parse_colour(dom_string_data(s), &color)) iframe->border_colour = nscss_color_to_ns(color); - xmlFree(s); + dom_string_unref(s); } - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "scrolling"))) { - if (!strcasecmp(s, "yes")) + + err = dom_element_get_attribute(n, kstr_scrolling, &s); + if (err == DOM_NO_ERR && s != NULL) { + if (strcasecmp(dom_string_data(s), "yes") == 0) iframe->scrolling = SCROLLING_YES; - else if (!strcasecmp(s, "no")) + else if (strcasecmp(dom_string_data(s), "no") == 0) iframe->scrolling = SCROLLING_NO; - xmlFree(s); + dom_string_unref(s); } - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "marginwidth"))) { - iframe->margin_width = atoi(s); - xmlFree(s); + + err = dom_element_get_attribute(n, kstr_marginwidth, &s); + if (err == DOM_NO_ERR && s != NULL) { + iframe->margin_width = atoi(dom_string_data(s)); + dom_string_unref(s); } - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "marginheight"))) { - iframe->margin_height = atoi(s); - xmlFree(s); + + err = dom_element_get_attribute(n, kstr_marginheight, &s); + if (err == DOM_NO_ERR && s != NULL) { + iframe->margin_height = atoi(dom_string_data(s)); + dom_string_unref(s); } /* box */ @@ -1971,46 +2367,49 @@ bool box_iframe(BOX_SPECIAL_PARAMS) bool box_input(BOX_SPECIAL_PARAMS) { struct form_control *gadget = NULL; - char *s, *type; + dom_string *type = NULL; + dom_exception err; nsurl *url; nserror error; - type = (char *) xmlGetProp(n, (const xmlChar *) "type"); + dom_element_get_attribute(n, kstr_type, &type); gadget = binding_get_control_for_node(content->parser_binding, n); - if (!gadget) + if (gadget == NULL) goto no_memory; box->gadget = gadget; gadget->box = box; - if (type && strcasecmp(type, "password") == 0) { - if (!box_input_text(n, content, box, 0, true)) + if (type && strcasecmp(dom_string_data(type), "password") == 0) { + if (box_input_text(n, content, box, 0, true) == false) goto no_memory; - } else if (type && strcasecmp(type, "file") == 0) { + } else if (type && strcasecmp(dom_string_data(type), "file") == 0) { box->type = BOX_INLINE_BLOCK; - } else if (type && strcasecmp(type, "hidden") == 0) { + } else if (type && strcasecmp(dom_string_data(type), "hidden") == 0) { /* no box for hidden inputs */ box->type = BOX_NONE; - } else if (type && (strcasecmp(type, "checkbox") == 0 || - strcasecmp(type, "radio") == 0)) { - } else if (type && (strcasecmp(type, "submit") == 0 || - strcasecmp(type, "reset") == 0 || - strcasecmp(type, "button") == 0)) { + } else if (type && + (strcasecmp(dom_string_data(type), "checkbox") == 0 || + strcasecmp(dom_string_data(type), "radio") == 0)) { + } else if (type && + (strcasecmp(dom_string_data(type), "submit") == 0 || + strcasecmp(dom_string_data(type), "reset") == 0 || + strcasecmp(dom_string_data(type), "button") == 0)) { struct box *inline_container, *inline_box; - if (!box_button(n, content, box, 0)) + if (box_button(n, content, box, 0) == false) goto no_memory; inline_container = box_create(NULL, 0, false, 0, 0, 0, 0, content); - if (!inline_container) + if (inline_container == NULL) goto no_memory; inline_container->type = BOX_INLINE_CONTAINER; inline_box = box_create(NULL, box->style, false, 0, 0, box->title, 0, content); - if (!inline_box) + if (inline_box == NULL) goto no_memory; inline_box->type = BOX_TEXT; @@ -2027,7 +2426,7 @@ bool box_input(BOX_SPECIAL_PARAMS) else inline_box->text = talloc_strdup(content, "Button"); - if (!inline_box->text) + if (inline_box->text == NULL) goto no_memory; inline_box->length = strlen(inline_box->text); @@ -2035,16 +2434,19 @@ bool box_input(BOX_SPECIAL_PARAMS) box_add_child(inline_container, inline_box); box_add_child(box, inline_container); - } else if (type && strcasecmp(type, "image") == 0) { + } else if (type && strcasecmp(dom_string_data(type), "image") == 0) { gadget->type = GADGET_IMAGE; if (box->style && css_computed_display(box->style, - n->parent == NULL) != CSS_DISPLAY_NONE && + box_is_root(n)) != CSS_DISPLAY_NONE && nsoption_bool(foreground_images) == true) { - if ((s = (char *) xmlGetProp(n, - (const xmlChar*) "src"))) { - error = nsurl_join(content->base_url, s, &url); - xmlFree(s); + dom_string *s; + + err = dom_element_get_attribute(n, kstr_src, &s); + if (err == DOM_NO_ERR && s != NULL) { + error = nsurl_join(content->base_url, + dom_string_data(s), &url); + dom_string_unref(s); if (error != NSERROR_OK) goto no_memory; @@ -2067,19 +2469,20 @@ bool box_input(BOX_SPECIAL_PARAMS) } } else { /* the default type is "text" */ - if (!box_input_text(n, content, box, 0, false)) + if (box_input_text(n, content, box, 0, false) == false) goto no_memory; } if (type) - xmlFree(type); + dom_string_unref(type); *convert_children = false; return true; no_memory: if (type) - xmlFree(type); + dom_string_unref(type); + return false; } @@ -2163,24 +2566,88 @@ bool box_select(BOX_SPECIAL_PARAMS) struct box *inline_box; struct form_control *gadget; dom_node *c, *c2; + dom_node *next, *next2; + dom_exception err; gadget = binding_get_control_for_node(content->parser_binding, n); - if (!gadget) + if (gadget == NULL) return false; - for (c = n->children; c; c = c->next) { - if (strcmp((const char *) c->name, "option") == 0) { - if (!box_select_add_option(gadget, c)) - goto no_memory; - } else if (strcmp((const char *) c->name, "optgroup") == 0) { - for (c2 = c->children; c2; c2 = c2->next) { - if (strcmp((const char *) c2->name, - "option") == 0) { - if (!box_select_add_option(gadget, c2)) - goto no_memory; - } - } + err = dom_node_get_first_child(n, &c); + if (err != DOM_NO_ERR) + return false; + + while (c != NULL) { + dom_string *name; + + err = dom_node_get_node_name(c, &name); + if (err != DOM_NO_ERR) { + dom_node_unref(c); + return false; } + + if (strcmp(dom_string_data(name), "option") == 0) { + dom_string_unref(name); + + if (box_select_add_option(gadget, c) == false) { + dom_node_unref(c); + goto no_memory; + } + } else if (strcmp(dom_string_data(name), "optgroup") == 0) { + dom_string_unref(name); + + err = dom_node_get_first_child(c, &c2); + if (err != DOM_NO_ERR) { + dom_node_unref(c); + return false; + } + + while (c2 != NULL) { + dom_string *c2_name; + + err = dom_node_get_node_name(c2, &c2_name); + if (err != DOM_NO_ERR) { + dom_node_unref(c2); + dom_node_unref(c); + return false; + } + + if (strcmp(dom_string_data(c2_name), + "option") == 0) { + dom_string_unref(c2_name); + + if (box_select_add_option(gadget, + c2) == false) { + dom_node_unref(c2); + dom_node_unref(c); + goto no_memory; + } + } else { + dom_string_unref(c2_name); + } + + err = dom_node_get_next_sibling(c2, &next2); + if (err != DOM_NO_ERR) { + dom_node_unref(c2); + dom_node_unref(c); + return false; + } + + dom_node_unref(c2); + c2 = next2; + } + } else { + dom_string_unref(name); + } + + err = dom_node_get_next_sibling(c, &next); + if (err != DOM_NO_ERR) { + dom_node_unref(c); + return false; + } + + dom_node_unref(c); + c = next; } if (gadget->data.select.num_items == 0) { @@ -2193,18 +2660,18 @@ bool box_select(BOX_SPECIAL_PARAMS) gadget->box = box; inline_container = box_create(NULL, 0, false, 0, 0, 0, 0, content); - if (!inline_container) + if (inline_container == NULL) goto no_memory; inline_container->type = BOX_INLINE_CONTAINER; inline_box = box_create(NULL, box->style, false, 0, 0, box->title, 0, content); - if (!inline_box) + if (inline_box == NULL) goto no_memory; inline_box->type = BOX_TEXT; box_add_child(inline_container, inline_box); box_add_child(box, inline_container); - if (!gadget->data.select.multiple && + if (gadget->data.select.multiple == false && gadget->data.select.num_selected == 0) { gadget->data.select.current = gadget->data.select.items; gadget->data.select.current->initial_selected = @@ -2221,7 +2688,7 @@ bool box_select(BOX_SPECIAL_PARAMS) else inline_box->text = talloc_strdup(content, messages_get("Form_Many")); - if (!inline_box->text) + if (inline_box->text == NULL) goto no_memory; inline_box->length = strlen(inline_box->text); @@ -2244,37 +2711,43 @@ no_memory: bool box_select_add_option(struct form_control *control, dom_node *n) { - char *value = 0; - char *text = 0; - char *text_nowrap = 0; + char *value = NULL; + char *text = NULL; + char *text_nowrap = NULL; bool selected; - xmlChar *content; - char *s; + dom_string *content, *s; + dom_exception err; - content = xmlNodeGetContent(n); - if (!content) - goto no_memory; - text = squash_whitespace((const char *) content); - xmlFree(content); - if (!text) + err = dom_node_get_text_content(n, &content); + if (err != DOM_NO_ERR) + return false; + + text = squash_whitespace(dom_string_data(content)); + + dom_string_unref(content); + + if (text == NULL) goto no_memory; - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "value"))) { - value = strdup(s); - xmlFree(s); - } else + err = dom_element_get_attribute(n, kstr_value, &s); + if (err == DOM_NO_ERR && s != NULL) { + value = strdup(dom_string_data(s)); + dom_string_unref(s); + } else { value = strdup(text); - if (!value) + } + + if (value == NULL) goto no_memory; - selected = xmlHasProp(n, (const xmlChar *) "selected") != NULL; + dom_element_has_attribute(n, kstr_selected, &selected); /* replace spaces/TABs with hard spaces to prevent line wrapping */ text_nowrap = cnv_space2nbsp(text); - if (!text_nowrap) + if (text_nowrap == NULL) goto no_memory; - if (!form_add_option(control, value, text_nowrap, selected)) + if (form_add_option(control, value, text_nowrap, selected) == false) goto no_memory; free(text); @@ -2301,78 +2774,52 @@ bool box_textarea(BOX_SPECIAL_PARAMS) * Consecutive BR may not be present. These constraints are satisfied * by using a 0-length TEXT for blank lines. */ - xmlChar *current, *string; - dom_node *n2; - xmlBufferPtr buf; - xmlParserCtxtPtr ctxt; + const char *current; + dom_string *area_data = NULL; + dom_exception err; struct box *inline_container, *inline_box, *br_box; char *s; size_t len; box->type = BOX_INLINE_BLOCK; box->gadget = binding_get_control_for_node(content->parser_binding, n); - if (!box->gadget) + if (box->gadget == NULL) return false; box->gadget->box = box; inline_container = box_create(NULL, 0, false, 0, 0, box->title, 0, content); - if (!inline_container) + if (inline_container == NULL) return false; inline_container->type = BOX_INLINE_CONTAINER; box_add_child(box, inline_container); - /** \todo Is it really necessary to reparse the content of a - * textarea element to remove entities? Hubbub will do that for us. - */ - n2 = n->children; - buf = xmlBufferCreate(); - while(n2) { - int ret = xmlNodeDump(buf, n2->doc, n2, 0, 0); - if (ret == -1) { - xmlBufferFree(buf); - return false; - } - n2 = n2->next; + err = dom_node_get_text_content(n, &area_data); + if (err != DOM_NO_ERR) + return false; + + if (area_data == NULL) { + current = dom_string_data(area_data); + } else { + /* No content, or failed reading it: use a blank string */ + current = ""; } - ctxt = xmlCreateDocParserCtxt(buf->content); - string = current = NULL; - if (ctxt) { - string = current = xmlStringDecodeEntities(ctxt, - buf->content, - XML_SUBSTITUTE_REF, - 0, 0, 0); - xmlFreeParserCtxt(ctxt); - } - - if (!string) { - /* If we get here, either the parser context failed to be - * created or we were unable to decode the entities in the - * buffer. Therefore, try to create a blank string in order - * to recover. */ - string = current = xmlStrdup((const xmlChar *) ""); - if (!string) { - xmlBufferFree(buf); - return false; - } - } - - while (1) { + while (true) { /* BOX_TEXT */ - len = strcspn((const char *) current, "\r\n"); - s = talloc_strndup(content, (const char *) current, len); - if (!s) { - xmlFree(string); - xmlBufferFree(buf); + len = strcspn(current, "\r\n"); + s = talloc_strndup(content, current, len); + if (s == NULL) { + if (area_data != NULL) + dom_string_unref(area_data); return false; } inline_box = box_create(NULL, box->style, false, 0, 0, box->title, 0, content); - if (!inline_box) { - xmlFree(string); - xmlBufferFree(buf); + if (inline_box == NULL) { + if (area_data != NULL) + dom_string_unref(area_data); return false; } inline_box->type = BOX_TEXT; @@ -2388,9 +2835,9 @@ bool box_textarea(BOX_SPECIAL_PARAMS) /* BOX_BR */ br_box = box_create(NULL, box->style, false, 0, 0, box->title, 0, content); - if (!br_box) { - xmlFree(string); - xmlBufferFree(buf); + if (br_box == NULL) { + if (area_data != NULL) + dom_string_unref(area_data); return false; } br_box->type = BOX_BR; @@ -2402,8 +2849,8 @@ bool box_textarea(BOX_SPECIAL_PARAMS) current++; } - xmlFree(string); - xmlBufferFree(buf); + if (area_data != NULL) + dom_string_unref(area_data); *convert_children = false; return true; @@ -2419,33 +2866,41 @@ bool box_embed(BOX_SPECIAL_PARAMS) { struct object_params *params; struct object_param *param; - xmlChar *src; - xmlAttr *a; + dom_namednodemap *attrs; + unsigned long idx, num_attrs; + dom_string *src; + dom_exception err; if (box->style && css_computed_display(box->style, - n->parent == NULL) == CSS_DISPLAY_NONE) + box_is_root(n)) == CSS_DISPLAY_NONE) return true; params = talloc(content, struct object_params); - if (!params) + if (params == NULL) return false; talloc_set_destructor(params, box_object_talloc_destructor); - params->data = 0; - params->type = 0; - params->codetype = 0; - params->codebase = 0; - params->classid = 0; - params->params = 0; + params->data = NULL; + params->type = NULL; + params->codetype = NULL; + params->codebase = NULL; + params->classid = NULL; + params->params = NULL; /* src is a URL */ - if (!(src = xmlGetProp(n, (const xmlChar *) "src"))) + err = dom_element_get_attribute(n, kstr_src, &src); + if (err != DOM_NO_ERR || src == NULL) return true; - if (!box_extract_link((char *) src, content->base_url, ¶ms->data)) + if (box_extract_link(dom_string_data(src), content->base_url, + ¶ms->data) == false) { + dom_string_unref(src); return false; - xmlFree(src); - if (!params->data) + } + + dom_string_unref(src); + + if (params->data == NULL) return true; /* Don't include ourself */ @@ -2453,29 +2908,73 @@ bool box_embed(BOX_SPECIAL_PARAMS) return true; /* add attributes as parameters to linked list */ - for (a = n->properties; a; a = a->next) { - if (strcasecmp((const char *) a->name, "src") == 0) - continue; - if (!a->children || !a->children->content) + err = dom_node_get_attributes(n, &attrs); + if (err != DOM_NO_ERR) + return false; + + err = dom_namednodemap_get_length(attrs, &num_attrs); + if (err != DOM_NO_ERR) { + dom_namednodemap_unref(attrs); + return false; + } + + for (idx = 0; idx < num_attrs; idx++) { + dom_attr *attr; + dom_string *name, *value; + + err = dom_namednodemap_item(attrs, idx, &attr); + if (err != DOM_NO_ERR) { + dom_namednodemap_unref(attrs); + return false; + } + + err = dom_attr_get_name(attr, &name); + if (err != DOM_NO_ERR) { + dom_namednodemap_unref(attrs); + return false; + } + + if (strcasecmp(dom_string_data(name), "src") == 0) { + dom_string_unref(name); continue; + } + + err = dom_attr_get_value(attr, &value); + if (err != DOM_NO_ERR) { + dom_string_unref(name); + dom_namednodemap_unref(attrs); + return false; + } param = talloc(content, struct object_param); - if (!param) + if (param == NULL) { + dom_string_unref(value); + dom_string_unref(name); + dom_namednodemap_unref(attrs); return false; - param->name = talloc_strdup(content, (const char *) a->name); - param->value = talloc_strdup(content, - (char *) a->children->content); - param->type = 0; - param->valuetype = talloc_strdup(content, "data"); - param->next = 0; + } - if (!param->name || !param->value || !param->valuetype) + param->name = talloc_strdup(content, dom_string_data(name)); + param->value = talloc_strdup(content, dom_string_data(value)); + param->type = NULL; + param->valuetype = talloc_strdup(content, "data"); + param->next = NULL; + + dom_string_unref(value); + dom_string_unref(name); + + if (param->name == NULL || param->value == NULL || + param->valuetype == NULL) { + dom_namednodemap_unref(attrs); return false; + } param->next = params->params; params->params = param; } + dom_namednodemap_unref(attrs); + box->object_params = params; /* start fetch */ @@ -2504,13 +3003,34 @@ bool box_embed(BOX_SPECIAL_PARAMS) bool box_get_attribute(dom_node *n, const char *attribute, void *context, char **value) { - xmlChar *s = xmlGetProp(n, (const xmlChar *) attribute); - if (!s) - return true; - *value = talloc_strdup(context, (const char *) s); - xmlFree(s); - if (!*value) + char *result; + dom_string *attr, *attr_name; + dom_exception err; + + err = dom_string_create_interned((const uint8_t *) attribute, + strlen(attribute), &attr_name); + if (err != DOM_NO_ERR) return false; + + err = dom_element_get_attribute(n, attr_name, &attr); + if (err != DOM_NO_ERR) { + dom_string_unref(attr_name); + return false; + } + + dom_string_unref(attr_name); + + if (attr != NULL) { + result = talloc_strdup(context, dom_string_data(attr)); + + dom_string_unref(attr); + + if (result == NULL) + return false; + + *value = result; + } + return true; } diff --git a/render/parser_binding.h b/render/parser_binding.h index cdd10f8b1..90930c379 100644 --- a/render/parser_binding.h +++ b/render/parser_binding.h @@ -25,19 +25,6 @@ struct box; struct form; struct form_control; -/** - * Private data attached to each DOM node - */ -typedef struct binding_private { - /* All the following only apply to ELEMENT nodes */ - - struct box *box; /**< Root box if ELEMENT node, or NULL */ - lwc_string *localname; /**< Local name of node */ - lwc_string *id; /**< Value of id attribute, or NULL */ - lwc_string **classes; /**< Pre-parsed class names, or NULL */ - uint32_t nclasses; /**< Number of class names */ -} binding_private; - typedef enum binding_error { BINDING_OK, BINDING_NOMEM,