diff --git a/ext/dom/html_collection.c b/ext/dom/html_collection.c index ce56b77ecd958..a4e2d6ad6fbed 100644 --- a/ext/dom/html_collection.c +++ b/ext/dom/html_collection.c @@ -46,47 +46,35 @@ static dom_named_item dom_html_collection_named_item(zend_string *key, zend_obje /* 2. Return the first element in the collection for which at least one of the following is true: */ xmlNodePtr basep = dom_object_get_node(objmap->baseobj); - if (basep != NULL) { - zend_long cur = 0; - zend_long next = cur; /* not +1, otherwise we skip the first candidate */ - xmlNodePtr candidate = basep->children; - bool iterate_tag_name = objmap->handler == &php_dom_obj_map_by_tag_name; - while (candidate != NULL) { - if (iterate_tag_name) { - candidate = dom_get_elements_by_tag_name_ns_raw(basep, candidate, objmap->ns, objmap->local, objmap->local_lower, &cur, next); - if (candidate == NULL) { - break; - } - next = cur + 1; - } else { - if (candidate->type != XML_ELEMENT_NODE) { - candidate = candidate->next; - continue; - } + if (basep != NULL && basep->children != NULL) { + php_dom_obj_map_collection_iter iter = {0}; + iter.candidate = basep->children; + iter.basep = basep; + + while (true) { + objmap->handler->collection_named_item_iter(objmap, &iter); + if (iter.candidate == NULL) { + break; } - ZEND_ASSERT(candidate->type == XML_ELEMENT_NODE); + ZEND_ASSERT(iter.candidate->type == XML_ELEMENT_NODE); xmlAttrPtr attr; /* it has an ID which is key; */ - if ((attr = xmlHasNsProp(candidate, BAD_CAST "id", NULL)) != NULL && dom_compare_value(attr, BAD_CAST ZSTR_VAL(key))) { + if ((attr = xmlHasNsProp(iter.candidate, BAD_CAST "id", NULL)) != NULL && dom_compare_value(attr, BAD_CAST ZSTR_VAL(key))) { ret.context_intern = objmap->baseobj; - ret.node = candidate; + ret.node = iter.candidate; return ret; } /* it is in the HTML namespace and has a name attribute whose value is key; */ - else if (php_dom_ns_is_fast(candidate, php_dom_ns_is_html_magic_token)) { - if ((attr = xmlHasNsProp(candidate, BAD_CAST "name", NULL)) != NULL && dom_compare_value(attr, BAD_CAST ZSTR_VAL(key))) { + else if (php_dom_ns_is_fast(iter.candidate, php_dom_ns_is_html_magic_token)) { + if ((attr = xmlHasNsProp(iter.candidate, BAD_CAST "name", NULL)) != NULL && dom_compare_value(attr, BAD_CAST ZSTR_VAL(key))) { ret.context_intern = objmap->baseobj; - ret.node = candidate; + ret.node = iter.candidate; return ret; } } - - if (!iterate_tag_name) { - candidate = candidate->next; - } } } diff --git a/ext/dom/namednodemap.c b/ext/dom/namednodemap.c index 953731ad84487..dbfd8b8c9f2ca 100644 --- a/ext/dom/namednodemap.c +++ b/ext/dom/namednodemap.c @@ -67,7 +67,7 @@ PHP_METHOD(DOMNamedNodeMap, getNamedItem) } dom_nnodemap_object *objmap = Z_DOMOBJ_P(ZEND_THIS)->ptr; - php_dom_obj_map_get_named_item_into_zval(objmap, named, NULL, return_value); + php_dom_obj_map_get_ns_named_item_into_zval(objmap, named, NULL, return_value); } /* }}} end dom_namednodemap_get_named_item */ @@ -112,7 +112,7 @@ PHP_METHOD(DOMNamedNodeMap, getNamedItemNS) objmap = (dom_nnodemap_object *)intern->ptr; if (objmap != NULL) { - php_dom_obj_map_get_named_item_into_zval(objmap, named, uri, return_value); + php_dom_obj_map_get_ns_named_item_into_zval(objmap, named, uri, return_value); } } /* }}} end dom_namednodemap_get_named_item_ns */ diff --git a/ext/dom/obj_map.c b/ext/dom/obj_map.c index 367171c43007e..9d54cb70d34ba 100644 --- a/ext/dom/obj_map.c +++ b/ext/dom/obj_map.c @@ -266,6 +266,16 @@ static void dom_map_get_elements_item(dom_nnodemap_object *map, zend_long index, } } +static void dom_map_collection_named_item_elements_iter(dom_nnodemap_object *map, php_dom_obj_map_collection_iter *iter) +{ + if (iter->candidate != iter->basep->children) { + iter->candidate = iter->candidate->next; + } + while (iter->candidate && iter->candidate->type != XML_ELEMENT_NODE) { + iter->candidate = iter->candidate->next; + } +} + static void dom_map_get_by_tag_name_item(dom_nnodemap_object *map, zend_long index, zval *return_value) { xmlNodePtr nodep = dom_object_get_node(map->baseobj); @@ -282,6 +292,12 @@ static void dom_map_get_by_tag_name_item(dom_nnodemap_object *map, zend_long ind } } +static void dom_map_collection_named_item_by_tag_name_iter(dom_nnodemap_object *map, php_dom_obj_map_collection_iter *iter) +{ + iter->candidate = dom_get_elements_by_tag_name_ns_raw(iter->basep, iter->candidate, map->ns, map->local, map->local_lower, &iter->cur, iter->next); + iter->next = iter->cur + 1; +} + static void dom_map_get_null_item(dom_nnodemap_object *map, zend_long index, zval *return_value) { RETURN_NULL(); @@ -376,9 +392,9 @@ void php_dom_obj_map_get_item_into_zval(dom_nnodemap_object *objmap, zend_long i } } -void php_dom_obj_map_get_named_item_into_zval(dom_nnodemap_object *objmap, const zend_string *named, const char *ns, zval *return_value) +void php_dom_obj_map_get_ns_named_item_into_zval(dom_nnodemap_object *objmap, const zend_string *named, const char *ns, zval *return_value) { - xmlNodePtr itemnode = objmap->handler->get_named_item(objmap, named, ns); + xmlNodePtr itemnode = objmap->handler->get_ns_named_item(objmap, named, ns); if (itemnode) { DOM_RET_OBJ(itemnode, objmap->baseobj); } else { @@ -390,17 +406,17 @@ void php_dom_obj_map_get_named_item_into_zval(dom_nnodemap_object *objmap, const * === Named item === * **********************/ -static xmlNodePtr dom_map_get_named_item_entity(dom_nnodemap_object *map, const zend_string *named, const char *ns) +static xmlNodePtr dom_map_get_ns_named_item_entity(dom_nnodemap_object *map, const zend_string *named, const char *ns) { return xmlHashLookup(map->ht, BAD_CAST ZSTR_VAL(named)); } -static bool dom_map_has_named_item_xmlht(dom_nnodemap_object *map, const zend_string *named, const char *ns) +static bool dom_map_has_ns_named_item_xmlht(dom_nnodemap_object *map, const zend_string *named, const char *ns) { - return dom_map_get_named_item_entity(map, named, ns) != NULL; + return dom_map_get_ns_named_item_entity(map, named, ns) != NULL; } -static xmlNodePtr dom_map_get_named_item_notation(dom_nnodemap_object *map, const zend_string *named, const char *ns) +static xmlNodePtr dom_map_get_ns_named_item_notation(dom_nnodemap_object *map, const zend_string *named, const char *ns) { xmlNotationPtr notation = xmlHashLookup(map->ht, BAD_CAST ZSTR_VAL(named)); if (notation) { @@ -409,7 +425,7 @@ static xmlNodePtr dom_map_get_named_item_notation(dom_nnodemap_object *map, cons return NULL; } -static xmlNodePtr dom_map_get_named_item_prop(dom_nnodemap_object *map, const zend_string *named, const char *ns) +static xmlNodePtr dom_map_get_ns_named_item_prop(dom_nnodemap_object *map, const zend_string *named, const char *ns) { xmlNodePtr nodep = dom_object_get_node(map->baseobj); if (nodep) { @@ -426,17 +442,17 @@ static xmlNodePtr dom_map_get_named_item_prop(dom_nnodemap_object *map, const ze return NULL; } -static bool dom_map_has_named_item_prop(dom_nnodemap_object *map, const zend_string *named, const char *ns) +static bool dom_map_has_ns_named_item_prop(dom_nnodemap_object *map, const zend_string *named, const char *ns) { - return dom_map_get_named_item_prop(map, named, ns) != NULL; + return dom_map_get_ns_named_item_prop(map, named, ns) != NULL; } -static xmlNodePtr dom_map_get_named_item_null(dom_nnodemap_object *map, const zend_string *named, const char *ns) +static xmlNodePtr dom_map_get_ns_named_item_null(dom_nnodemap_object *map, const zend_string *named, const char *ns) { return NULL; } -static bool dom_map_has_named_item_null(dom_nnodemap_object *map, const zend_string *named, const char *ns) +static bool dom_map_has_ns_named_item_null(dom_nnodemap_object *map, const zend_string *named, const char *ns) { return false; } @@ -448,8 +464,9 @@ static bool dom_map_has_named_item_null(dom_nnodemap_object *map, const zend_str const php_dom_obj_map_handler php_dom_obj_map_attributes = { .length = dom_map_get_prop_length, .get_item = dom_map_get_attributes_item, - .get_named_item = dom_map_get_named_item_prop, - .has_named_item = dom_map_has_named_item_prop, + .get_ns_named_item = dom_map_get_ns_named_item_prop, + .has_ns_named_item = dom_map_has_ns_named_item_prop, + .collection_named_item_iter = NULL, .use_cache = false, .nameless = false, }; @@ -457,8 +474,9 @@ const php_dom_obj_map_handler php_dom_obj_map_attributes = { const php_dom_obj_map_handler php_dom_obj_map_by_tag_name = { .length = dom_map_get_by_tag_name_length, .get_item = dom_map_get_by_tag_name_item, - .get_named_item = dom_map_get_named_item_null, - .has_named_item = dom_map_has_named_item_null, + .get_ns_named_item = dom_map_get_ns_named_item_null, + .has_ns_named_item = dom_map_has_ns_named_item_null, + .collection_named_item_iter = dom_map_collection_named_item_by_tag_name_iter, .use_cache = true, .nameless = true, }; @@ -466,8 +484,9 @@ const php_dom_obj_map_handler php_dom_obj_map_by_tag_name = { const php_dom_obj_map_handler php_dom_obj_map_child_nodes = { .length = dom_map_get_nodes_length, .get_item = dom_map_get_nodes_item, - .get_named_item = dom_map_get_named_item_null, - .has_named_item = dom_map_has_named_item_null, + .get_ns_named_item = dom_map_get_ns_named_item_null, + .has_ns_named_item = dom_map_has_ns_named_item_null, + .collection_named_item_iter = NULL, .use_cache = true, .nameless = true, }; @@ -475,8 +494,9 @@ const php_dom_obj_map_handler php_dom_obj_map_child_nodes = { const php_dom_obj_map_handler php_dom_obj_map_nodeset = { .length = dom_map_get_nodeset_length, .get_item = dom_map_get_nodeset_item, - .get_named_item = dom_map_get_named_item_null, - .has_named_item = dom_map_has_named_item_null, + .get_ns_named_item = dom_map_get_ns_named_item_null, + .has_ns_named_item = dom_map_has_ns_named_item_null, + .collection_named_item_iter = NULL, .use_cache = false, .nameless = true, }; @@ -484,8 +504,9 @@ const php_dom_obj_map_handler php_dom_obj_map_nodeset = { const php_dom_obj_map_handler php_dom_obj_map_entities = { .length = dom_map_get_xmlht_length, .get_item = dom_map_get_entity_item, - .get_named_item = dom_map_get_named_item_entity, - .has_named_item = dom_map_has_named_item_xmlht, + .get_ns_named_item = dom_map_get_ns_named_item_entity, + .has_ns_named_item = dom_map_has_ns_named_item_xmlht, + .collection_named_item_iter = NULL, .use_cache = false, .nameless = false, }; @@ -493,8 +514,9 @@ const php_dom_obj_map_handler php_dom_obj_map_entities = { const php_dom_obj_map_handler php_dom_obj_map_notations = { .length = dom_map_get_xmlht_length, .get_item = dom_map_get_notation_item, - .get_named_item = dom_map_get_named_item_notation, - .has_named_item = dom_map_has_named_item_xmlht, + .get_ns_named_item = dom_map_get_ns_named_item_notation, + .has_ns_named_item = dom_map_has_ns_named_item_xmlht, + .collection_named_item_iter = NULL, .use_cache = false, .nameless = false, }; @@ -502,8 +524,9 @@ const php_dom_obj_map_handler php_dom_obj_map_notations = { const php_dom_obj_map_handler php_dom_obj_map_child_elements = { .length = dom_map_get_elements_length, .get_item = dom_map_get_elements_item, - .get_named_item = dom_map_get_named_item_null, - .has_named_item = dom_map_has_named_item_null, + .get_ns_named_item = dom_map_get_ns_named_item_null, + .has_ns_named_item = dom_map_has_ns_named_item_null, + .collection_named_item_iter = dom_map_collection_named_item_elements_iter, .use_cache = true, .nameless = true, }; @@ -511,8 +534,9 @@ const php_dom_obj_map_handler php_dom_obj_map_child_elements = { const php_dom_obj_map_handler php_dom_obj_map_noop = { .length = dom_map_get_zero_length, .get_item = dom_map_get_null_item, - .get_named_item = dom_map_get_named_item_null, - .has_named_item = dom_map_has_named_item_null, + .get_ns_named_item = dom_map_get_ns_named_item_null, + .has_ns_named_item = dom_map_has_ns_named_item_null, + .collection_named_item_iter = NULL, .use_cache = false, .nameless = true, }; diff --git a/ext/dom/obj_map.h b/ext/dom/obj_map.h index dc2b33bd24fec..97ec43f0011f8 100644 --- a/ext/dom/obj_map.h +++ b/ext/dom/obj_map.h @@ -19,11 +19,17 @@ typedef struct dom_nnodemap_object dom_nnodemap_object; +typedef struct php_dom_obj_map_collection_iter { + zend_long cur, next; + xmlNodePtr candidate, basep; +} php_dom_obj_map_collection_iter; + typedef struct php_dom_obj_map_handler { zend_long (*length)(dom_nnodemap_object *); void (*get_item)(dom_nnodemap_object *, zend_long, zval *); - xmlNodePtr (*get_named_item)(dom_nnodemap_object *, const zend_string *, const char *); - bool (*has_named_item)(dom_nnodemap_object *, const zend_string *, const char *); + xmlNodePtr (*get_ns_named_item)(dom_nnodemap_object *, const zend_string *, const char *); + bool (*has_ns_named_item)(dom_nnodemap_object *, const zend_string *, const char *); + void (*collection_named_item_iter)(dom_nnodemap_object *, php_dom_obj_map_collection_iter *); bool use_cache; bool nameless; } php_dom_obj_map_handler; @@ -51,7 +57,7 @@ typedef struct dom_nnodemap_object { } dom_nnodemap_object; void php_dom_create_obj_map(dom_object *basenode, dom_object *intern, xmlHashTablePtr ht, zend_string *local, zend_string *ns, const php_dom_obj_map_handler *handler); -void php_dom_obj_map_get_named_item_into_zval(dom_nnodemap_object *objmap, const zend_string *named, const char *ns, zval *return_value); +void php_dom_obj_map_get_ns_named_item_into_zval(dom_nnodemap_object *objmap, const zend_string *named, const char *ns, zval *return_value); void php_dom_obj_map_get_item_into_zval(dom_nnodemap_object *objmap, zend_long index, zval *return_value); zend_long php_dom_get_nodelist_length(dom_object *obj); diff --git a/ext/dom/php_dom.c b/ext/dom/php_dom.c index 5df8a1cb1e1ce..9e7896b7853f3 100644 --- a/ext/dom/php_dom.c +++ b/ext/dom/php_dom.c @@ -2373,7 +2373,7 @@ static zval *dom_nodemap_read_dimension(zend_object *object, zval *offset, int t zend_long lval; if (dom_nodemap_or_nodelist_process_offset_as_named(offset, &lval)) { /* exceptional case, switch to named lookup */ - php_dom_obj_map_get_named_item_into_zval(php_dom_obj_from_obj(object)->ptr, Z_STR_P(offset), NULL, rv); + php_dom_obj_map_get_ns_named_item_into_zval(php_dom_obj_from_obj(object)->ptr, Z_STR_P(offset), NULL, rv); return rv; } @@ -2399,7 +2399,7 @@ static int dom_nodemap_has_dimension(zend_object *object, zval *member, int chec if (dom_nodemap_or_nodelist_process_offset_as_named(member, &offset)) { /* exceptional case, switch to named lookup */ dom_nnodemap_object *map = php_dom_obj_from_obj(object)->ptr; - return map->handler->has_named_item(map, Z_STR_P(member), NULL); + return map->handler->has_ns_named_item(map, Z_STR_P(member), NULL); } return offset >= 0 && offset < php_dom_get_namednodemap_length(php_dom_obj_from_obj(object)); @@ -2420,7 +2420,7 @@ static zval *dom_modern_nodemap_read_dimension(zend_object *object, zval *offset if (ZEND_HANDLE_NUMERIC(Z_STR_P(offset), lval)) { map->handler->get_item(map, (zend_long) lval, rv); } else { - php_dom_obj_map_get_named_item_into_zval(map, Z_STR_P(offset), NULL, rv); + php_dom_obj_map_get_ns_named_item_into_zval(map, Z_STR_P(offset), NULL, rv); } } else if (Z_TYPE_P(offset) == IS_LONG) { map->handler->get_item(map, Z_LVAL_P(offset), rv); @@ -2448,7 +2448,7 @@ static int dom_modern_nodemap_has_dimension(zend_object *object, zval *member, i if (ZEND_HANDLE_NUMERIC(Z_STR_P(member), lval)) { return (zend_long) lval >= 0 && (zend_long) lval < php_dom_get_namednodemap_length(obj); } else { - return map->handler->has_named_item(map, Z_STR_P(member), NULL); + return map->handler->has_ns_named_item(map, Z_STR_P(member), NULL); } } else if (Z_TYPE_P(member) == IS_LONG) { zend_long offset = Z_LVAL_P(member);