1 /*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | http://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Authors: Christian Stocker <chregu@php.net> |
14 | Rob Richards <rrichards@php.net> |
15 +----------------------------------------------------------------------+
16 */
17
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21
22 #include "php.h"
23 #if defined(HAVE_LIBXML) && defined(HAVE_DOM)
24 #include "php_dom.h"
25 #include "dom_ce.h"
26
27 typedef struct _nodeIterator nodeIterator;
28 struct _nodeIterator {
29 int cur;
30 int index;
31 xmlNode *node;
32 };
33
34 typedef struct _notationIterator notationIterator;
35 struct _notationIterator {
36 int cur;
37 int index;
38 xmlNotation *notation;
39 };
40
41 #if LIBXML_VERSION >= 20908
itemHashScanner(void * payload,void * data,const xmlChar * name)42 static void itemHashScanner (void *payload, void *data, const xmlChar *name) /* {{{ */
43 #else
44 static void itemHashScanner (void *payload, void *data, xmlChar *name)
45 #endif
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
create_notation(const xmlChar * name,const xmlChar * ExternalID,const xmlChar * SystemID)59 xmlNodePtr 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
php_dom_libxml_hash_iter(xmlHashTable * ht,int index)83 xmlNode *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
php_dom_libxml_notation_iter(xmlHashTable * ht,int index)104 xmlNode *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
php_dom_iterator_dtor(zend_object_iterator * iter)125 static 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
php_dom_iterator_valid(zend_object_iterator * iter)134 static 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
php_dom_iterator_current_data(zend_object_iterator * iter)147 zval *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
php_dom_iterator_current_key(zend_object_iterator * iter,zval * key)155 static 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
php_dom_iterator_move_forward(zend_object_iterator * iter)175 static 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 zend_bool do_curobj_undef = 1;
186
187 php_dom_iterator *iterator = (php_dom_iterator *)iter;
188
189 object = &iterator->intern.data;
190 nnmap = Z_DOMOBJ_P(object);
191 objmap = (dom_nnodemap_object *)nnmap->ptr;
192
193 intern = Z_DOMOBJ_P(&iterator->curobj);
194
195 if (intern != NULL && intern->ptr != NULL) {
196 if (objmap->nodetype != XML_ENTITY_NODE &&
197 objmap->nodetype != XML_NOTATION_NODE) {
198 if (objmap->nodetype == DOM_NODESET) {
199 nodeht = HASH_OF(&objmap->baseobj_zv);
200 zend_hash_move_forward_ex(nodeht, &iterator->pos);
201 if ((entry = zend_hash_get_current_data_ex(nodeht, &iterator->pos))) {
202 zval_ptr_dtor(&iterator->curobj);
203 ZVAL_UNDEF(&iterator->curobj);
204 ZVAL_COPY(&iterator->curobj, entry);
205 do_curobj_undef = 0;
206 }
207 } else {
208 curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->ptr)->node;
209 if (objmap->nodetype == XML_ATTRIBUTE_NODE ||
210 objmap->nodetype == XML_ELEMENT_NODE) {
211 curnode = curnode->next;
212 } else {
213 /* Nav the tree evey time as this is LIVE */
214 basenode = dom_object_get_node(objmap->baseobj);
215 if (basenode && (basenode->type == XML_DOCUMENT_NODE ||
216 basenode->type == XML_HTML_DOCUMENT_NODE)) {
217 basenode = xmlDocGetRootElement((xmlDoc *) basenode);
218 } else if (basenode) {
219 basenode = basenode->children;
220 } else {
221 goto err;
222 }
223 curnode = dom_get_elements_by_tag_name_ns_raw(
224 basenode, (char *) objmap->ns, (char *) objmap->local, &previndex, iter->index);
225 }
226 }
227 } else {
228 if (objmap->nodetype == XML_ENTITY_NODE) {
229 curnode = php_dom_libxml_hash_iter(objmap->ht, iter->index);
230 } else {
231 curnode = php_dom_libxml_notation_iter(objmap->ht, iter->index);
232 }
233 }
234 }
235 err:
236 if (do_curobj_undef) {
237 zval_ptr_dtor(&iterator->curobj);
238 ZVAL_UNDEF(&iterator->curobj);
239 }
240 if (curnode) {
241 php_dom_create_object(curnode, &iterator->curobj, objmap->baseobj);
242 }
243 }
244 /* }}} */
245
246 static const zend_object_iterator_funcs php_dom_iterator_funcs = {
247 php_dom_iterator_dtor,
248 php_dom_iterator_valid,
249 php_dom_iterator_current_data,
250 php_dom_iterator_current_key,
251 php_dom_iterator_move_forward,
252 NULL,
253 NULL,
254 NULL, /* get_gc */
255 };
256
php_dom_get_iterator(zend_class_entry * ce,zval * object,int by_ref)257 zend_object_iterator *php_dom_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */
258 {
259 dom_object *intern;
260 dom_nnodemap_object *objmap;
261 xmlNodePtr nodep, curnode=NULL;
262 int curindex = 0;
263 HashTable *nodeht;
264 zval *entry;
265 php_dom_iterator *iterator;
266
267 if (by_ref) {
268 zend_throw_error(NULL, "An iterator cannot be used with foreach by reference");
269 return NULL;
270 }
271 iterator = emalloc(sizeof(php_dom_iterator));
272 zend_iterator_init(&iterator->intern);
273
274 ZVAL_OBJ_COPY(&iterator->intern.data, Z_OBJ_P(object));
275 iterator->intern.funcs = &php_dom_iterator_funcs;
276
277 ZVAL_UNDEF(&iterator->curobj);
278
279 intern = Z_DOMOBJ_P(object);
280 objmap = (dom_nnodemap_object *)intern->ptr;
281 if (objmap != NULL) {
282 if (objmap->nodetype != XML_ENTITY_NODE &&
283 objmap->nodetype != XML_NOTATION_NODE) {
284 if (objmap->nodetype == DOM_NODESET) {
285 nodeht = HASH_OF(&objmap->baseobj_zv);
286 zend_hash_internal_pointer_reset_ex(nodeht, &iterator->pos);
287 if ((entry = zend_hash_get_current_data_ex(nodeht, &iterator->pos))) {
288 ZVAL_COPY(&iterator->curobj, entry);
289 }
290 } else {
291 nodep = (xmlNode *)dom_object_get_node(objmap->baseobj);
292 if (!nodep) {
293 goto err;
294 }
295 if (objmap->nodetype == XML_ATTRIBUTE_NODE || objmap->nodetype == XML_ELEMENT_NODE) {
296 if (objmap->nodetype == XML_ATTRIBUTE_NODE) {
297 curnode = (xmlNodePtr) nodep->properties;
298 } else {
299 curnode = (xmlNodePtr) nodep->children;
300 }
301 } else {
302 if (nodep->type == XML_DOCUMENT_NODE || nodep->type == XML_HTML_DOCUMENT_NODE) {
303 nodep = xmlDocGetRootElement((xmlDoc *) nodep);
304 } else {
305 nodep = nodep->children;
306 }
307 curnode = dom_get_elements_by_tag_name_ns_raw(
308 nodep, (char *) objmap->ns, (char *) objmap->local, &curindex, 0);
309 }
310 }
311 } else {
312 if (objmap->nodetype == XML_ENTITY_NODE) {
313 curnode = php_dom_libxml_hash_iter(objmap->ht, 0);
314 } else {
315 curnode = php_dom_libxml_notation_iter(objmap->ht, 0);
316 }
317 }
318 }
319 err:
320 if (curnode) {
321 php_dom_create_object(curnode, &iterator->curobj, objmap->baseobj);
322 }
323
324 return &iterator->intern;
325 }
326 /* }}} */
327
328 #endif
329