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
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 TSRMLS_DC) /* {{{ */
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 TSRMLS_DC) /* {{{ */
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 TSRMLS_DC) /* {{{ */
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 TSRMLS_DC) /* {{{ */
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 TSRMLS_CC)) {
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 TSRMLS_DC) /* {{{ */
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(basenode, objmap->ns, objmap->local, &previndex, iter->index);
222                }
223            }
224        } else {
225            if (objmap->nodetype == XML_ENTITY_NODE) {
226                curnode = php_dom_libxml_hash_iter(objmap->ht, iter->index);
227            } else {
228                curnode = php_dom_libxml_notation_iter(objmap->ht, iter->index);
229            }
230        }
231    }
232err:
233    if (curnode) {
234        php_dom_create_object(curnode, &iterator->curobj, objmap->baseobj TSRMLS_CC);
235    }
236}
237/* }}} */
238
239zend_object_iterator_funcs php_dom_iterator_funcs = {
240    php_dom_iterator_dtor,
241    php_dom_iterator_valid,
242    php_dom_iterator_current_data,
243    php_dom_iterator_current_key,
244    php_dom_iterator_move_forward,
245    NULL
246};
247
248zend_object_iterator *php_dom_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */
249{
250    dom_object *intern;
251    dom_nnodemap_object *objmap;
252    xmlNodePtr nodep, curnode=NULL;
253    int curindex = 0;
254    HashTable *nodeht;
255    zval *entry;
256    php_dom_iterator *iterator;
257
258    if (by_ref) {
259        zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
260    }
261    iterator = emalloc(sizeof(php_dom_iterator));
262    zend_iterator_init(&iterator->intern TSRMLS_CC);
263
264    ZVAL_COPY(&iterator->intern.data, object);
265    iterator->intern.funcs = &php_dom_iterator_funcs;
266
267    ZVAL_UNDEF(&iterator->curobj);
268
269    intern = Z_DOMOBJ_P(object);
270    objmap = (dom_nnodemap_object *)intern->ptr;
271    if (objmap != NULL) {
272        if (objmap->nodetype != XML_ENTITY_NODE &&
273            objmap->nodetype != XML_NOTATION_NODE) {
274            if (objmap->nodetype == DOM_NODESET) {
275                nodeht = HASH_OF(&objmap->baseobj_zv);
276                zend_hash_internal_pointer_reset(nodeht);
277                if ((entry = zend_hash_get_current_data(nodeht))) {
278                    ZVAL_COPY(&iterator->curobj, entry);
279                }
280            } else {
281                nodep = (xmlNode *)dom_object_get_node(objmap->baseobj);
282                if (!nodep) {
283                    goto err;
284                }
285                if (objmap->nodetype == XML_ATTRIBUTE_NODE || objmap->nodetype == XML_ELEMENT_NODE) {
286                    if (objmap->nodetype == XML_ATTRIBUTE_NODE) {
287                        curnode = (xmlNodePtr) nodep->properties;
288                    } else {
289                        curnode = (xmlNodePtr) nodep->children;
290                    }
291                } else {
292                    if (nodep->type == XML_DOCUMENT_NODE || nodep->type == XML_HTML_DOCUMENT_NODE) {
293                        nodep = xmlDocGetRootElement((xmlDoc *) nodep);
294                    } else {
295                        nodep = nodep->children;
296                    }
297                    curnode = dom_get_elements_by_tag_name_ns_raw(nodep, objmap->ns, objmap->local, &curindex, 0);
298                }
299            }
300        } else {
301            if (objmap->nodetype == XML_ENTITY_NODE) {
302                curnode = php_dom_libxml_hash_iter(objmap->ht, 0);
303            } else {
304                curnode = php_dom_libxml_notation_iter(objmap->ht, 0);
305            }
306        }
307    }
308err:
309    if (curnode) {
310        php_dom_create_object(curnode, &iterator->curobj, objmap->baseobj TSRMLS_CC);
311    }
312
313    return &iterator->intern;
314}
315/* }}} */
316
317#endif
318
319/*
320 * Local variables:
321 * tab-width: 4
322 * c-basic-offset: 4
323 * End:
324 * vim600: noet sw=4 ts=4 fdm=marker
325 * vim<600: noet sw=4 ts=4
326 */
327