Skip to content

Commit ff0a2cf

Browse files
committed
Refactor implementation of DOM nodelists, named maps, and iterators
The code was really messy with lots of checks and inconsistencies. This splits everything up into different functions and now everything is relayed to a handler vtable.
1 parent 4fadf64 commit ff0a2cf

16 files changed

+521
-421
lines changed

ext/dom/config.m4

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ if test "$PHP_DOM" != "no"; then
3333
node.c
3434
nodelist.c
3535
notation.c
36+
obj_map.c
3637
parentnode/css_selectors.c
3738
parentnode/tree.c
3839
php_dom.c

ext/dom/config.w32

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ if (PHP_DOM == "yes") {
1515
entity.c nodelist.c html_collection.c text.c comment.c \
1616
entityreference.c \
1717
token_list.c \
18-
notation.c xpath.c dom_iterators.c \
18+
notation.c obj_map.c xpath.c dom_iterators.c \
1919
namednodemap.c xpath_callbacks.c", null, "/I ext/lexbor");
2020

2121
ADD_EXTENSION_DEP('dom', 'lexbor');

ext/dom/documenttype.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ zend_result dom_documenttype_entities_read(dom_object *obj, zval *retval)
5353
xmlHashTable *entityht = (xmlHashTable *) dtdptr->entities;
5454

5555
dom_object *intern = Z_DOMOBJ_P(retval);
56-
dom_namednode_iter(obj, XML_ENTITY_NODE, intern, entityht, NULL, NULL);
56+
dom_namednode_iter(obj, intern, entityht, NULL, NULL, &php_dom_obj_map_entities);
5757

5858
return SUCCESS;
5959
}
@@ -74,7 +74,7 @@ zend_result dom_documenttype_notations_read(dom_object *obj, zval *retval)
7474
xmlHashTable *notationht = (xmlHashTable *) dtdptr->notations;
7575

7676
dom_object *intern = Z_DOMOBJ_P(retval);
77-
dom_namednode_iter(obj, XML_NOTATION_NODE, intern, notationht, NULL, NULL);
77+
dom_namednode_iter(obj, intern, notationht, NULL, NULL, &php_dom_obj_map_notations);
7878

7979
return SUCCESS;
8080
}

ext/dom/dom_iterators.c

Lines changed: 21 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ xmlNodePtr create_notation(const xmlChar *name, const xmlChar *ExternalID, const
6868
}
6969
/* }}} */
7070

71-
static xmlNode *php_dom_libxml_hash_iter_ex(xmlHashTable *ht, int index)
71+
xmlNodePtr php_dom_libxml_hash_iter(xmlHashTable *ht, int index)
7272
{
7373
int htsize;
7474

@@ -84,18 +84,6 @@ static xmlNode *php_dom_libxml_hash_iter_ex(xmlHashTable *ht, int index)
8484
}
8585
}
8686

