xref: /PHP-5.6/ext/dom/dom_iterators.c (revision 49493a2d)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 5                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2016 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 
itemHashScanner(void * payload,void * data,xmlChar * name)45 static void itemHashScanner (void *payload, void *data, xmlChar *name) /* {{{ */
46 {
47 	nodeIterator *priv = (nodeIterator *)data;
48 
49 	if(priv->cur < priv->index) {
50 		priv->cur++;
51 	} else {
52 		if(priv->node == NULL) {
53 			priv->node = (xmlNode *)payload;
54 		}
55 	}
56 }
57 /* }}} */
58 
create_notation(const xmlChar * name,const xmlChar * ExternalID,const xmlChar * SystemID)59 xmlNodePtr create_notation(const xmlChar *name, const xmlChar *ExternalID, const xmlChar *SystemID) /* {{{ */
60 {
61 	xmlEntityPtr ret;
62 
63 	ret = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity));
64     memset(ret, 0, sizeof(xmlEntity));
65     ret->type = XML_NOTATION_NODE;
66     ret->name = xmlStrdup(name);
67 	ret->ExternalID = xmlStrdup(ExternalID);
68 	ret->SystemID = xmlStrdup(SystemID);
69 	ret->length = 0;
70 	ret->content = NULL;
71 	ret->URI = NULL;
72 	ret->orig = NULL;
73 	ret->children = NULL;
74 	ret->parent = NULL;
75 	ret->doc = NULL;
76 	ret->_private = NULL;
77 	ret->last = NULL;
78 	ret->prev = NULL;
79 	return((xmlNodePtr) ret);
80 }
81 /* }}} */
82 
php_dom_libxml_hash_iter(xmlHashTable * ht,int index)83 xmlNode *php_dom_libxml_hash_iter(xmlHashTable *ht, int index) /* {{{ */
84 {
85 	xmlNode *nodep = NULL;
86 	nodeIterator *iter;
87 	int htsize;
88 
89 	if ((htsize = xmlHashSize(ht)) > 0 && index < htsize) {
90 		iter = emalloc(sizeof(nodeIterator));
91 		iter->cur = 0;
92 		iter->index = index;
93 		iter->node = NULL;
94 		xmlHashScan(ht, itemHashScanner, iter);
95 		nodep = iter->node;
96 		efree(iter);
97 		return nodep;
98 	} else {
99 		return NULL;
100 	}
101 }
102 /* }}} */
103 
php_dom_libxml_notation_iter(xmlHashTable * ht,int index)104 xmlNode *php_dom_libxml_notation_iter(xmlHashTable *ht, int index) /* {{{ */
105 {
106 	notationIterator *iter;
107 	xmlNotation *notep = NULL;
108 	int htsize;
109 
110 	if ((htsize = xmlHashSize(ht)) > 0 && index < htsize) {
111 		iter = emalloc(sizeof(notationIterator));
112 		iter->cur = 0;
113 		iter->index = index;
114 		iter->notation = NULL;
115 		xmlHashScan(ht, itemHashScanner, iter);
116 		notep = iter->notation;
117 		efree(iter);
118 		return create_notation(notep->name, notep->PublicID, notep->SystemID);
119 	} else {
120 		return NULL;
121 	}
122 }
123 /* }}} */
124 
php_dom_iterator_dtor(zend_object_iterator * iter TSRMLS_DC)125 static void php_dom_iterator_dtor(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
126 {
127 	php_dom_iterator *iterator = (php_dom_iterator *)iter;
128 
129 	zval_ptr_dtor((zval**)&iterator->intern.data);
130 
131 	if (iterator->curobj) {
132 		zval_ptr_dtor((zval**)&iterator->curobj);
133 	}
134 
135 	efree(iterator);
136 }
137 /* }}} */
138 
php_dom_iterator_valid(zend_object_iterator * iter TSRMLS_DC)139 static int php_dom_iterator_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
140 {
141 
142 	php_dom_iterator *iterator = (php_dom_iterator *)iter;
143 
144 	if (iterator->curobj) {
145 		return SUCCESS;
146 	} else {
147 		return FAILURE;
148 	}
149 }
150 /* }}} */
151 
php_dom_iterator_current_data(zend_object_iterator * iter,zval *** data TSRMLS_DC)152 static void php_dom_iterator_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) /* {{{ */
153 {
154 	php_dom_iterator *iterator = (php_dom_iterator *)iter;
155 
156 	*data = &iterator->curobj;
157 }
158 /* }}} */
159 
php_dom_iterator_current_key(zend_object_iterator * iter,zval * key TSRMLS_DC)160 static void php_dom_iterator_current_key(zend_object_iterator *iter, zval *key TSRMLS_DC) /* {{{ */
161 {
162 	php_dom_iterator *iterator = (php_dom_iterator *)iter;
163 	zval *object = (zval *)iterator->intern.data;
164 
165 	if (instanceof_function(Z_OBJCE_P(object), dom_nodelist_class_entry TSRMLS_CC)) {
166 		ZVAL_LONG(key, iter->index);
167 	} else {
168 		dom_object *intern = (dom_object *)zend_object_store_get_object(iterator->curobj TSRMLS_CC);
169 
170 		if (intern != NULL && intern->ptr != NULL) {
171 			xmlNodePtr curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->ptr)->node;
172 			ZVAL_STRINGL(key, (char *) curnode->name, xmlStrlen(curnode->name), 1);
173 		} else {
174 			ZVAL_NULL(key);
175 		}
176 	}
177 }
178 /* }}} */
179 
php_dom_iterator_move_forward(zend_object_iterator * iter TSRMLS_DC)180 static void php_dom_iterator_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
181 {
182 	zval *curobj, *curattr = NULL;
183 	zval *object;
184 	xmlNodePtr curnode = NULL, basenode;
185 	dom_object *intern;
186 	dom_object *nnmap;
187 	dom_nnodemap_object *objmap;
188 	int ret, previndex=0;
189 	HashTable *nodeht;
190 	zval **entry;
191 
192 	php_dom_iterator *iterator = (php_dom_iterator *)iter;
193 
194 	object = (zval *)iterator->intern.data;
195 	nnmap = (dom_object *)zend_object_store_get_object(object TSRMLS_CC);
196 	objmap = (dom_nnodemap_object *)nnmap->ptr;
197 
198 	curobj = iterator->curobj;
199 	intern = (dom_object *)zend_object_store_get_object(curobj TSRMLS_CC);
200 	if (intern != NULL && intern->ptr != NULL) {
201 		if (objmap->nodetype != XML_ENTITY_NODE &&
202 			objmap->nodetype != XML_NOTATION_NODE) {
203 			if (objmap->nodetype == DOM_NODESET) {
204 				nodeht = HASH_OF(objmap->baseobjptr);
205 				zend_hash_move_forward(nodeht);
206 				if (zend_hash_get_current_data(nodeht, (void **) &entry)==SUCCESS) {
207 					curattr = *entry;
208 					Z_ADDREF_P(curattr);
209 				}
210 			} else {
211 				curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->ptr)->node;
212 				if (objmap->nodetype == XML_ATTRIBUTE_NODE ||
213 					objmap->nodetype == XML_ELEMENT_NODE) {
214 					curnode = curnode->next;
215 				} else {
216 					/* Nav the tree evey time as this is LIVE */
217 					basenode = dom_object_get_node(objmap->baseobj);
218 					if (basenode && (basenode->type == XML_DOCUMENT_NODE ||
219 						basenode->type == XML_HTML_DOCUMENT_NODE)) {
220 						basenode = xmlDocGetRootElement((xmlDoc *) basenode);
221 					} else if (basenode) {
222 						basenode = basenode->children;
223 					} else {
224 						goto err;
225 					}
226 					curnode = dom_get_elements_by_tag_name_ns_raw(basenode, objmap->ns, 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 	zval_ptr_dtor((zval**)&curobj);
239 	if (curnode) {
240 		MAKE_STD_ZVAL(curattr);
241 		curattr = php_dom_create_object(curnode, &ret, curattr, objmap->baseobj TSRMLS_CC);
242 	}
243 
244 	iterator->curobj = curattr;
245 }
246 /* }}} */
247 
248 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 };
256 
php_dom_get_iterator(zend_class_entry * ce,zval * object,int by_ref TSRMLS_DC)257 zend_object_iterator *php_dom_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */
258 {
259 	dom_object *intern;
260 	dom_nnodemap_object *objmap;
261 	xmlNodePtr nodep, curnode=NULL;
262 	zval *curattr = NULL;
263 	int ret, curindex = 0;
264 	HashTable *nodeht;
265 	zval **entry;
266 	php_dom_iterator *iterator;
267 
268 	if (by_ref) {
269 		zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
270 	}
271 	iterator = emalloc(sizeof(php_dom_iterator));
272 
273 	Z_ADDREF_P(object);
274 	iterator->intern.data = (void*)object;
275 	iterator->intern.funcs = &php_dom_iterator_funcs;
276 
277 	intern = (dom_object *)zend_object_store_get_object(object TSRMLS_CC);
278 	objmap = (dom_nnodemap_object *)intern->ptr;
279 	if (objmap != NULL) {
280 		if (objmap->nodetype != XML_ENTITY_NODE &&
281 			objmap->nodetype != XML_NOTATION_NODE) {
282 			if (objmap->nodetype == DOM_NODESET) {
283 				nodeht = HASH_OF(objmap->baseobjptr);
284 				zend_hash_internal_pointer_reset(nodeht);
285 				if (zend_hash_get_current_data(nodeht, (void **) &entry)==SUCCESS) {
286 					curattr = *entry;
287 					Z_ADDREF_P(curattr);
288 				}
289 			} else {
290 				nodep = (xmlNode *)dom_object_get_node(objmap->baseobj);
291 				if (!nodep) {
292 					goto err;
293 				}
294 				if (objmap->nodetype == XML_ATTRIBUTE_NODE || objmap->nodetype == XML_ELEMENT_NODE) {
295 					if (objmap->nodetype == XML_ATTRIBUTE_NODE) {
296 						curnode = (xmlNodePtr) nodep->properties;
297 					} else {
298 						curnode = (xmlNodePtr) nodep->children;
299 					}
300 				} else {
301 					if (nodep->type == XML_DOCUMENT_NODE || nodep->type == XML_HTML_DOCUMENT_NODE) {
302 						nodep = xmlDocGetRootElement((xmlDoc *) nodep);
303 					} else {
304 						nodep = nodep->children;
305 					}
306 					curnode = dom_get_elements_by_tag_name_ns_raw(nodep, objmap->ns, objmap->local, &curindex, 0);
307 				}
308 			}
309 		} else {
310 			if (objmap->nodetype == XML_ENTITY_NODE) {
311 				curnode = php_dom_libxml_hash_iter(objmap->ht, 0);
312 			} else {
313 				curnode = php_dom_libxml_notation_iter(objmap->ht, 0);
314 			}
315 		}
316 	}
317 err:
318 	if (curnode) {
319 		MAKE_STD_ZVAL(curattr);
320 		curattr = php_dom_create_object(curnode, &ret, curattr, objmap->baseobj TSRMLS_CC);
321 	}
322 
323 	iterator->curobj = curattr;
324 
325 	return (zend_object_iterator*)iterator;
326 }
327 /* }}} */
328 
329 #endif
330 
331 /*
332  * Local variables:
333  * tab-width: 4
334  * c-basic-offset: 4
335  * End:
336  * vim600: noet sw=4 ts=4 fdm=marker
337  * vim<600: noet sw=4 ts=4
338  */
339