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