87-
xmlNode *php_dom_libxml_hash_iter(dom_nnodemap_object *objmap, int index)
88-
{
89-
xmlNode *curnode = php_dom_libxml_hash_iter_ex(objmap->ht, index);
90-
91-
if (curnode != NULL && objmap->nodetype != XML_ENTITY_NODE) {
92-
xmlNotation *notation = (xmlNotation *) curnode;
93-
curnode = create_notation(notation->name, notation->PublicID, notation->SystemID);
94-
}
95-
96-
return curnode;
97-
}
98-
9987
static void php_dom_iterator_dtor(zend_object_iterator *iter) /* {{{ */
10088
{
10189
php_dom_iterator *iterator = (php_dom_iterator *)iter;
@@ -109,7 +97,7 @@ static zend_result php_dom_iterator_valid(zend_object_iterator *iter) /* {{{ */
10997
{
11098
php_dom_iterator *iterator = (php_dom_iterator *)iter;
11199

112-
if (Z_TYPE(iterator->curobj) != IS_UNDEF) {
100+
if (!Z_ISNULL(iterator->curobj)) {
113101
return SUCCESS;
114102
} else {
115103
return FAILURE;
@@ -120,7 +108,7 @@ static zend_result php_dom_iterator_valid(zend_object_iterator *iter) /* {{{ */
120108
zval *php_dom_iterator_current_data(zend_object_iterator *iter) /* {{{ */
121109
{
122110
php_dom_iterator *iterator = (php_dom_iterator *)iter;
123-
return Z_ISUNDEF(iterator->curobj) ? NULL : &iterator->curobj;
111+
return Z_ISNULL(iterator->curobj) ? NULL : &iterator->curobj;
124112
}
125113
/* }}} */
126114

@@ -131,14 +119,14 @@ static void php_dom_iterator_current_key(zend_object_iterator *iter, zval *key)
131119

132120
/* Only dtd named node maps, i.e. the ones based on a libxml hash table or attribute collections,
133121
* are keyed by the name because in that case the name is unique. */
134-
if (!objmap->ht && objmap->nodetype != XML_ATTRIBUTE_NODE) {
122+
if (objmap->handler->nameless) {
135123
ZVAL_LONG(key, iterator->index);
136124
} else {
137125
dom_object *intern = Z_DOMOBJ_P(&iterator->curobj);
138126

139-
if (intern != NULL && intern->ptr != NULL) {
127+
if (intern->ptr != NULL) {
140128
xmlNodePtr curnode = ((php_libxml_node_ptr *)intern->ptr)->node;
141-
if (objmap->nodetype == XML_ATTRIBUTE_NODE && php_dom_follow_spec_intern(intern)) {
129+
if (curnode->type == XML_ATTRIBUTE_NODE && php_dom_follow_spec_intern(intern)) {
142130
ZVAL_NEW_STR(key, dom_node_get_node_name_attribute_or_element(curnode, false));
143131
} else {
144132
ZVAL_STRINGL(key, (const char *) curnode->name, xmlStrlen(curnode->name));
@@ -150,99 +138,36 @@ static void php_dom_iterator_current_key(zend_object_iterator *iter, zval *key)
150138
}
151139
/* }}} */
152140

153-
static xmlNodePtr dom_fetch_first_iteration_item(dom_nnodemap_object *objmap)
154-
{
155-
xmlNodePtr basep = dom_object_get_node(objmap->baseobj);
156-
if (!basep) {
157-
return NULL;
158-
}
159-
if (objmap->nodetype == XML_ATTRIBUTE_NODE || objmap->nodetype == XML_ELEMENT_NODE) {
160-
if (objmap->nodetype == XML_ATTRIBUTE_NODE) {
161-
return (xmlNodePtr) basep->properties;
162-
} else {
163-
return dom_nodelist_iter_start_first_child(basep);
164-
}
165-
} else {
166-
zend_long curindex = 0;
167-
xmlNodePtr nodep = php_dom_first_child_of_container_node(basep);
168-
return dom_get_elements_by_tag_name_ns_raw(
169-
basep, nodep, objmap->ns, objmap->local, objmap->local_lower, &curindex, 0);
170-
}
171-
}
172-
173141
static void php_dom_iterator_move_forward(zend_object_iterator *iter) /* {{{ */
174142
{
175-
xmlNodePtr curnode = NULL;
176-
177143
php_dom_iterator *iterator = (php_dom_iterator *)iter;
178-
if (Z_ISUNDEF(iterator->curobj)) {
144+
if (Z_ISNULL(iterator->curobj)) {
179145
return;
180146
}
181147

182148
iterator->index++;
149+
zval garbage;
150+
ZVAL_COPY_VALUE(&garbage, &iterator->curobj);
151+
ZVAL_NULL(&iterator->curobj);
183152

184153
dom_object *intern = Z_DOMOBJ_P(&iterator->curobj);
185154
dom_nnodemap_object *objmap = php_dom_iterator_get_nnmap(iterator);
186155

187-
if (intern != NULL && intern->ptr != NULL) {
188-
if (objmap->nodetype != XML_ENTITY_NODE &&
189-
objmap->nodetype != XML_NOTATION_NODE) {
190-
if (objmap->nodetype == DOM_NODESET) {
191-
HashTable *nodeht = Z_ARRVAL_P(&objmap->baseobj_zv);
192-
zval *entry = zend_hash_index_find(nodeht, iterator->index);
193-
if (entry) {
194-
zval_ptr_dtor(&iterator->curobj);
195-
ZVAL_COPY(&iterator->curobj, entry);
196-
return;
197-
}
198-
} else {
199-
if (objmap->nodetype == XML_ATTRIBUTE_NODE ||
200-
objmap->nodetype == XML_ELEMENT_NODE) {
201-
202-
/* Note: keep legacy behaviour for non-spec mode. */
203-
if (php_dom_follow_spec_intern(intern) && php_dom_is_cache_tag_stale_from_doc_ptr(&iterator->cache_tag, intern->document)) {
204-
php_dom_mark_cache_tag_up_to_date_from_doc_ref(&iterator->cache_tag, intern->document);
205-
curnode = dom_fetch_first_iteration_item(objmap);
206-
zend_ulong index = 0;
207-
while (curnode != NULL && index++ < iterator->index) {
208-
curnode = curnode->next;
209-
}
210-
} else {
211-
curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->ptr)->node;
212-
curnode = curnode->next;
213-
}
214-
} else {
215-
/* The collection is live, we nav the tree from the base object if we cannot
216-
* use the cache to restart from the last point. */
217-
xmlNodePtr basenode = dom_object_get_node(objmap->baseobj);
218-
219-
/* We have a strong reference to the base node via baseobj_zv, this cannot become NULL */
220-
ZEND_ASSERT(basenode != NULL);
221-
222-
zend_long previndex;
223-
if (php_dom_is_cache_tag_stale_from_node(&iterator->cache_tag, basenode)) {
224-
php_dom_mark_cache_tag_up_to_date_from_node(&iterator->cache_tag, basenode);
225-
previndex = 0;
226-
curnode = php_dom_first_child_of_container_node(basenode);
227-
} else {
228-
previndex = iterator->index - 1;
229-
curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->ptr)->node;
230-
}
231-
curnode = dom_get_elements_by_tag_name_ns_raw(
232-
basenode, curnode, objmap->ns, objmap->local, objmap->local_lower, &previndex, iterator->index);
233-
}
156+
if (intern->ptr != NULL) {
157+
/* Note: keep legacy behaviour for non-spec mode. */
158+
/* TODO: make this prettier */
159+
if (!php_dom_follow_spec_intern(intern) && (objmap->handler == &php_dom_obj_map_attributes || objmap->handler == &php_dom_obj_map_child_nodes)) {
160+
xmlNodePtr curnode = ((php_libxml_node_ptr *) intern->ptr)->node;
161+
curnode = curnode->next;
162+
if (curnode) {
163+
php_dom_create_object(curnode, &iterator->curobj, objmap->baseobj);
234164
}
235165
} else {
236-
curnode = php_dom_libxml_hash_iter(objmap, iterator->index);
166+
objmap->handler->get_item(objmap, (zend_long) iterator->index, &iterator->curobj);
237167
}
238168
}
239169

240-
zval_ptr_dtor(&iterator->curobj);
241-
ZVAL_UNDEF(&iterator->curobj);
242-
243-
if (curnode) {
244-
php_dom_create_object(curnode, &iterator->curobj, objmap->baseobj);
245-
}
170+
zval_ptr_dtor(&garbage);
246171
}
247172
/* }}} */
248173

@@ -261,7 +186,6 @@ zend_object_iterator *php_dom_get_iterator(zend_class_entry *ce, zval *object, i
261186
{
262187
dom_object *intern;
263188
dom_nnodemap_object *objmap;
264-
xmlNodePtr curnode=NULL;
265189
php_dom_iterator *iterator;
266190

267191
if (by_ref) {
@@ -277,26 +201,7 @@ zend_object_iterator *php_dom_get_iterator(zend_class_entry *ce, zval *object, i
277201

278202
intern = Z_DOMOBJ_P(object);
279203
objmap = (dom_nnodemap_object *)intern->ptr;
280-
if (objmap != NULL) {
281-
if (objmap->nodetype != XML_ENTITY_NODE &&
282-
objmap->nodetype != XML_NOTATION_NODE) {
283-
if (objmap->nodetype == DOM_NODESET) {
284-
HashTable *nodeht = Z_ARRVAL_P(&objmap->baseobj_zv);
285-
zval *entry = zend_hash_index_find(nodeht, 0);
286-
if (entry) {
287-
ZVAL_COPY(&iterator->curobj, entry);
288-
}
289-
} else {
290-
curnode = dom_fetch_first_iteration_item(objmap);
291-
}
292-
} else {
293-
curnode = php_dom_libxml_hash_iter(objmap, 0);
294-
}
295-
}
296-
297-
if (curnode) {
298-
php_dom_create_object(curnode, &iterator->curobj, objmap->baseobj);
299-
}
204+
objmap->handler->get_item(objmap, 0, &iterator->curobj);
300205

301206
return &iterator->intern;
302207
}

ext/dom/element.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -825,7 +825,7 @@ static void dom_element_get_elements_by_tag_name(INTERNAL_FUNCTION_PARAMETERS, z
825825

826826
object_init_ex(return_value, iter_ce);
827827
namednode = Z_DOMOBJ_P(return_value);
828-
dom_namednode_iter(intern, 0, namednode, NULL, name, NULL);
828+
dom_namednode_iter(intern, namednode, NULL, name, NULL, &php_dom_obj_map_by_tag_name);
829829
}
830830

831831
PHP_METHOD(DOMElement, getElementsByTagName)
@@ -1257,7 +1257,7 @@ static void dom_element_get_elements_by_tag_name_ns(INTERNAL_FUNCTION_PARAMETERS
12571257

12581258
object_init_ex(return_value, iter_ce);
12591259
namednode = Z_DOMOBJ_P(return_value);
1260-
dom_namednode_iter(intern, 0, namednode, NULL, name, uri);
1260+
dom_namednode_iter(intern, namednode, NULL, name, uri, &php_dom_obj_map_by_tag_name);
12611261
}
12621262

12631263
PHP_METHOD(DOMElement, getElementsByTagNameNS)

0 commit comments

Comments
 (0)