xref: /PHP-7.4/ext/dom/dom_iterators.c (revision 83804519)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 7                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) The PHP Group                                          |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP license,      |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.php.net/license/3_01.txt                                  |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Authors: Christian Stocker <chregu@php.net>                          |
16    |          Rob Richards <rrichards@php.net>                            |
17    +----------------------------------------------------------------------+
18 */
19 
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 
24 #include "php.h"
25 #if HAVE_LIBXML && HAVE_DOM
26 #include "php_dom.h"
27 #include "dom_ce.h"
28 
29 typedef struct _nodeIterator nodeIterator;
30 struct _nodeIterator {
31 	int cur;
32 	int index;
33 	xmlNode *node;
34 };
35 
36 typedef struct _notationIterator notationIterator;
37 struct _notationIterator {
38 	int cur;
39 	int index;
40 	xmlNotation *notation;
41 };
42 
43 #if LIBXML_VERSION >= 20908
itemHashScanner(void * payload,void * data,const xmlChar * name)44 static void itemHashScanner (void *payload, void *data, const xmlChar *name) /* {{{ */
45 #else
46 static void itemHashScanner (void *payload, void *data, xmlChar *name)
47 #endif
48 {
49 	nodeIterator *priv = (nodeIterator *)data;
50 
51 	if(priv->cur < priv->index) {
52 		priv->cur++;
53 	} else {
54 		if(priv->node == NULL) {
55 			priv->node = (xmlNode *)payload;
56 		}
57 	}
58 }
59 /* }}} */
60 
create_notation(const xmlChar * name,const xmlChar * ExternalID,const xmlChar * SystemID)61 xmlNodePtr create_notation(const xmlChar *name, const xmlChar *ExternalID, const xmlChar *SystemID) /* {{{ */
62 {
63 	xmlEntityPtr ret;
64 
65 	ret = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity));
66     memset(ret, 0, sizeof(xmlEntity));
67     ret->type = XML_NOTATION_NODE;
68     ret->name = xmlStrdup(name);
69 	ret->ExternalID = xmlStrdup(ExternalID);
70 	ret->SystemID = xmlStrdup(SystemID);
71 	ret->length = 0;
72 	ret->content = NULL;
73 	ret->URI = NULL;
74 	ret->orig = NULL;
75 	ret->children = NULL;
76 	ret->parent = NULL;
77 	ret->doc = NULL;
78 	ret->_private = NULL;
79 	ret->last = NULL;
80 	ret->prev = NULL;
81 	return((xmlNodePtr) ret);
82 }
83 /* }}} */
84 
php_dom_libxml_hash_iter(xmlHashTable * ht,int index)85 xmlNode *php_dom_libxml_hash_iter(xmlHashTable *ht, int index) /* {{{ */
86 {
87 	xmlNode *nodep = NULL;
88 	nodeIterator *iter;
89 	int htsize;
90 
91 	if ((htsize = xmlHashSize(ht)) > 0 && index < htsize) {
92 		iter = emalloc(sizeof(nodeIterator));
93 		iter->cur = 0;
94 		iter->index = index;
95 		iter->node = NULL;
96 		xmlHashScan(ht, itemHashScanner, iter);
97 		nodep = iter->node;
98 		efree(iter);
99 		return nodep;
100 	} else {
101 		return NULL;
102 	}
103 }
104 /* }}} */
105 
php_dom_libxml_notation_iter(xmlHashTable * ht,int index)106 xmlNode *php_dom_libxml_notation_iter(xmlHashTable *ht, int index) /* {{{ */
107 {
108 	notationIterator *iter;
109 	xmlNotation *notep = NULL;
110 	int htsize;
111 
112 	if ((htsize = xmlHashSize(ht)) > 0 && index < htsize) {
113 		iter = emalloc(sizeof(notationIterator));
114 		iter->cur = 0;
115 		iter->index = index;
116 		iter->notation = NULL;
117 		xmlHashScan(ht, itemHashScanner, iter);
118 		notep = iter->notation;
119 		efree(iter);
120 		return create_notation(notep->name, notep->PublicID, notep->SystemID);
121 	} else {
122 		return NULL;
123 	}
124 }
125 /* }}} */
126 
php_dom_iterator_dtor(zend_object_iterator * iter)127 static void php_dom_iterator_dtor(zend_object_iterator *iter) /* {{{ */
128 {
129 	php_dom_iterator *iterator = (php_dom_iterator *)iter;
130 
131 	zval_ptr_dtor(&iterator->intern.data);
132 	zval_ptr_dtor(&iterator->curobj);
133 }
134 /* }}} */
135 
php_dom_iterator_valid(zend_object_iterator * iter)136 static int php_dom_iterator_valid(zend_object_iterator *iter) /* {{{ */
137 {
138 
139 	php_dom_iterator *iterator = (php_dom_iterator *)iter;
140 
141 	if (Z_TYPE(iterator->curobj) != IS_UNDEF) {
142 		return SUCCESS;
143 	} else {
144 		return FAILURE;
145 	}
146 }
147 /* }}} */
148 
php_dom_iterator_current_data(zend_object_iterator * iter)149 zval *php_dom_iterator_current_data(zend_object_iterator *iter) /* {{{ */
150 {
151 	php_dom_iterator *iterator = (php_dom_iterator *)iter;
152 
153 	return &iterator->curobj;
154 }
155 /* }}} */
156 
php_dom_iterator_current_key(zend_object_iterator * iter,zval * key)157 static void php_dom_iterator_current_key(zend_object_iterator *iter, zval *key) /* {{{ */
158 {
159 	php_dom_iterator *iterator = (php_dom_iterator *)iter;
160 	zval *object = &iterator->intern.data;
161 
162 	if (instanceof_function(Z_OBJCE_P(object), dom_nodelist_class_entry)) {
163 		ZVAL_LONG(key, iter->index);
164 	} else {
165 		dom_object *intern = Z_DOMOBJ_P(&iterator->curobj);
166 
167 		if (intern != NULL && intern->ptr != NULL) {
168 			xmlNodePtr curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->ptr)->node;
169 			ZVAL_STRINGL(key, (char *) curnode->name, xmlStrlen(curnode->name));
170 		} else {
171 			ZVAL_NULL(key);
172 		}
173 	}
174 }
175 /* }}} */
176 
php_dom_iterator_move_forward(zend_object_iterator * iter)177 static void php_dom_iterator_move_forward(zend_object_iterator *iter) /* {{{ */
178 {
179 	zval *object;
180 	xmlNodePtr curnode = NULL, basenode;
181 	dom_object *intern;
182 	dom_object *nnmap;
183 	dom_nnodemap_object *objmap;
184 	int previndex=0;
185 	HashTable *nodeht;
186 	zval *entry;
187 	zend_bool do_curobj_undef = 1;
188 
189 	php_dom_iterator *iterator = (php_dom_iterator *)iter;
190 
191 	object = &iterator->intern.data;
192 	nnmap = Z_DOMOBJ_P(object);
193 	objmap = (dom_nnodemap_object *)nnmap->ptr;
194 
195 	intern = Z_DOMOBJ_P(&iterator->curobj);
196 
197 	if (intern != NULL && intern->ptr != NULL) {
198 		if (objmap->nodetype != XML_ENTITY_NODE &&
199 			objmap->nodetype != XML_NOTATION_NODE) {
200 			if (objmap->nodetype == DOM_NODESET) {
201 				nodeht = HASH_OF(&objmap->baseobj_zv);
202 				zend_hash_move_forward_ex(nodeht, &iterator->pos);
203 				if ((entry = zend_hash_get_current_data_ex(nodeht, &iterator->pos))) {
204 					zval_ptr_dtor(&iterator->curobj);
205 					ZVAL_UNDEF(&iterator->curobj);
206 					ZVAL_COPY(&iterator->curobj, entry);
207 					do_curobj_undef = 0;
208 				}
209 			} else {
210 				curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->ptr)->node;
211 				if (objmap->nodetype == XML_ATTRIBUTE_NODE ||
212 					objmap->nodetype == XML_ELEMENT_NODE) {
213 					curnode = curnode->next;
214 				} else {
215 					/* Nav the tree evey time as this is LIVE */
216 					basenode = dom_object_get_node(objmap->baseobj);
217 					if (basenode && (basenode->type == XML_DOCUMENT_NODE ||
218 						basenode->type == XML_HTML_DOCUMENT_NODE)) {
219 						basenode = xmlDocGetRootElement((xmlDoc *) basenode);
220 					} else if (basenode) {
221 						basenode = basenode->children;
222 					} else {
223 						goto err;
224 					}
225 					curnode = dom_get_elements_by_tag_name_ns_raw(
226 						basenode, (char *) objmap->ns, (char *) objmap->local, &previndex, iter->index);
227 				}
228 			}
229 		} else {
230 			if (objmap->nodetype == XML_ENTITY_NODE) {
231 				curnode = php_dom_libxml_hash_iter(objmap->ht, iter->index);
232 			} else {
233 				curnode = php_dom_libxml_notation_iter(objmap->ht, iter->index);
234 			}
235 		}
236 	}
237 err:
238 	if (do_curobj_undef) {
239 		zval_ptr_dtor(&iterator->curobj);
240 		ZVAL_UNDEF(&iterator->curobj);
241 	}
242 	if (curnode) {
243 		php_dom_create_object(curnode, &iterator->curobj, objmap->baseobj);
244 	}
245 }
246 /* }}} */
247 
248 static const zend_object_iterator_funcs php_dom_iterator_funcs = {
249 	php_dom_iterator_dtor,
250 	php_dom_iterator_valid,
251 	php_dom_iterator_current_data,
252 	php_dom_iterator_current_key,
253 	php_dom_iterator_move_forward,
254 	NULL,
255 	NULL
256 };
257 
php_dom_get_iterator(zend_class_entry * ce,zval * object,int by_ref)258 zend_object_iterator *php_dom_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */
259 {
260 	dom_object *intern;
261 	dom_nnodemap_object *objmap;
262 	xmlNodePtr nodep, curnode=NULL;
263 	int curindex = 0;
264 	HashTable *nodeht;
265 	zval *entry;
266 	php_dom_iterator *iterator;
267 
268 	if (by_ref) {
269 		zend_throw_error(NULL, "An iterator cannot be used with foreach by reference");
270 		return NULL;
271 	}
272 	iterator = emalloc(sizeof(php_dom_iterator));
273 	zend_iterator_init(&iterator->intern);
274 
275 	Z_ADDREF_P(object);
276 	ZVAL_OBJ(&iterator->intern.data, Z_OBJ_P(object));
277 	iterator->intern.funcs = &php_dom_iterator_funcs;
278 
279 	ZVAL_UNDEF(&iterator->curobj);
280 
281 	intern = Z_DOMOBJ_P(object);
282 	objmap = (dom_nnodemap_object *)intern->ptr;
283 	if (objmap != NULL) {
284 		if (objmap->nodetype != XML_ENTITY_NODE &&
285 			objmap->nodetype != XML_NOTATION_NODE) {
286 			if (objmap->nodetype == DOM_NODESET) {
287 				nodeht = HASH_OF(&objmap->baseobj_zv);
288 				zend_hash_internal_pointer_reset_ex(nodeht, &iterator->pos);
289 				if ((entry = zend_hash_get_current_data_ex(nodeht, &iterator->pos))) {
290 					ZVAL_COPY(&iterator->curobj, entry);
291 				}
292 			} else {
293 				nodep = (xmlNode *)dom_object_get_node(objmap->baseobj);
294 				if (!nodep) {
295 					goto err;
296 				}
297 				if (objmap->nodetype == XML_ATTRIBUTE_NODE || objmap->nodetype == XML_ELEMENT_NODE) {
298 					if (objmap->nodetype == XML_ATTRIBUTE_NODE) {
299 						curnode = (xmlNodePtr) nodep->properties;
300 					} else {
301 						curnode = (xmlNodePtr) nodep->children;
302 					}
303 				} else {
304 					if (nodep->type == XML_DOCUMENT_NODE || nodep->type == XML_HTML_DOCUMENT_NODE) {
305 						nodep = xmlDocGetRootElement((xmlDoc *) nodep);
306 					} else {
307 						nodep = nodep->children;
308 					}
309 					curnode = dom_get_elements_by_tag_name_ns_raw(
310 						nodep, (char *) objmap->ns, (char *) objmap->local, &curindex, 0);
311 				}
312 			}
313 		} else {
314 			if (objmap->nodetype == XML_ENTITY_NODE) {
315 				curnode = php_dom_libxml_hash_iter(objmap->ht, 0);
316 			} else {
317 				curnode = php_dom_libxml_notation_iter(objmap->ht, 0);
318 			}
319 		}
320 	}
321 err:
322 	if (curnode) {
323 		php_dom_create_object(curnode, &iterator->curobj, objmap->baseobj);
324 	}
325 
326 	return &iterator->intern;
327 }
328 /* }}} */
329 
330 #endif
331