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((zval**)&iterator->intern.data);
130
131    if (iterator->curobj) {
132        zval_ptr_dtor((zval**)&iterator->curobj);
133    }
134
135    efree(iterator);
136}
137/* }}} */
138
139static 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
152static 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
160static 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
180static 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    }
237err:
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
248zend_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
257zend_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    }
317err:
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