1/*
2   +----------------------------------------------------------------------+
3   | PHP Version 7                                                        |
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
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
186    php_dom_iterator *iterator = (php_dom_iterator *)iter;
187
188    object = &iterator->intern.data;
189    nnmap = Z_DOMOBJ_P(object);
190    objmap = (dom_nnodemap_object *)nnmap->ptr;
191
192    intern = Z_DOMOBJ_P(&iterator->curobj);
193    zval_ptr_dtor(&iterator->curobj);
194    ZVAL_UNDEF(&iterator->curobj);
195
196    if (intern != NULL && intern->ptr != NULL) {
197        if (objmap->nodetype != XML_ENTITY_NODE &&
198            objmap->nodetype != XML_NOTATION_NODE) {
199            if (objmap->nodetype == DOM_NODESET) {
200                nodeht = HASH_OF(&objmap->baseobj_zv);
201                zend_hash_move_forward(nodeht);
202                if ((entry = zend_hash_get_current_data(nodeht))) {
203                    ZVAL_COPY(&iterator->curobj, entry);
204                }
205            } else {
206                curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->ptr)->node;
207                if (objmap->nodetype == XML_ATTRIBUTE_NODE ||
208                    objmap->nodetype == XML_ELEMENT_NODE) {
209                    curnode = curnode->next;
210                } else {
211                    /* Nav the tree evey time as this is LIVE */
212                    basenode = dom_object_get_node(objmap->baseobj);
213                    if (basenode && (basenode->type == XML_DOCUMENT_NODE ||
214                        basenode->type == XML_HTML_DOCUMENT_NODE)) {
215                        basenode = xmlDocGetRootElement((xmlDoc *) basenode);
216                    } else if (basenode) {
217                        basenode = basenode->children;
218                    } else {
219                        goto err;
220                    }
221                    curnode = dom_get_elements_by_tag_name_ns_raw(
222                        basenode, (char *) objmap->ns, (char *) objmap->local, &previndex, iter->index);
223                }
224            }
225        } else {
226            if (objmap->nodetype == XML_ENTITY_NODE) {
227                curnode = php_dom_libxml_hash_iter(objmap->ht, iter->index);
228            } else {
229                curnode = php_dom_libxml_notation_iter(objmap->ht, iter->index);
230            }
231        }
232    }
233err:
234    if (curnode) {
235        php_dom_create_object(curnode, &iterator->curobj, objmap->baseobj);
236    }
237}
238/* }}} */
239
240zend_object_iterator_funcs php_dom_iterator_funcs = {
241    php_dom_iterator_dtor,
242    php_dom_iterator_valid,
243    php_dom_iterator_current_data,
244    php_dom_iterator_current_key,
245    php_dom_iterator_move_forward,
246    NULL
247};
248
249zend_object_iterator *php_dom_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */
250{
251    dom_object *intern;
252    dom_nnodemap_object *objmap;
253    xmlNodePtr nodep, curnode=NULL;
254    int curindex = 0;
255    HashTable *nodeht;
256    zval *entry;
257    php_dom_iterator *iterator;
258
259    if (by_ref) {
260        zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
261    }
262    iterator = emalloc(sizeof(php_dom_iterator));
263    zend_iterator_init(&iterator->intern);
264
265    ZVAL_COPY(&iterator->intern.data, object);
266    iterator->intern.funcs = &php_dom_iterator_funcs;
267
268    ZVAL_UNDEF(&iterator->curobj);
269
270    intern = Z_DOMOBJ_P(object);
271    objmap = (dom_nnodemap_object *)intern->ptr;
272    if (objmap != NULL) {
273        if (objmap->nodetype != XML_ENTITY_NODE &&
274            objmap->nodetype != XML_NOTATION_NODE) {
275            if (objmap->nodetype == DOM_NODESET) {
276                nodeht = HASH_OF(&objmap->baseobj_zv);
277                zend_hash_internal_pointer_reset(nodeht);
278                if ((entry = zend_hash_get_current_data(nodeht))) {
279                    ZVAL_COPY(&iterator->curobj, entry);
280                }
281            } else {
282                nodep = (xmlNode *)dom_object_get_node(objmap->baseobj);
283                if (!nodep) {
284                    goto err;
285                }
286                if (objmap->nodetype == XML_ATTRIBUTE_NODE || objmap->nodetype == XML_ELEMENT_NODE) {
287                    if (objmap->nodetype == XML_ATTRIBUTE_NODE) {
288                        curnode = (xmlNodePtr) nodep->properties;
289                    } else {
290                        curnode = (xmlNodePtr) nodep->children;
291                    }
292                } else {
293                    if (nodep->type == XML_DOCUMENT_NODE || nodep->type == XML_HTML_DOCUMENT_NODE) {
294                        nodep = xmlDocGetRootElement((xmlDoc *) nodep);
295                    } else {
296                        nodep = nodep->children;
297                    }
298                    curnode = dom_get_elements_by_tag_name_ns_raw(
299                        nodep, (char *) objmap->ns, (char *) objmap->local, &curindex, 0);
300                }
301            }
302        } else {
303            if (objmap->nodetype == XML_ENTITY_NODE) {
304                curnode = php_dom_libxml_hash_iter(objmap->ht, 0);
305            } else {
306                curnode = php_dom_libxml_notation_iter(objmap->ht, 0);
307            }
308        }
309    }
310err:
311    if (curnode) {
312        php_dom_create_object(curnode, &iterator->curobj, objmap->baseobj);
313    }
314
315    return &iterator->intern;
316}
317/* }}} */
318
319#endif
320
321/*
322 * Local variables:
323 * tab-width: 4
324 * c-basic-offset: 4
325 * End:
326 * vim600: noet sw=4 ts=4 fdm=marker
327 * vim<600: noet sw=4 ts=4
328 */
329