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 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
193static 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    }
250err:
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
261zend_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
270zend_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    }
330err:
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