php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
dom_iterators.c
Go to the documentation of this file.
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 | https://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
27typedef struct nodeIterator {
28 int cur;
29 int index;
30 xmlNode *node;
31} nodeIterator;
32
33/* Function pointer typedef changed in 2.9.8, see https://github.com/GNOME/libxml2/commit/e03f0a199a67017b2f8052354cf732b2b4cae787 */
34#if LIBXML_VERSION >= 20908
35static void itemHashScanner (void *payload, void *data, const xmlChar *name) /* {{{ */
36#else
37static void itemHashScanner (void *payload, void *data, xmlChar *name)
38#endif
39{
40 nodeIterator *priv = data;
41
42 if (priv->cur < priv->index) {
43 priv->cur++;
44 } else {
45 if (priv->node == NULL) {
46 priv->node = payload;
47 }
48 }
49}
50/* }}} */
51
52static dom_nnodemap_object *php_dom_iterator_get_nnmap(const php_dom_iterator *iterator)
53{
54 const zval *object = &iterator->intern.data;
55 dom_object *nnmap = Z_DOMOBJ_P(object);
56 return nnmap->ptr;
57}
58
59xmlNodePtr create_notation(const xmlChar *name, const xmlChar *ExternalID, const xmlChar *SystemID) /* {{{ */
60{
61 xmlEntityPtr ret = xmlMalloc(sizeof(xmlEntity));
62 memset(ret, 0, sizeof(xmlEntity));
63 ret->type = XML_NOTATION_NODE;
64 ret->name = xmlStrdup(name);
65 ret->ExternalID = xmlStrdup(ExternalID);
66 ret->SystemID = xmlStrdup(SystemID);
67 return (xmlNodePtr) ret;
68}
69/* }}} */
70
71static xmlNode *php_dom_libxml_hash_iter_ex(xmlHashTable *ht, int index)
72{
73 int htsize;
74
75 if ((htsize = xmlHashSize(ht)) > 0 && index < htsize) {
76 nodeIterator iter;
77 iter.cur = 0;
78 iter.index = index;
79 iter.node = NULL;
80 xmlHashScan(ht, itemHashScanner, &iter);
81 return iter.node;
82 } else {
83 return NULL;
84 }
85}
86
87xmlNode *php_dom_libxml_hash_iter(dom_nnodemap_object *objmap, int index)
88{
89 xmlNode *curnode = php_dom_libxml_hash_iter_ex(objmap->ht, index);
90
91 if (curnode != NULL && objmap->nodetype != XML_ENTITY_NODE) {
92 xmlNotation *notation = (xmlNotation *) curnode;
93 curnode = create_notation(notation->name, notation->PublicID, notation->SystemID);
94 }
95
96 return curnode;
97}
98
99static void php_dom_iterator_dtor(zend_object_iterator *iter) /* {{{ */
100{
101 php_dom_iterator *iterator = (php_dom_iterator *)iter;
102
103 zval_ptr_dtor(&iterator->intern.data);
104 zval_ptr_dtor(&iterator->curobj);
105}
106/* }}} */
107
108static zend_result php_dom_iterator_valid(zend_object_iterator *iter) /* {{{ */
109{
110 php_dom_iterator *iterator = (php_dom_iterator *)iter;
111
112 if (Z_TYPE(iterator->curobj) != IS_UNDEF) {
113 return SUCCESS;
114 } else {
115 return FAILURE;
116 }
117}
118/* }}} */
119
120zval *php_dom_iterator_current_data(zend_object_iterator *iter) /* {{{ */
121{
122 php_dom_iterator *iterator = (php_dom_iterator *)iter;
123 return Z_ISUNDEF(iterator->curobj) ? NULL : &iterator->curobj;
124}
125/* }}} */
126
127static void php_dom_iterator_current_key(zend_object_iterator *iter, zval *key) /* {{{ */
128{
129 php_dom_iterator *iterator = (php_dom_iterator *)iter;
130 dom_nnodemap_object *objmap = php_dom_iterator_get_nnmap(iterator);
131
132 /* Only dtd named node maps, i.e. the ones based on a libxml hash table or attribute collections,
133 * are keyed by the name because in that case the name is unique. */
134 if (!objmap->ht && objmap->nodetype != XML_ATTRIBUTE_NODE) {
135 ZVAL_LONG(key, iterator->index);
136 } else {
137 dom_object *intern = Z_DOMOBJ_P(&iterator->curobj);
138
139 if (intern != NULL && intern->ptr != NULL) {
140 xmlNodePtr curnode = ((php_libxml_node_ptr *)intern->ptr)->node;
141 if (objmap->nodetype == XML_ATTRIBUTE_NODE && php_dom_follow_spec_intern(intern)) {
143 } else {
144 ZVAL_STRINGL(key, (const char *) curnode->name, xmlStrlen(curnode->name));
145 }
146 } else {
147 ZVAL_NULL(key);
148 }
149 }
150}
151/* }}} */
152
153static xmlNodePtr dom_fetch_first_iteration_item(dom_nnodemap_object *objmap)
154{
155 xmlNodePtr basep = dom_object_get_node(objmap->baseobj);
156 if (!basep) {
157 return NULL;
158 }
159 if (objmap->nodetype == XML_ATTRIBUTE_NODE || objmap->nodetype == XML_ELEMENT_NODE) {
160 if (objmap->nodetype == XML_ATTRIBUTE_NODE) {
161 return (xmlNodePtr) basep->properties;
162 } else {
164 }
165 } else {
166 zend_long curindex = 0;
167 xmlNodePtr nodep = php_dom_first_child_of_container_node(basep);
169 basep, nodep, objmap->ns, objmap->local, objmap->local_lower, &curindex, 0);
170 }
171}
172
173static void php_dom_iterator_move_forward(zend_object_iterator *iter) /* {{{ */
174{
175 xmlNodePtr curnode = NULL;
176
177 php_dom_iterator *iterator = (php_dom_iterator *)iter;
178 if (Z_ISUNDEF(iterator->curobj)) {
179 return;
180 }
181
182 iterator->index++;
183
184 dom_object *intern = Z_DOMOBJ_P(&iterator->curobj);
185 dom_nnodemap_object *objmap = php_dom_iterator_get_nnmap(iterator);
186
187 if (intern != NULL && intern->ptr != NULL) {
188 if (objmap->nodetype != XML_ENTITY_NODE &&
189 objmap->nodetype != XML_NOTATION_NODE) {
190 if (objmap->nodetype == DOM_NODESET) {
191 HashTable *nodeht = HASH_OF(&objmap->baseobj_zv);
192 zval *entry;
193 zend_hash_move_forward_ex(nodeht, &iterator->pos);
194 if ((entry = zend_hash_get_current_data_ex(nodeht, &iterator->pos))) {
195 zval_ptr_dtor(&iterator->curobj);
196 ZVAL_COPY(&iterator->curobj, entry);
197 return;
198 }
199 } else {
200 if (objmap->nodetype == XML_ATTRIBUTE_NODE ||
201 objmap->nodetype == XML_ELEMENT_NODE) {
202
203 /* Note: keep legacy behaviour for non-spec mode. */
204 if (php_dom_follow_spec_intern(intern) && php_dom_is_cache_tag_stale_from_doc_ptr(&iterator->cache_tag, intern->document)) {
205 php_dom_mark_cache_tag_up_to_date_from_doc_ref(&iterator->cache_tag, intern->document);
206 curnode = dom_fetch_first_iteration_item(objmap);
207 zend_ulong index = 0;
208 while (curnode != NULL && index++ < iterator->index) {
209 curnode = curnode->next;
210 }
211 } else {
212 curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->ptr)->node;
213 curnode = curnode->next;
214 }
215 } else {
216 /* The collection is live, we nav the tree from the base object if we cannot
217 * use the cache to restart from the last point. */
218 xmlNodePtr basenode = dom_object_get_node(objmap->baseobj);
219
220 /* We have a strong reference to the base node via baseobj_zv, this cannot become NULL */
221 ZEND_ASSERT(basenode != NULL);
222
223 zend_long previndex;
224 if (php_dom_is_cache_tag_stale_from_node(&iterator->cache_tag, basenode)) {
225 php_dom_mark_cache_tag_up_to_date_from_node(&iterator->cache_tag, basenode);
226 previndex = 0;
227 curnode = php_dom_first_child_of_container_node(basenode);
228 } else {
229 previndex = iterator->index - 1;
230 curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->ptr)->node;
231 }
233 basenode, curnode, objmap->ns, objmap->local, objmap->local_lower, &previndex, iterator->index);
234 }
235 }
236 } else {
237 curnode = php_dom_libxml_hash_iter(objmap, iterator->index);
238 }
239 }
240
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
250static const 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 NULL, /* get_gc */
259};
260
261zend_object_iterator *php_dom_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */
262{
263 dom_object *intern;
264 dom_nnodemap_object *objmap;
265 xmlNodePtr curnode=NULL;
266 HashTable *nodeht;
267 zval *entry;
268 php_dom_iterator *iterator;
269
270 if (by_ref) {
271 zend_throw_error(NULL, "An iterator cannot be used with foreach by reference");
272 return NULL;
273 }
274 iterator = emalloc(sizeof(*iterator));
275 memset(iterator, 0, sizeof(*iterator));
276 zend_iterator_init(&iterator->intern);
277
278 ZVAL_OBJ_COPY(&iterator->intern.data, Z_OBJ_P(object));
279 iterator->intern.funcs = &php_dom_iterator_funcs;
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_ex(nodeht, &iterator->pos);
289 if ((entry = zend_hash_get_current_data_ex(nodeht, &iterator->pos))) {
290 ZVAL_COPY(&iterator->curobj, entry);
291 }
292 } else {
293 curnode = dom_fetch_first_iteration_item(objmap);
294 }
295 } else {
296 curnode = php_dom_libxml_hash_iter(objmap, 0);
297 }
298 }
299
300 if (curnode) {
301 php_dom_create_object(curnode, &iterator->curobj, objmap->baseobj);
302 }
303
304 return &iterator->intern;
305}
306/* }}} */
307
308#endif
memset(ptr, 0, type->size)
HashTable * ht
Definition ffi.c:4838
#define NULL
Definition gdcache.h:45
#define SUCCESS
Definition hash_sha3.c:261
#define DOM_NODESET
Definition php_dom.h:65
zend_object_iterator * php_dom_get_iterator(zend_class_entry *ce, zval *object, int by_ref)
xmlNode * php_dom_libxml_hash_iter(dom_nnodemap_object *objmap, int index)
xmlNodePtr create_notation(const xmlChar *name, const xmlChar *ExternalID, const xmlChar *SystemID)
xmlNode * dom_get_elements_by_tag_name_ns_raw(xmlNodePtr basep, xmlNodePtr nodep, xmlChar *ns, xmlChar *local, xmlChar *local_lower, zend_long *cur, zend_long index)
xmlNodePtr dom_nodelist_iter_start_first_child(xmlNodePtr nodep)
zend_string * dom_node_get_node_name_attribute_or_element(const xmlNode *nodep, bool uppercase)
const XML_ELEMENT_NODE
const XML_ATTRIBUTE_NODE
const XML_ENTITY_NODE
const XML_NOTATION_NODE
unsigned char key[REFLECTION_KEY_LEN]
zend_constant * data
void * ptr
Definition xml_common.h:26
php_libxml_ref_obj * document
Definition xml_common.h:27
const zend_object_iterator_funcs * funcs
dom_object * baseobj
Definition php_dom.h:81
xmlHashTable * ht
Definition php_dom.h:85
xmlChar * local_lower
Definition php_dom.h:86
xmlChar * local
Definition php_dom.h:86
zend_ulong index
Definition php_dom.h:102
HashPosition pos
Definition php_dom.h:99
php_libxml_cache_tag cache_tag
Definition php_dom.h:103
zend_object_iterator intern
Definition php_dom.h:97
PHP_DOM_EXPORT xmlNodePtr dom_object_get_node(dom_object *obj)
struct _dom_object dom_object
#define Z_DOMOBJ_P(zv)
Definition xml_common.h:36
PHP_DOM_EXPORT bool php_dom_create_object(xmlNodePtr obj, zval *return_value, dom_object *domobj)
ZEND_API ZEND_COLD void zend_throw_error(zend_class_entry *exception_ce, const char *format,...)
Definition zend.c:1772
#define HASH_OF(p)
Definition zend_API.h:1062
#define ZVAL_STRINGL(z, s, l)
Definition zend_API.h:952
#define emalloc(size)
Definition zend_alloc.h:151
struct _zval_struct zval
ZEND_API zend_result ZEND_FASTCALL zend_hash_move_forward_ex(HashTable *ht, HashPosition *pos)
Definition zend_hash.c:2773
ZEND_API void ZEND_FASTCALL zend_hash_internal_pointer_reset_ex(HashTable *ht, HashPosition *pos)
Definition zend_hash.c:2733
ZEND_API zval *ZEND_FASTCALL zend_hash_get_current_data_ex(HashTable *ht, HashPosition *pos)
Definition zend_hash.c:2915
ZEND_API void zend_iterator_init(zend_object_iterator *iter)
struct _zend_object_iterator zend_object_iterator
struct _zend_object_iterator_funcs zend_object_iterator_funcs
int32_t zend_long
Definition zend_long.h:42
uint32_t zend_ulong
Definition zend_long.h:43
#define ZEND_ASSERT(c)
struct _zend_class_entry zend_class_entry
#define ZVAL_UNDEF(z)
#define IS_UNDEF
Definition zend_types.h:600
#define ZVAL_NULL(z)
#define ZVAL_LONG(z, l)
struct _zend_array HashTable
Definition zend_types.h:386
#define Z_OBJ_P(zval_p)
Definition zend_types.h:990
#define Z_ISUNDEF(zval)
Definition zend_types.h:956
@ FAILURE
Definition zend_types.h:61
#define ZVAL_NEW_STR(z, s)
#define ZVAL_COPY(z, v)
#define ZVAL_OBJ_COPY(z, o)
ZEND_RESULT_CODE zend_result
Definition zend_types.h:64
#define Z_TYPE(zval)
Definition zend_types.h:659
ZEND_API void zval_ptr_dtor(zval *zval_ptr)
zend_string * name
zval * ret