1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 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: dom_iterators.c 272374 2008-12-31 11:17:49Z sebastian $ */
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 :
31 : typedef struct _nodeIterator nodeIterator;
32 : struct _nodeIterator {
33 : int cur;
34 : int index;
35 : xmlNode *node;
36 : };
37 :
38 : typedef struct _notationIterator notationIterator;
39 : struct _notationIterator {
40 : int cur;
41 : int index;
42 : xmlNotation *notation;
43 : };
44 :
45 24 : static void itemHashScanner (void *payload, void *data, xmlChar *name) {
46 24 : nodeIterator *priv = (nodeIterator *)data;
47 :
48 24 : if(priv->cur < priv->index) {
49 6 : priv->cur++;
50 : } else {
51 18 : if(priv->node == NULL) {
52 12 : priv->node = (xmlNode *)payload;
53 : }
54 : }
55 24 : }
56 :
57 : xmlNodePtr create_notation(const xmlChar *name,
58 5 : const xmlChar *ExternalID, const xmlChar *SystemID) {
59 : xmlEntityPtr ret;
60 :
61 5 : ret = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity));
62 5 : memset(ret, 0, sizeof(xmlEntity));
63 5 : ret->type = XML_NOTATION_NODE;
64 5 : ret->name = xmlStrdup(name);
65 5 : ret->ExternalID = xmlStrdup(ExternalID);
66 5 : ret->SystemID = xmlStrdup(SystemID);
67 5 : ret->length = 0;
68 5 : ret->content = NULL;
69 5 : ret->URI = NULL;
70 5 : ret->orig = NULL;
71 5 : ret->children = NULL;
72 5 : ret->parent = NULL;
73 5 : ret->doc = NULL;
74 5 : ret->_private = NULL;
75 5 : ret->last = NULL;
76 5 : ret->prev = NULL;
77 5 : return((xmlNodePtr) ret);
78 : }
79 :
80 : xmlNode *php_dom_libxml_hash_iter(xmlHashTable *ht, int index)
81 9 : {
82 9 : xmlNode *nodep = NULL;
83 : nodeIterator *iter;
84 : int htsize;
85 :
86 9 : if ((htsize = xmlHashSize(ht)) > 0 && index < htsize) {
87 7 : iter = emalloc(sizeof(nodeIterator));
88 7 : iter->cur = 0;
89 7 : iter->index = index;
90 7 : iter->node = NULL;
91 7 : xmlHashScan(ht, itemHashScanner, iter);
92 7 : nodep = iter->node;
93 7 : efree(iter);
94 7 : return nodep;
95 : } else {
96 2 : return NULL;
97 : }
98 : }
99 :
100 : xmlNode *php_dom_libxml_notation_iter(xmlHashTable *ht, int index)
101 6 : {
102 : notationIterator *iter;
103 6 : xmlNotation *notep = NULL;
104 : int htsize;
105 :
106 6 : if ((htsize = xmlHashSize(ht)) > 0 && index < htsize) {
107 5 : iter = emalloc(sizeof(notationIterator));
108 5 : iter->cur = 0;
109 5 : iter->index = index;
110 5 : iter->notation = NULL;
111 5 : xmlHashScan(ht, itemHashScanner, iter);
112 5 : notep = iter->notation;
113 5 : efree(iter);
114 5 : return create_notation(notep->name, notep->PublicID, notep->SystemID);
115 : } else {
116 1 : return NULL;
117 : }
118 : }
119 :
120 : static void php_dom_iterator_dtor(zend_object_iterator *iter TSRMLS_DC)
121 74 : {
122 74 : php_dom_iterator *iterator = (php_dom_iterator *)iter;
123 :
124 74 : zval_ptr_dtor((zval**)&iterator->intern.data);
125 :
126 74 : if (iterator->curobj) {
127 0 : zval_ptr_dtor((zval**)&iterator->curobj);
128 : }
129 :
130 74 : efree(iterator);
131 74 : }
132 :
133 : static int php_dom_iterator_valid(zend_object_iterator *iter TSRMLS_DC)
134 209 : {
135 :
136 209 : php_dom_iterator *iterator = (php_dom_iterator *)iter;
137 :
138 209 : if (iterator->curobj) {
139 135 : return SUCCESS;
140 : } else {
141 74 : return FAILURE;
142 : }
143 : }
144 :
145 : static void php_dom_iterator_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC)
146 135 : {
147 135 : php_dom_iterator *iterator = (php_dom_iterator *)iter;
148 :
149 135 : *data = &iterator->curobj;
150 135 : }
151 :
152 : static int php_dom_iterator_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC)
153 4 : {
154 : zval *curobj;
155 4 : xmlNodePtr curnode = NULL;
156 : dom_object *intern;
157 : zval *object;
158 : int namelen;
159 :
160 4 : php_dom_iterator *iterator = (php_dom_iterator *)iter;
161 :
162 4 : object = (zval *)iterator->intern.data;
163 :
164 4 : if (instanceof_function(Z_OBJCE_P(object), dom_nodelist_class_entry TSRMLS_CC)) {
165 0 : *int_key = iter->index;
166 0 : return HASH_KEY_IS_LONG;
167 : } else {
168 4 : curobj = iterator->curobj;
169 :
170 4 : intern = (dom_object *)zend_object_store_get_object(curobj TSRMLS_CC);
171 4 : if (intern != NULL && intern->ptr != NULL) {
172 4 : curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->ptr)->node;
173 : } else {
174 0 : return HASH_KEY_NON_EXISTANT;
175 : }
176 :
177 4 : namelen = xmlStrlen(curnode->name);
178 4 : *str_key = estrndup(curnode->name, namelen);
179 4 : *str_key_len = namelen + 1;
180 4 : return HASH_KEY_IS_STRING;
181 : }
182 : }
183 :
184 : static void php_dom_iterator_move_forward(zend_object_iterator *iter TSRMLS_DC)
185 135 : {
186 135 : zval *curobj, *curattr = NULL;
187 : zval *object;
188 135 : xmlNodePtr curnode = NULL, basenode;
189 : dom_object *intern;
190 : dom_object *nnmap;
191 : dom_nnodemap_object *objmap;
192 135 : int ret, previndex=0;
193 : HashTable *nodeht;
194 : zval **entry;
195 :
196 135 : php_dom_iterator *iterator = (php_dom_iterator *)iter;
197 :
198 135 : object = (zval *)iterator->intern.data;
199 135 : nnmap = (dom_object *)zend_object_store_get_object(object TSRMLS_CC);
200 135 : objmap = (dom_nnodemap_object *)nnmap->ptr;
201 :
202 135 : curobj = iterator->curobj;
203 135 : intern = (dom_object *)zend_object_store_get_object(curobj TSRMLS_CC);
204 135 : if (intern != NULL && intern->ptr != NULL) {
205 266 : if (objmap->nodetype != XML_ENTITY_NODE &&
206 : objmap->nodetype != XML_NOTATION_NODE) {
207 131 : if (objmap->nodetype == DOM_NODESET) {
208 0 : nodeht = HASH_OF(objmap->baseobjptr);
209 0 : zend_hash_move_forward(nodeht);
210 0 : if (zend_hash_get_current_data(nodeht, (void **) &entry)==SUCCESS) {
211 0 : curattr = *entry;
212 0 : curattr->refcount++;
213 : }
214 : } else {
215 131 : curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->ptr)->node;
216 246 : if (objmap->nodetype == XML_ATTRIBUTE_NODE ||
217 : objmap->nodetype == XML_ELEMENT_NODE) {
218 115 : curnode = curnode->next;
219 : } else {
220 : /* Nav the tree evey time as this is LIVE */
221 16 : basenode = dom_object_get_node(objmap->baseobj);
222 25 : if (basenode && (basenode->type == XML_DOCUMENT_NODE ||
223 : basenode->type == XML_HTML_DOCUMENT_NODE)) {
224 9 : basenode = xmlDocGetRootElement((xmlDoc *) basenode);
225 7 : } else if (basenode) {
226 7 : basenode = basenode->children;
227 : } else {
228 0 : goto err;
229 : }
230 16 : curnode = dom_get_elements_by_tag_name_ns_raw(basenode, objmap->ns, objmap->local, &previndex, iter->index);
231 : }
232 : }
233 : } else {
234 4 : if (objmap->nodetype == XML_ENTITY_NODE) {
235 3 : curnode = php_dom_libxml_hash_iter(objmap->ht, iter->index);
236 : } else {
237 1 : curnode = php_dom_libxml_notation_iter(objmap->ht, iter->index);
238 : }
239 : }
240 : }
241 135 : err:
242 135 : zval_ptr_dtor((zval**)&curobj);
243 135 : if (curnode) {
244 73 : MAKE_STD_ZVAL(curattr);
245 73 : curattr = php_dom_create_object(curnode, &ret, NULL, curattr, objmap->baseobj TSRMLS_CC);
246 : }
247 :
248 135 : iterator->curobj = curattr;
249 135 : }
250 :
251 : zend_object_iterator_funcs php_dom_iterator_funcs = {
252 : php_dom_iterator_dtor,
253 : php_dom_iterator_valid,
254 : php_dom_iterator_current_data,
255 : php_dom_iterator_current_key,
256 : php_dom_iterator_move_forward,
257 : NULL
258 : };
259 :
260 : zend_object_iterator *php_dom_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC)
261 74 : {
262 : dom_object *intern;
263 : dom_nnodemap_object *objmap;
264 74 : xmlNodePtr nodep, curnode=NULL;
265 74 : zval *curattr = NULL;
266 74 : int ret, curindex = 0;
267 : HashTable *nodeht;
268 : zval **entry;
269 : php_dom_iterator *iterator;
270 :
271 74 : if (by_ref) {
272 0 : zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
273 : }
274 74 : iterator = emalloc(sizeof(php_dom_iterator));
275 :
276 74 : object->refcount++;
277 74 : iterator->intern.data = (void*)object;
278 74 : iterator->intern.funcs = &php_dom_iterator_funcs;
279 :
280 74 : intern = (dom_object *)zend_object_store_get_object(object TSRMLS_CC);
281 74 : objmap = (dom_nnodemap_object *)intern->ptr;
282 74 : if (objmap != NULL) {
283 146 : if (objmap->nodetype != XML_ENTITY_NODE &&
284 : objmap->nodetype != XML_NOTATION_NODE) {
285 72 : if (objmap->nodetype == DOM_NODESET) {
286 0 : nodeht = HASH_OF(objmap->baseobjptr);
287 0 : zend_hash_internal_pointer_reset(nodeht);
288 0 : if (zend_hash_get_current_data(nodeht, (void **) &entry)==SUCCESS) {
289 0 : curattr = *entry;
290 0 : curattr->refcount++;
291 : }
292 : } else {
293 72 : nodep = (xmlNode *)dom_object_get_node(objmap->baseobj);
294 72 : if (!nodep) {
295 0 : goto err;
296 : }
297 137 : if (objmap->nodetype == XML_ATTRIBUTE_NODE || objmap->nodetype == XML_ELEMENT_NODE) {
298 65 : if (objmap->nodetype == XML_ATTRIBUTE_NODE) {
299 2 : curnode = (xmlNodePtr) nodep->properties;
300 : } else {
301 63 : curnode = (xmlNodePtr) nodep->children;
302 : }
303 : } else {
304 11 : if (nodep->type == XML_DOCUMENT_NODE || nodep->type == XML_HTML_DOCUMENT_NODE) {
305 4 : nodep = xmlDocGetRootElement((xmlDoc *) nodep);
306 : } else {
307 3 : nodep = nodep->children;
308 : }
309 7 : curnode = dom_get_elements_by_tag_name_ns_raw(nodep, objmap->ns, objmap->local, &curindex, 0);
310 : }
311 : }
312 : } else {
313 2 : if (objmap->nodetype == XML_ENTITY_NODE) {
314 1 : curnode = php_dom_libxml_hash_iter(objmap->ht, 0);
315 : } else {
316 1 : curnode = php_dom_libxml_notation_iter(objmap->ht, 0);
317 : }
318 : }
319 : }
320 74 : err:
321 74 : if (curnode) {
322 62 : MAKE_STD_ZVAL(curattr);
323 62 : curattr = php_dom_create_object(curnode, &ret, NULL, curattr, objmap->baseobj TSRMLS_CC);
324 : }
325 :
326 74 : iterator->curobj = curattr;
327 :
328 74 : return (zend_object_iterator*)iterator;
329 : }
330 :
331 : #endif
|