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