1/*
2   +----------------------------------------------------------------------+
3   | PHP Version 7                                                        |
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
31typedef struct _nodeIterator nodeIterator;
32struct _nodeIterator {
33	int cur;
34	int index;
35	xmlNode *node;
36};
37
38typedef struct _notationIterator notationIterator;
39struct _notationIterator {
40	int cur;
41	int index;
42	xmlNotation *notation;
43};
44
45static 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
59xmlNodePtr 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
83xmlNode *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
104xmlNode *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
125static void php_dom_iterator_dtor(zend_object_iterator *iter) /* {{{ */
126{
127	php_dom_iterator *iterator = (php_dom_iterator *)iter;
128
129	zval_ptr_dtor(&iterator->intern.data);
130	zval_ptr_dtor(&iterator->curobj);
131}
132/* }}} */
133
134static int php_dom_iterator_valid(zend_object_iterator *iter) /* {{{ */
135{
136
137	php_dom_iterator *iterator = (php_dom_iterator *)iter;
138
139	if (Z_TYPE(iterator->curobj) != IS_UNDEF) {
140		return SUCCESS;
141	} else {
142		return FAILURE;
143	}
144}
145/* }}} */
146
147zval *php_dom_iterator_current_data(zend_object_iterator *iter) /* {{{ */
148{
149	php_dom_iterator *iterator = (php_dom_iterator *)iter;
150
151	return &iterator->curobj;
152}
153/* }}} */
154
155static void php_dom_iterator_current_key(zend_object_iterator *iter, zval *key) /* {{{ */
156{
157	php_dom_iterator *iterator = (php_dom_iterator *)iter;
158	zval *object = &iterator->intern.data;
159
160	if (instanceof_function(Z_OBJCE_P(object), dom_nodelist_class_entry)) {
161		ZVAL_LONG(key, iter->index);
162	} else {
163		dom_object *intern = Z_DOMOBJ_P(&iterator->curobj);
164
165		if (intern != NULL && intern->ptr != NULL) {
166			xmlNodePtr curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->ptr)->node;
167			ZVAL_STRINGL(key, (char *) curnode->name, xmlStrlen(curnode->name));
168		} else {
169			ZVAL_NULL(key);
170		}
171	}
172}
173/* }}} */
174
175static void php_dom_iterator_move_forward(zend_object_iterator *iter) /* {{{ */
176{
177	zval *object;
178	xmlNodePtr curnode = NULL, basenode;
179	dom_object *intern;
180	dom_object *nnmap;
181	dom_nnodemap_object *objmap;
182	int previndex=0;
183	HashTable *nodeht;
184	zval *entry;
185	zend_bool do_curobj_undef = 1;
186
187	php_dom_iterator *iterator = (php_dom_iterator *)iter;
188
189	object = &iterator->intern.data;
190	nnmap = Z_DOMOBJ_P(object);
191	objmap = (dom_nnodemap_object *)nnmap->ptr;
192
193	intern = Z_DOMOBJ_P(&iterator->curobj);
194
195	if (intern != NULL && intern->ptr != NULL) {
196		if (objmap->nodetype != XML_ENTITY_NODE &&
197			objmap->nodetype != XML_NOTATION_NODE) {
198			if (objmap->nodetype == DOM_NODESET) {
199				nodeht = HASH_OF(&objmap->baseobj_zv);
200				zend_hash_move_forward(nodeht);
201				if ((entry = zend_hash_get_current_data(nodeht))) {
202					zval_ptr_dtor(&iterator->curobj);
203					ZVAL_UNDEF(&iterator->curobj);
204					ZVAL_COPY(&iterator->curobj, entry);
205					do_curobj_undef = 0;
206				}
207			} else {
208				curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->ptr)->node;
209				if (objmap->nodetype == XML_ATTRIBUTE_NODE ||
210					objmap->nodetype == XML_ELEMENT_NODE) {
211					curnode = curnode->next;
212				} else {
213					/* Nav the tree evey time as this is LIVE */
214					basenode = dom_object_get_node(objmap->baseobj);
215					if (basenode && (basenode->type == XML_DOCUMENT_NODE ||
216						basenode->type == XML_HTML_DOCUMENT_NODE)) {
217						basenode = xmlDocGetRootElement((xmlDoc *) basenode);
218					} else if (basenode) {
219						basenode = basenode->children;
220					} else {
221						goto err;
222					}
223					curnode = dom_get_elements_by_tag_name_ns_raw(
224						basenode, (char *) objmap->ns, (char *) objmap->local, &previndex, iter->index);
225				}
226			}
227		} else {
228			if (objmap->nodetype == XML_ENTITY_NODE) {
229				curnode = php_dom_libxml_hash_iter(objmap->ht, iter->index);
230			} else {
231				curnode = php_dom_libxml_notation_iter(objmap->ht, iter->index);
232			}
233		}
234	}
235err:
236	if (do_curobj_undef) {
237		zval_ptr_dtor(&iterator->curobj);
238		ZVAL_UNDEF(&iterator->curobj);
239	}
240	if (curnode) {
241		php_dom_create_object(curnode, &iterator->curobj, objmap->baseobj);
242	}
243}
244/* }}} */
245
246zend_object_iterator_funcs php_dom_iterator_funcs = {
247	php_dom_iterator_dtor,
248	php_dom_iterator_valid,
249	php_dom_iterator_current_data,
250	php_dom_iterator_current_key,
251	php_dom_iterator_move_forward,
252	NULL
253};
254
255zend_object_iterator *php_dom_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */
256{
257	dom_object *intern;
258	dom_nnodemap_object *objmap;
259	xmlNodePtr nodep, curnode=NULL;
260	int curindex = 0;
261	HashTable *nodeht;
262	zval *entry;
263	php_dom_iterator *iterator;
264
265	if (by_ref) {
266		zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
267	}
268	iterator = emalloc(sizeof(php_dom_iterator));
269	zend_iterator_init(&iterator->intern);
270
271	ZVAL_COPY(&iterator->intern.data, object);
272	iterator->intern.funcs = &php_dom_iterator_funcs;
273
274	ZVAL_UNDEF(&iterator->curobj);
275
276	intern = Z_DOMOBJ_P(object);
277	objmap = (dom_nnodemap_object *)intern->ptr;
278	if (objmap != NULL) {
279		if (objmap->nodetype != XML_ENTITY_NODE &&
280			objmap->nodetype != XML_NOTATION_NODE) {
281			if (objmap->nodetype == DOM_NODESET) {
282				nodeht = HASH_OF(&objmap->baseobj_zv);
283				zend_hash_internal_pointer_reset(nodeht);
284				if ((entry = zend_hash_get_current_data(nodeht))) {
285					ZVAL_COPY(&iterator->curobj, entry);
286				}
287			} else {
288				nodep = (xmlNode *)dom_object_get_node(objmap->baseobj);
289				if (!nodep) {
290					goto err;
291				}
292				if (objmap->nodetype == XML_ATTRIBUTE_NODE || objmap->nodetype == XML_ELEMENT_NODE) {
293					if (objmap->nodetype == XML_ATTRIBUTE_NODE) {
294						curnode = (xmlNodePtr) nodep->properties;
295					} else {
296						curnode = (xmlNodePtr) nodep->children;
297					}
298				} else {
299					if (nodep->type == XML_DOCUMENT_NODE || nodep->type == XML_HTML_DOCUMENT_NODE) {
300						nodep = xmlDocGetRootElement((xmlDoc *) nodep);
301					} else {
302						nodep = nodep->children;
303					}
304					curnode = dom_get_elements_by_tag_name_ns_raw(
305						nodep, (char *) objmap->ns, (char *) objmap->local, &curindex, 0);
306				}
307			}
308		} else {
309			if (objmap->nodetype == XML_ENTITY_NODE) {
310				curnode = php_dom_libxml_hash_iter(objmap->ht, 0);
311			} else {
312				curnode = php_dom_libxml_notation_iter(objmap->ht, 0);
313			}
314		}
315	}
316err:
317	if (curnode) {
318		php_dom_create_object(curnode, &iterator->curobj, objmap->baseobj);
319	}
320
321	return &iterator->intern;
322}
323/* }}} */
324
325#endif
326
327/*
328 * Local variables:
329 * tab-width: 4
330 * c-basic-offset: 4
331 * End:
332 * vim600: noet sw=4 ts=4 fdm=marker
333 * vim<600: noet sw=4 ts=4
334 */
335