xref: /PHP-5.4/ext/dom/dom_iterators.c (revision c0d060f5)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 5                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2014 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,char ** str_key,uint * str_key_len,ulong * int_key TSRMLS_DC)160 static int php_dom_iterator_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */
161 {
162 	zval *curobj;
163 	xmlNodePtr curnode = NULL;
164 	dom_object *intern;
165 	zval *object;
166 	int namelen;
167 
168 	php_dom_iterator *iterator = (php_dom_iterator *)iter;
169 
170 	object = (zval *)iterator->intern.data;
171 
172 	if (instanceof_function(Z_OBJCE_P(object), dom_nodelist_class_entry TSRMLS_CC)) {
173 		*int_key = iter->index;
174 		return HASH_KEY_IS_LONG;
175 	} else {
176 		curobj = iterator->curobj;
177 
178 		intern = (dom_object *)zend_object_store_get_object(curobj TSRMLS_CC);
179 		if (intern != NULL && intern->ptr != NULL) {
180 			curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->ptr)->node;
181 		} else {
182 			return HASH_KEY_NON_EXISTANT;
183 		}
184 
185 		namelen = xmlStrlen(curnode->name);
186 		*str_key = estrndup(curnode->name, namelen);
187 		*str_key_len = namelen + 1;
188 		return HASH_KEY_IS_STRING;
189 	}
190 }
191 /* }}} */
192 
php_dom_iterator_move_forward(zend_object_iterator * iter TSRMLS_DC)193 static void php_dom_iterator_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
194 {
195 	zval *curobj, *curattr = NULL;
196 	zval *object;
197 	xmlNodePtr curnode = NULL, basenode;
198 	dom_object *intern;
199 	dom_object *nnmap;
200 	dom_nnodemap_object *objmap;
201 	int ret, previndex=0;
202 	HashTable *nodeht;
203 	zval **entry;
204 
205 	php_dom_iterator *iterator = (php_dom_iterator *)iter;
206 
207 	object = (zval *)iterator->intern.data;
208 	nnmap = (dom_object *)zend_object_store_get_object(object TSRMLS_CC);
209 	objmap = (dom_nnodemap_object *)nnmap->ptr;
210 
211 	curobj = iterator->curobj;
212 	intern = (dom_object *)zend_object_store_get_object(curobj TSRMLS_CC);
213 	if (intern != NULL && intern->ptr != NULL) {
214 		if (objmap->nodetype != XML_ENTITY_NODE &&
215 			objmap->nodetype != XML_NOTATION_NODE) {
216 			if (objmap->nodetype == DOM_NODESET) {
217 				nodeht = HASH_OF(objmap->baseobjptr);
218 				zend_hash_move_forward(nodeht);
219 				if (zend_hash_get_current_data(nodeht, (void **) &entry)==SUCCESS) {
220 					curattr = *entry;
221 					Z_ADDREF_P(curattr);
222 				}
223 			} else {
224 				curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->ptr)->node;
225 				if (objmap->nodetype == XML_ATTRIBUTE_NODE ||
226 					objmap->nodetype == XML_ELEMENT_NODE) {
227 					curnode = curnode->next;
228 				} else {
229 					/* Nav the tree evey time as this is LIVE */
230 					basenode = dom_object_get_node(objmap->baseobj);
231 					if (basenode && (basenode->type == XML_DOCUMENT_NODE ||
232 						basenode->type == XML_HTML_DOCUMENT_NODE)) {
233 						basenode = xmlDocGetRootElement((xmlDoc *) basenode);
234 					} else if (basenode) {
235 						basenode = basenode->children;
236 					} else {
237 						goto err;
238 					}
239 					curnode = dom_get_elements_by_tag_name_ns_raw(basenode, objmap->ns, objmap->local, &previndex, iter->index);
240 				}
241 			}
242 		} else {
243 			if (objmap->nodetype == XML_ENTITY_NODE) {
244 				curnode = php_dom_libxml_hash_iter(objmap->ht, iter->index);
245 			} else {
246 				curnode = php_dom_libxml_notation_iter(objmap->ht, iter->index);
247 			}
248 		}
249 	}
250 err:
251 	zval_ptr_dtor((zval**)&curobj);
252 	if (curnode) {
253 		MAKE_STD_ZVAL(curattr);
254 		curattr = php_dom_create_object(curnode, &ret, curattr, objmap->baseobj TSRMLS_CC);
255 	}
256 
257 	iterator->curobj = curattr;
258 }
259 /* }}} */
260 
261 zend_object_iterator_funcs php_dom_iterator_funcs = {
262 	php_dom_iterator_dtor,
263 	php_dom_iterator_valid,
264 	php_dom_iterator_current_data,
265 	php_dom_iterator_current_key,
266 	php_dom_iterator_move_forward,
267 	NULL
268 };
269 
php_dom_get_iterator(zend_class_entry * ce,zval * object,int by_ref TSRMLS_DC)270 zend_object_iterator *php_dom_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */
271 {
272 	dom_object *intern;
273 	dom_nnodemap_object *objmap;
274 	xmlNodePtr nodep, curnode=NULL;
275 	zval *curattr = NULL;
276 	int ret, curindex = 0;
277 	HashTable *nodeht;
278 	zval **entry;
279 	php_dom_iterator *iterator;
280 
281 	if (by_ref) {
282 		zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
283 	}
284 	iterator = emalloc(sizeof(php_dom_iterator));
285 
286 	Z_ADDREF_P(object);
287 	iterator->intern.data = (void*)object;
288 	iterator->intern.funcs = &php_dom_iterator_funcs;
289 
290 	intern = (dom_object *)zend_object_store_get_object(object TSRMLS_CC);
291 	objmap = (dom_nnodemap_object *)intern->ptr;
292 	if (objmap != NULL) {
293 		if (objmap->nodetype != XML_ENTITY_NODE &&
294 			objmap->nodetype != XML_NOTATION_NODE) {
295 			if (objmap->nodetype == DOM_NODESET) {
296 				nodeht = HASH_OF(objmap->baseobjptr);
297 				zend_hash_internal_pointer_reset(nodeht);
298 				if (zend_hash_get_current_data(nodeht, (void **) &entry)==SUCCESS) {
299 					curattr = *entry;
300 					Z_ADDREF_P(curattr);
301 				}
302 			} else {
303 				nodep = (xmlNode *)dom_object_get_node(objmap->baseobj);
304 				if (!nodep) {
305 					goto err;
306 				}
307 				if (objmap->nodetype == XML_ATTRIBUTE_NODE || objmap->nodetype == XML_ELEMENT_NODE) {
308 					if (objmap->nodetype == XML_ATTRIBUTE_NODE) {
309 						curnode = (xmlNodePtr) nodep->properties;
310 					} else {
311 						curnode = (xmlNodePtr) nodep->children;
312 					}
313 				} else {
314 					if (nodep->type == XML_DOCUMENT_NODE || nodep->type == XML_HTML_DOCUMENT_NODE) {
315 						nodep = xmlDocGetRootElement((xmlDoc *) nodep);
316 					} else {
317 						nodep = nodep->children;
318 					}
319 					curnode = dom_get_elements_by_tag_name_ns_raw(nodep, objmap->ns, objmap->local, &curindex, 0);
320 				}
321 			}
322 		} else {
323 			if (objmap->nodetype == XML_ENTITY_NODE) {
324 				curnode = php_dom_libxml_hash_iter(objmap->ht, 0);
325 			} else {
326 				curnode = php_dom_libxml_notation_iter(objmap->ht, 0);
327 			}
328 		}
329 	}
330 err:
331 	if (curnode) {
332 		MAKE_STD_ZVAL(curattr);
333 		curattr = php_dom_create_object(curnode, &ret, curattr, objmap->baseobj TSRMLS_CC);
334 	}
335 
336 	iterator->curobj = curattr;
337 
338 	return (zend_object_iterator*)iterator;
339 }
340 /* }}} */
341 
342 #endif
343 
344 /*
345  * Local variables:
346  * tab-width: 4
347  * c-basic-offset: 4
348  * End:
349  * vim600: noet sw=4 ts=4 fdm=marker
350  * vim<600: noet sw=4 ts=4
351  */
352