xref: /PHP-7.2/ext/dom/dom_iterators.c (revision a820aab9)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 7                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2018 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 /* $Id$ */
21 
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 
26 #include "php.h"
27 #if HAVE_LIBXML && HAVE_DOM
28 #include "php_dom.h"
29 #include "dom_ce.h"
30 
31 typedef struct _nodeIterator nodeIterator;
32 struct _nodeIterator {
33 	int cur;
34 	int index;
35 	xmlNode *node;
36 };
37 
38 typedef struct _notationIterator notationIterator;
39 struct _notationIterator {
40 	int cur;
41 	int index;
42 	xmlNotation *notation;
43 };
44 
45 #if LIBXML_VERSION >= 20908
itemHashScanner(void * payload,void * data,const xmlChar * name)46 static void itemHashScanner (void *payload, void *data, const xmlChar *name) /* {{{ */
47 #else
48 static void itemHashScanner (void *payload, void *data, xmlChar *name)
49 #endif
50 {
51 	nodeIterator *priv = (nodeIterator *)data;
52 
53 	if(priv->cur < priv->index) {
54 		priv->cur++;
55 	} else {
56 		if(priv->node == NULL) {
57 			priv->node = (xmlNode *)payload;
58 		}
59 	}
60 }
61 /* }}} */
62 
create_notation(const xmlChar * name,const xmlChar * ExternalID,const xmlChar * SystemID)63 xmlNodePtr create_notation(const xmlChar *name, const xmlChar *ExternalID, const xmlChar *SystemID) /* {{{ */
64 {
65 	xmlEntityPtr ret;
66 
67 	ret = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity));
68     memset(ret, 0, sizeof(xmlEntity));
69     ret->type = XML_NOTATION_NODE;
70     ret->name = xmlStrdup(name);
71 	ret->ExternalID = xmlStrdup(ExternalID);
72 	ret->SystemID = xmlStrdup(SystemID);
73 	ret->length = 0;
74 	ret->content = NULL;
75 	ret->URI = NULL;
76 	ret->orig = NULL;
77 	ret->children = NULL;
78 	ret->parent = NULL;
79 	ret->doc = NULL;
80 	ret->_private = NULL;
81 	ret->last = NULL;
82 	ret->prev = NULL;
83 	return((xmlNodePtr) ret);
84 }
85 /* }}} */
86 
php_dom_libxml_hash_iter(xmlHashTable * ht,int index)87 xmlNode *php_dom_libxml_hash_iter(xmlHashTable *ht, int index) /* {{{ */
88 {
89 	xmlNode *nodep = NULL;
90 	nodeIterator *iter;
91 	int htsize;
92 
93 	if ((htsize = xmlHashSize(ht)) > 0 && index < htsize) {
94 		iter = emalloc(sizeof(nodeIterator));
95 		iter->cur = 0;
96 		iter->index = index;
97 		iter->node = NULL;
98 		xmlHashScan(ht, itemHashScanner, iter);
99 		nodep = iter->node;
100 		efree(iter);
101 		return nodep;
102 	} else {
103 		return NULL;
104 	}
105 }
106 /* }}} */
107 
php_dom_libxml_notation_iter(xmlHashTable * ht,int index)108 xmlNode *php_dom_libxml_notation_iter(xmlHashTable *ht, int index) /* {{{ */
109 {
110 	notationIterator *iter;
111 	xmlNotation *notep = NULL;
112 	int htsize;
113 
114 	if ((htsize = xmlHashSize(ht)) > 0 && index < htsize) {
115 		iter = emalloc(sizeof(notationIterator));
116 		iter->cur = 0;
117 		iter->index = index;
118 		iter->notation = NULL;
119 		xmlHashScan(ht, itemHashScanner, iter);
120 		notep = iter->notation;
121 		efree(iter);
122 		return create_notation(notep->name, notep->PublicID, notep->SystemID);
123 	} else {
124 		return NULL;
125 	}
126 }
127 /* }}} */
128 
php_dom_iterator_dtor(zend_object_iterator * iter)129 static void php_dom_iterator_dtor(zend_object_iterator *iter) /* {{{ */
130 {
131 	php_dom_iterator *iterator = (php_dom_iterator *)iter;
132 
133 	zval_ptr_dtor(&iterator->intern.data);
134 	zval_ptr_dtor(&iterator->curobj);
135 }
136 /* }}} */
137 
php_dom_iterator_valid(zend_object_iterator * iter)138 static int php_dom_iterator_valid(zend_object_iterator *iter) /* {{{ */
139 {
140 
141 	php_dom_iterator *iterator = (php_dom_iterator *)iter;
142 
143 	if (Z_TYPE(iterator->curobj) != IS_UNDEF) {
144 		return SUCCESS;
145 	} else {
146 		return FAILURE;
147 	}
148 }
149 /* }}} */
150 
php_dom_iterator_current_data(zend_object_iterator * iter)151 zval *php_dom_iterator_current_data(zend_object_iterator *iter) /* {{{ */
152 {
153 	php_dom_iterator *iterator = (php_dom_iterator *)iter;
154 
155 	return &iterator->curobj;
156 }
157 /* }}} */
158 
php_dom_iterator_current_key(zend_object_iterator * iter,zval * key)159 static void php_dom_iterator_current_key(zend_object_iterator *iter, zval *key) /* {{{ */
160 {
161 	php_dom_iterator *iterator = (php_dom_iterator *)iter;
162 	zval *object = &iterator->intern.data;
163 
164 	if (instanceof_function(Z_OBJCE_P(object), dom_nodelist_class_entry)) {
165 		ZVAL_LONG(key, iter->index);
166 	} else {
167 		dom_object *intern = Z_DOMOBJ_P(&iterator->curobj);
168 
169 		if (intern != NULL && intern->ptr != NULL) {
170 			xmlNodePtr curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->ptr)->node;
171 			ZVAL_STRINGL(key, (char *) curnode->name, xmlStrlen(curnode->name));
172 		} else {
173 			ZVAL_NULL(key);
174 		}
175 	}
176 }
177 /* }}} */
178 
php_dom_iterator_move_forward(zend_object_iterator * iter)179 static void php_dom_iterator_move_forward(zend_object_iterator *iter) /* {{{ */
180 {
181 	zval *object;
182 	xmlNodePtr curnode = NULL, basenode;
183 	dom_object *intern;
184 	dom_object *nnmap;
185 	dom_nnodemap_object *objmap;
186 	int previndex=0;
187 	HashTable *nodeht;
188 	zval *entry;
189 	zend_bool do_curobj_undef = 1;
190 
191 	php_dom_iterator *iterator = (php_dom_iterator *)iter;
192 
193 	object = &iterator->intern.data;
194 	nnmap = Z_DOMOBJ_P(object);
195 	objmap = (dom_nnodemap_object *)nnmap->ptr;
196 
197 	intern = Z_DOMOBJ_P(&iterator->curobj);
198 
199 	if (intern != NULL && intern->ptr != NULL) {
200 		if (objmap->nodetype != XML_ENTITY_NODE &&
201 			objmap->nodetype != XML_NOTATION_NODE) {
202 			if (objmap->nodetype == DOM_NODESET) {
203 				nodeht = HASH_OF(&objmap->baseobj_zv);
204 				zend_hash_move_forward(nodeht);
205 				if ((entry = zend_hash_get_current_data(nodeht))) {
206 					zval_ptr_dtor(&iterator->curobj);
207 					ZVAL_UNDEF(&iterator->curobj);
208 					ZVAL_COPY(&iterator->curobj, entry);
209 					do_curobj_undef = 0;
210 				}
211 			} else {
212 				curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->ptr)->node;
213 				if (objmap->nodetype == XML_ATTRIBUTE_NODE ||
214 					objmap->nodetype == XML_ELEMENT_NODE) {
215 					curnode = curnode->next;
216 				} else {
217 					/* Nav the tree evey time as this is LIVE */
218 					basenode = dom_object_get_node(objmap->baseobj);
219 					if (basenode && (basenode->type == XML_DOCUMENT_NODE ||
220 						basenode->type == XML_HTML_DOCUMENT_NODE)) {
221 						basenode = xmlDocGetRootElement((xmlDoc *) basenode);
222 					} else if (basenode) {
223 						basenode = basenode->children;
224 					} else {
225 						goto err;
226 					}
227 					curnode = dom_get_elements_by_tag_name_ns_raw(
228 						basenode, (char *) objmap->ns, (char *) objmap->local, &previndex, iter->index);
229 				}
230 			}
231 		} else {
232 			if (objmap->nodetype == XML_ENTITY_NODE) {
233 				curnode = php_dom_libxml_hash_iter(objmap->ht, iter->index);
234 			} else {
235 				curnode = php_dom_libxml_notation_iter(objmap->ht, iter->index);
236 			}
237 		}
238 	}
239 err:
240 	if (do_curobj_undef) {
241 		zval_ptr_dtor(&iterator->curobj);
242 		ZVAL_UNDEF(&iterator->curobj);
243 	}
244 	if (curnode) {
245 		php_dom_create_object(curnode, &iterator->curobj, objmap->baseobj);
246 	}
247 }
248 /* }}} */
249 
250 zend_object_iterator_funcs php_dom_iterator_funcs = {
251 	php_dom_iterator_dtor,
252 	php_dom_iterator_valid,
253 	php_dom_iterator_current_data,
254 	php_dom_iterator_current_key,
255 	php_dom_iterator_move_forward,
256 	NULL,
257 	NULL
258 };
259 
php_dom_get_iterator(zend_class_entry * ce,zval * object,int by_ref)260 zend_object_iterator *php_dom_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */
261 {
262 	dom_object *intern;
263 	dom_nnodemap_object *objmap;
264 	xmlNodePtr nodep, curnode=NULL;
265 	int curindex = 0;
266 	HashTable *nodeht;
267 	zval *entry;
268 	php_dom_iterator *iterator;
269 
270 	if (by_ref) {
271 		zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
272 	}
273 	iterator = emalloc(sizeof(php_dom_iterator));
274 	zend_iterator_init(&iterator->intern);
275 
276 	ZVAL_COPY(&iterator->intern.data, 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(nodeht);
289 				if ((entry = zend_hash_get_current_data(nodeht))) {
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 
332 /*
333  * Local variables:
334  * tab-width: 4
335  * c-basic-offset: 4
336  * End:
337  * vim600: noet sw=4 ts=4 fdm=marker
338  * vim<600: noet sw=4 ts=4
339  */
340