/src/php-src/ext/spl/spl_iterators.c
Line | Count | Source (jump to first uncovered line) |
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: Marcus Boerger <helly@php.net> | |
14 | | +----------------------------------------------------------------------+ |
15 | | */ |
16 | | |
17 | | #ifdef HAVE_CONFIG_H |
18 | | # include "config.h" |
19 | | #endif |
20 | | |
21 | | #include "php.h" |
22 | | #include "zend_exceptions.h" |
23 | | #include "zend_interfaces.h" |
24 | | #include "ext/pcre/php_pcre.h" |
25 | | |
26 | | #include "spl_iterators.h" |
27 | | #include "spl_iterators_arginfo.h" |
28 | | #include "spl_array.h" /* For spl_ce_ArrayIterator */ |
29 | | #include "spl_exceptions.h" |
30 | | #include "zend_smart_str.h" |
31 | | |
32 | | #ifdef accept |
33 | | #undef accept |
34 | | #endif |
35 | | |
36 | | PHPAPI zend_class_entry *spl_ce_RecursiveIterator; |
37 | | PHPAPI zend_class_entry *spl_ce_RecursiveIteratorIterator; |
38 | | PHPAPI zend_class_entry *spl_ce_FilterIterator; |
39 | | PHPAPI zend_class_entry *spl_ce_CallbackFilterIterator; |
40 | | PHPAPI zend_class_entry *spl_ce_RecursiveFilterIterator; |
41 | | PHPAPI zend_class_entry *spl_ce_RecursiveCallbackFilterIterator; |
42 | | PHPAPI zend_class_entry *spl_ce_ParentIterator; |
43 | | PHPAPI zend_class_entry *spl_ce_SeekableIterator; |
44 | | PHPAPI zend_class_entry *spl_ce_LimitIterator; |
45 | | PHPAPI zend_class_entry *spl_ce_CachingIterator; |
46 | | PHPAPI zend_class_entry *spl_ce_RecursiveCachingIterator; |
47 | | PHPAPI zend_class_entry *spl_ce_OuterIterator; |
48 | | PHPAPI zend_class_entry *spl_ce_IteratorIterator; |
49 | | PHPAPI zend_class_entry *spl_ce_NoRewindIterator; |
50 | | PHPAPI zend_class_entry *spl_ce_InfiniteIterator; |
51 | | PHPAPI zend_class_entry *spl_ce_EmptyIterator; |
52 | | PHPAPI zend_class_entry *spl_ce_AppendIterator; |
53 | | PHPAPI zend_class_entry *spl_ce_RegexIterator; |
54 | | PHPAPI zend_class_entry *spl_ce_RecursiveRegexIterator; |
55 | | PHPAPI zend_class_entry *spl_ce_RecursiveTreeIterator; |
56 | | |
57 | | typedef enum { |
58 | | RS_NEXT = 0, |
59 | | RS_TEST = 1, |
60 | | RS_SELF = 2, |
61 | | RS_CHILD = 3, |
62 | | RS_START = 4 |
63 | | } RecursiveIteratorState; |
64 | | |
65 | | typedef struct _spl_sub_iterator { |
66 | | zend_object_iterator *iterator; |
67 | | zval zobject; |
68 | | zend_class_entry *ce; |
69 | | RecursiveIteratorState state; |
70 | | zend_function *haschildren; |
71 | | zend_function *getchildren; |
72 | | } spl_sub_iterator; |
73 | | |
74 | | typedef struct _spl_recursive_it_object { |
75 | | spl_sub_iterator *iterators; |
76 | | int level; |
77 | | RecursiveIteratorMode mode; |
78 | | int flags; |
79 | | int max_depth; |
80 | | bool in_iteration; |
81 | | zend_function *beginIteration; |
82 | | zend_function *endIteration; |
83 | | zend_function *callHasChildren; |
84 | | zend_function *callGetChildren; |
85 | | zend_function *beginChildren; |
86 | | zend_function *endChildren; |
87 | | zend_function *nextElement; |
88 | | zend_class_entry *ce; |
89 | | zend_string *prefix[6]; |
90 | | zend_string *postfix[1]; |
91 | | zend_object std; |
92 | | } spl_recursive_it_object; |
93 | | |
94 | | typedef struct _spl_recursive_it_iterator { |
95 | | zend_object_iterator intern; |
96 | | } spl_recursive_it_iterator; |
97 | | |
98 | | typedef struct _spl_dual_it_object { |
99 | | struct { |
100 | | zval zobject; |
101 | | zend_class_entry *ce; |
102 | | zend_object *object; |
103 | | zend_object_iterator *iterator; |
104 | | } inner; |
105 | | struct { |
106 | | zval data; |
107 | | zval key; |
108 | | zend_long pos; |
109 | | } current; |
110 | | dual_it_type dit_type; |
111 | | union { |
112 | | struct { |
113 | | zend_long offset; |
114 | | zend_long count; |
115 | | } limit; |
116 | | struct { |
117 | | zend_long flags; /* CIT_* */ |
118 | | zend_string *zstr; |
119 | | zval zchildren; |
120 | | zval zcache; |
121 | | } caching; |
122 | | struct { |
123 | | zval zarrayit; |
124 | | zend_object_iterator *iterator; |
125 | | } append; |
126 | | struct { |
127 | | zend_long flags; |
128 | | zend_long preg_flags; |
129 | | pcre_cache_entry *pce; |
130 | | zend_string *regex; |
131 | | regex_mode mode; |
132 | | } regex; |
133 | | zend_fcall_info_cache callback_filter; |
134 | | } u; |
135 | | zend_object std; |
136 | | } spl_dual_it_object; |
137 | | |
138 | | static zend_object_handlers spl_handlers_rec_it_it; |
139 | | static zend_object_handlers spl_handlers_dual_it; |
140 | | |
141 | 1.16k | static inline spl_recursive_it_object *spl_recursive_it_from_obj(zend_object *obj) /* {{{ */ { |
142 | 1.16k | return (spl_recursive_it_object*)((char*)(obj) - XtOffsetOf(spl_recursive_it_object, std)); |
143 | 1.16k | } |
144 | | /* }}} */ |
145 | | |
146 | 55 | #define Z_SPLRECURSIVE_IT_P(zv) spl_recursive_it_from_obj(Z_OBJ_P((zv))) |
147 | | |
148 | 1.46k | static inline spl_dual_it_object *spl_dual_it_from_obj(zend_object *obj) /* {{{ */ { |
149 | 1.46k | return (spl_dual_it_object*)((char*)(obj) - XtOffsetOf(spl_dual_it_object, std)); |
150 | 1.46k | } /* }}} */ |
151 | | |
152 | 548 | #define Z_SPLDUAL_IT_P(zv) spl_dual_it_from_obj(Z_OBJ_P((zv))) |
153 | | |
154 | | #define SPL_FETCH_AND_CHECK_DUAL_IT(var, objzval) \ |
155 | 413 | do { \ |
156 | 413 | spl_dual_it_object *it = Z_SPLDUAL_IT_P(objzval); \ |
157 | 413 | if (it->dit_type == DIT_Unknown) { \ |
158 | 0 | zend_throw_error(NULL, "The object is in an invalid state as the parent constructor was not called"); \ |
159 | 0 | RETURN_THROWS(); \ |
160 | 0 | } \ |
161 | 413 | (var) = it; \ |
162 | 413 | } while (0) |
163 | | |
164 | | #define SPL_FETCH_SUB_ELEMENT(var, object, element) \ |
165 | 20 | do { \ |
166 | 20 | if(!(object)->iterators) { \ |
167 | 0 | zend_throw_error(NULL, "The object is in an invalid state as the parent constructor was not called"); \ |
168 | 0 | return; \ |
169 | 0 | } \ |
170 | 20 | (var) = (object)->iterators[(object)->level].element; \ |
171 | 20 | } while (0) |
172 | | |
173 | | #define SPL_FETCH_SUB_ELEMENT_ADDR(var, object, element) \ |
174 | 0 | do { \ |
175 | 0 | if(!(object)->iterators) { \ |
176 | 0 | zend_throw_error(NULL, "The object is in an invalid state as the parent constructor was not called"); \ |
177 | 0 | RETURN_THROWS(); \ |
178 | 0 | } \ |
179 | 0 | (var) = &(object)->iterators[(object)->level].element; \ |
180 | 0 | } while (0) |
181 | | |
182 | 20 | #define SPL_FETCH_SUB_ITERATOR(var, object) SPL_FETCH_SUB_ELEMENT(var, object, iterator) |
183 | | |
184 | | |
185 | | static void spl_recursive_it_dtor(zend_object_iterator *_iter) |
186 | 5 | { |
187 | 5 | spl_recursive_it_iterator *iter = (spl_recursive_it_iterator*)_iter; |
188 | 5 | spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(&iter->intern.data); |
189 | 5 | zend_object_iterator *sub_iter; |
190 | | |
191 | 5 | if (object->iterators) { |
192 | 5 | while (object->level > 0) { |
193 | 0 | if (!Z_ISUNDEF(object->iterators[object->level].zobject)) { |
194 | 0 | sub_iter = object->iterators[object->level].iterator; |
195 | 0 | zend_iterator_dtor(sub_iter); |
196 | 0 | zval_ptr_dtor(&object->iterators[object->level].zobject); |
197 | 0 | } |
198 | 0 | object->level--; |
199 | 0 | } |
200 | 5 | object->iterators = erealloc(object->iterators, sizeof(spl_sub_iterator)); |
201 | 5 | object->level = 0; |
202 | 5 | } |
203 | | |
204 | 5 | zval_ptr_dtor(&iter->intern.data); |
205 | 5 | } |
206 | | |
207 | | static zend_result spl_recursive_it_valid_ex(spl_recursive_it_object *object, zval *zthis) |
208 | 15 | { |
209 | 15 | zend_object_iterator *sub_iter; |
210 | 15 | int level = object->level; |
211 | | |
212 | 15 | if(!object->iterators) { |
213 | 0 | return FAILURE; |
214 | 0 | } |
215 | 20 | while (level >=0) { |
216 | 15 | sub_iter = object->iterators[level].iterator; |
217 | 15 | if (sub_iter->funcs->valid(sub_iter) == SUCCESS) { |
218 | 10 | return SUCCESS; |
219 | 10 | } |
220 | 5 | level--; |
221 | 5 | } |
222 | 5 | if (object->endIteration && object->in_iteration) { |
223 | 0 | zend_call_method_with_0_params(Z_OBJ_P(zthis), object->ce, &object->endIteration, "endIteration", NULL); |
224 | 0 | } |
225 | 5 | object->in_iteration = 0; |
226 | 5 | return FAILURE; |
227 | 15 | } |
228 | | |
229 | | static zend_result spl_recursive_it_valid(zend_object_iterator *iter) |
230 | 15 | { |
231 | 15 | return spl_recursive_it_valid_ex(Z_SPLRECURSIVE_IT_P(&iter->data), &iter->data); |
232 | 15 | } |
233 | | |
234 | | static zval *spl_recursive_it_get_current_data(zend_object_iterator *iter) |
235 | 10 | { |
236 | 10 | spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(&iter->data); |
237 | 10 | zend_object_iterator *sub_iter = object->iterators[object->level].iterator; |
238 | | |
239 | 10 | return sub_iter->funcs->get_current_data(sub_iter); |
240 | 10 | } |
241 | | |
242 | | static void spl_recursive_it_get_current_key(zend_object_iterator *iter, zval *key) |
243 | 0 | { |
244 | 0 | spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(&iter->data); |
245 | 0 | zend_object_iterator *sub_iter = object->iterators[object->level].iterator; |
246 | |
|
247 | 0 | if (sub_iter->funcs->get_current_key) { |
248 | 0 | sub_iter->funcs->get_current_key(sub_iter, key); |
249 | 0 | } else { |
250 | 0 | ZVAL_LONG(key, iter->index); |
251 | 0 | } |
252 | 0 | } |
253 | | |
254 | | static void spl_recursive_it_move_forward_ex(spl_recursive_it_object *object, zval *zthis) |
255 | 15 | { |
256 | 15 | zend_object_iterator *iterator; |
257 | 15 | zend_class_entry *ce; |
258 | 15 | zval retval, child; |
259 | 15 | zend_object_iterator *sub_iter; |
260 | | |
261 | 15 | SPL_FETCH_SUB_ITERATOR(iterator, object); |
262 | | |
263 | 20 | while (!EG(exception)) { |
264 | 30 | next_step: |
265 | 30 | iterator = object->iterators[object->level].iterator; |
266 | 30 | switch (object->iterators[object->level].state) { |
267 | 10 | case RS_NEXT: |
268 | 10 | iterator->funcs->move_forward(iterator); |
269 | 10 | if (EG(exception)) { |
270 | 0 | if (!(object->flags & RIT_CATCH_GET_CHILD)) { |
271 | 0 | return; |
272 | 0 | } else { |
273 | 0 | zend_clear_exception(); |
274 | 0 | } |
275 | 0 | } |
276 | 10 | ZEND_FALLTHROUGH; |
277 | 20 | case RS_START: |
278 | 20 | if (iterator->funcs->valid(iterator) == FAILURE) { |
279 | 10 | break; |
280 | 10 | } |
281 | 10 | object->iterators[object->level].state = RS_TEST; |
282 | | /* break; */ |
283 | | /* TODO: Check this is correct */ |
284 | 10 | ZEND_FALLTHROUGH; |
285 | 10 | case RS_TEST: |
286 | 10 | if (object->callHasChildren) { |
287 | 0 | zend_call_method_with_0_params(Z_OBJ_P(zthis), object->ce, &object->callHasChildren, "callHasChildren", &retval); |
288 | 10 | } else { |
289 | 10 | zend_class_entry *ce = object->iterators[object->level].ce; |
290 | 10 | zend_object *obj = Z_OBJ(object->iterators[object->level].zobject); |
291 | 10 | zend_function **cache = &object->iterators[object->level].haschildren; |
292 | | |
293 | 10 | zend_call_method_with_0_params(obj, ce, cache, "haschildren", &retval); |
294 | 10 | } |
295 | 10 | if (EG(exception)) { |
296 | 0 | if (!(object->flags & RIT_CATCH_GET_CHILD)) { |
297 | 0 | object->iterators[object->level].state = RS_NEXT; |
298 | 0 | return; |
299 | 0 | } else { |
300 | 0 | zend_clear_exception(); |
301 | 0 | } |
302 | 0 | } |
303 | 10 | if (Z_TYPE(retval) != IS_UNDEF) { |
304 | 10 | bool has_children = zend_is_true(&retval); |
305 | 10 | zval_ptr_dtor(&retval); |
306 | 10 | if (has_children) { |
307 | 5 | if (object->max_depth == -1 || object->max_depth > object->level) { |
308 | 5 | switch (object->mode) { |
309 | 0 | case RIT_LEAVES_ONLY: |
310 | 0 | case RIT_CHILD_FIRST: |
311 | 0 | object->iterators[object->level].state = RS_CHILD; |
312 | 0 | goto next_step; |
313 | 5 | case RIT_SELF_FIRST: |
314 | 5 | object->iterators[object->level].state = RS_SELF; |
315 | 5 | goto next_step; |
316 | 5 | } |
317 | 5 | } else { |
318 | | /* do not recurse into */ |
319 | 0 | if (object->mode == RIT_LEAVES_ONLY) { |
320 | | /* this is not a leave, so skip it */ |
321 | 0 | object->iterators[object->level].state = RS_NEXT; |
322 | 0 | goto next_step; |
323 | 0 | } |
324 | 0 | } |
325 | 5 | } |
326 | 10 | } |
327 | 5 | if (object->nextElement) { |
328 | 0 | zend_call_method_with_0_params(Z_OBJ_P(zthis), object->ce, &object->nextElement, "nextelement", NULL); |
329 | 0 | } |
330 | 5 | object->iterators[object->level].state = RS_NEXT; |
331 | 5 | if (EG(exception)) { |
332 | 0 | if (!(object->flags & RIT_CATCH_GET_CHILD)) { |
333 | 0 | return; |
334 | 0 | } else { |
335 | 0 | zend_clear_exception(); |
336 | 0 | } |
337 | 0 | } |
338 | 5 | return /* self */; |
339 | 5 | case RS_SELF: |
340 | 5 | if (object->nextElement && (object->mode == RIT_SELF_FIRST || object->mode == RIT_CHILD_FIRST)) { |
341 | 0 | zend_call_method_with_0_params(Z_OBJ_P(zthis), object->ce, &object->nextElement, "nextelement", NULL); |
342 | 0 | } |
343 | 5 | if (object->mode == RIT_SELF_FIRST) { |
344 | 5 | object->iterators[object->level].state = RS_CHILD; |
345 | 5 | } else { |
346 | 0 | object->iterators[object->level].state = RS_NEXT; |
347 | 0 | } |
348 | 5 | return /* self */; |
349 | 5 | case RS_CHILD: |
350 | 5 | if (object->callGetChildren) { |
351 | 0 | zend_call_method_with_0_params(Z_OBJ_P(zthis), object->ce, &object->callGetChildren, "callGetChildren", &child); |
352 | 5 | } else { |
353 | 5 | zend_class_entry *ce = object->iterators[object->level].ce; |
354 | 5 | zend_object *obj = Z_OBJ(object->iterators[object->level].zobject); |
355 | 5 | zend_function **cache = &object->iterators[object->level].getchildren; |
356 | | |
357 | 5 | zend_call_method_with_0_params(obj, ce, cache, "getchildren", &child); |
358 | 5 | } |
359 | | |
360 | 5 | if (EG(exception)) { |
361 | 0 | if (!(object->flags & RIT_CATCH_GET_CHILD)) { |
362 | 0 | return; |
363 | 0 | } else { |
364 | 0 | zend_clear_exception(); |
365 | 0 | zval_ptr_dtor(&child); |
366 | 0 | object->iterators[object->level].state = RS_NEXT; |
367 | 0 | goto next_step; |
368 | 0 | } |
369 | 0 | } |
370 | | |
371 | 5 | if (Z_TYPE(child) == IS_UNDEF || Z_TYPE(child) != IS_OBJECT || |
372 | 5 | !((ce = Z_OBJCE(child)) && instanceof_function(ce, spl_ce_RecursiveIterator))) { |
373 | 0 | zval_ptr_dtor(&child); |
374 | 0 | zend_throw_exception(spl_ce_UnexpectedValueException, "Objects returned by RecursiveIterator::getChildren() must implement RecursiveIterator", 0); |
375 | 0 | return; |
376 | 0 | } |
377 | | |
378 | 5 | if (object->mode == RIT_CHILD_FIRST) { |
379 | 0 | object->iterators[object->level].state = RS_SELF; |
380 | 5 | } else { |
381 | 5 | object->iterators[object->level].state = RS_NEXT; |
382 | 5 | } |
383 | 5 | object->iterators = erealloc(object->iterators, sizeof(spl_sub_iterator) * (++object->level+1)); |
384 | 5 | sub_iter = ce->get_iterator(ce, &child, 0); |
385 | 5 | ZVAL_COPY_VALUE(&object->iterators[object->level].zobject, &child); |
386 | 5 | object->iterators[object->level].iterator = sub_iter; |
387 | 5 | object->iterators[object->level].ce = ce; |
388 | 5 | object->iterators[object->level].state = RS_START; |
389 | 5 | if (object->level > 0 |
390 | 5 | && object->iterators[object->level - 1].ce == 0) { |
391 | 0 | object->iterators[object->level].haschildren = |
392 | 0 | object->iterators[object->level - 1].haschildren; |
393 | 0 | object->iterators[object->level].getchildren = |
394 | 0 | object->iterators[object->level - 1].getchildren; |
395 | 5 | } else { |
396 | 5 | object->iterators[object->level].haschildren = NULL; |
397 | 5 | object->iterators[object->level].getchildren = NULL; |
398 | 5 | } |
399 | 5 | if (sub_iter->funcs->rewind) { |
400 | 5 | sub_iter->funcs->rewind(sub_iter); |
401 | 5 | } |
402 | 5 | if (object->beginChildren) { |
403 | 0 | zend_call_method_with_0_params(Z_OBJ_P(zthis), object->ce, &object->beginChildren, "beginchildren", NULL); |
404 | 0 | if (EG(exception)) { |
405 | 0 | if (!(object->flags & RIT_CATCH_GET_CHILD)) { |
406 | 0 | return; |
407 | 0 | } else { |
408 | 0 | zend_clear_exception(); |
409 | 0 | } |
410 | 0 | } |
411 | 0 | } |
412 | 5 | goto next_step; |
413 | 30 | } |
414 | | /* no more elements */ |
415 | 10 | if (object->level > 0) { |
416 | 5 | if (object->endChildren) { |
417 | 0 | zend_call_method_with_0_params(Z_OBJ_P(zthis), object->ce, &object->endChildren, "endchildren", NULL); |
418 | 0 | if (EG(exception)) { |
419 | 0 | if (!(object->flags & RIT_CATCH_GET_CHILD)) { |
420 | 0 | return; |
421 | 0 | } else { |
422 | 0 | zend_clear_exception(); |
423 | 0 | } |
424 | 0 | } |
425 | 0 | } |
426 | 5 | if (object->level > 0) { |
427 | 5 | zval garbage; |
428 | 5 | ZVAL_COPY_VALUE(&garbage, &object->iterators[object->level].zobject); |
429 | 5 | ZVAL_UNDEF(&object->iterators[object->level].zobject); |
430 | 5 | zval_ptr_dtor(&garbage); |
431 | 5 | zend_iterator_dtor(iterator); |
432 | 5 | object->level--; |
433 | 5 | } |
434 | 5 | } else { |
435 | 5 | return; /* done completeley */ |
436 | 5 | } |
437 | 10 | } |
438 | 15 | } |
439 | | |
440 | | static void spl_recursive_it_rewind_ex(spl_recursive_it_object *object, zval *zthis) |
441 | 5 | { |
442 | 5 | zend_object_iterator *sub_iter; |
443 | | |
444 | 5 | SPL_FETCH_SUB_ITERATOR(sub_iter, object); |
445 | | |
446 | 5 | while (object->level) { |
447 | 0 | sub_iter = object->iterators[object->level].iterator; |
448 | 0 | zend_iterator_dtor(sub_iter); |
449 | 0 | zval_ptr_dtor(&object->iterators[object->level--].zobject); |
450 | 0 | if (!EG(exception) && (!object->endChildren || object->endChildren->common.scope != spl_ce_RecursiveIteratorIterator)) { |
451 | 0 | zend_call_method_with_0_params(Z_OBJ_P(zthis), object->ce, &object->endChildren, "endchildren", NULL); |
452 | 0 | } |
453 | 0 | } |
454 | 5 | object->iterators = erealloc(object->iterators, sizeof(spl_sub_iterator)); |
455 | 5 | object->iterators[0].state = RS_START; |
456 | 5 | sub_iter = object->iterators[0].iterator; |
457 | 5 | if (sub_iter->funcs->rewind) { |
458 | 5 | sub_iter->funcs->rewind(sub_iter); |
459 | 5 | } |
460 | 5 | if (!EG(exception) && object->beginIteration && !object->in_iteration) { |
461 | 0 | zend_call_method_with_0_params(Z_OBJ_P(zthis), object->ce, &object->beginIteration, "beginIteration", NULL); |
462 | 0 | } |
463 | 5 | object->in_iteration = 1; |
464 | 5 | spl_recursive_it_move_forward_ex(object, zthis); |
465 | 5 | } |
466 | | |
467 | | static void spl_recursive_it_move_forward(zend_object_iterator *iter) |
468 | 10 | { |
469 | 10 | spl_recursive_it_move_forward_ex(Z_SPLRECURSIVE_IT_P(&iter->data), &iter->data); |
470 | 10 | } |
471 | | |
472 | | static void spl_recursive_it_rewind(zend_object_iterator *iter) |
473 | 5 | { |
474 | 5 | spl_recursive_it_rewind_ex(Z_SPLRECURSIVE_IT_P(&iter->data), &iter->data); |
475 | 5 | } |
476 | | |
477 | | static const zend_object_iterator_funcs spl_recursive_it_iterator_funcs = { |
478 | | spl_recursive_it_dtor, |
479 | | spl_recursive_it_valid, |
480 | | spl_recursive_it_get_current_data, |
481 | | spl_recursive_it_get_current_key, |
482 | | spl_recursive_it_move_forward, |
483 | | spl_recursive_it_rewind, |
484 | | NULL, |
485 | | NULL, /* get_gc */ |
486 | | }; |
487 | | |
488 | | static zend_object_iterator *spl_recursive_it_get_iterator(zend_class_entry *ce, zval *zobject, int by_ref) |
489 | 5 | { |
490 | 5 | if (by_ref) { |
491 | 0 | zend_throw_error(NULL, "An iterator cannot be used with foreach by reference"); |
492 | 0 | return NULL; |
493 | 0 | } |
494 | | |
495 | 5 | spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(zobject); |
496 | 5 | if (object->iterators == NULL) { |
497 | 0 | zend_throw_error(NULL, "Object is not initialized"); |
498 | 0 | return NULL; |
499 | 0 | } |
500 | | |
501 | 5 | spl_recursive_it_iterator *iterator = emalloc(sizeof(spl_recursive_it_iterator)); |
502 | 5 | zend_iterator_init((zend_object_iterator*)iterator); |
503 | | |
504 | 5 | ZVAL_OBJ_COPY(&iterator->intern.data, Z_OBJ_P(zobject)); |
505 | 5 | iterator->intern.funcs = &spl_recursive_it_iterator_funcs; |
506 | 5 | return (zend_object_iterator*)iterator; |
507 | 5 | } |
508 | | |
509 | 0 | static zend_result spl_get_iterator_from_aggregate(zval *retval, zend_class_entry *ce, zend_object *obj) { |
510 | 0 | zend_function **getiterator_cache = |
511 | 0 | ce->iterator_funcs_ptr ? &ce->iterator_funcs_ptr->zf_new_iterator : NULL; |
512 | 0 | zend_call_method_with_0_params(obj, ce, getiterator_cache, "getiterator", retval); |
513 | 0 | if (EG(exception)) { |
514 | 0 | return FAILURE; |
515 | 0 | } |
516 | 0 | if (Z_TYPE_P(retval) != IS_OBJECT |
517 | 0 | || !instanceof_function(Z_OBJCE_P(retval), zend_ce_traversable)) { |
518 | 0 | zend_throw_exception_ex(spl_ce_LogicException, 0, |
519 | 0 | "%s::getIterator() must return an object that implements Traversable", |
520 | 0 | ZSTR_VAL(ce->name)); |
521 | 0 | zval_ptr_dtor(retval); |
522 | 0 | return FAILURE; |
523 | 0 | } |
524 | 0 | return SUCCESS; |
525 | 0 | } |
526 | | |
527 | | static void spl_RecursiveIteratorIterator_free_iterators(spl_recursive_it_object *object) |
528 | 301 | { |
529 | 301 | if (object->iterators) { |
530 | 10 | while (object->level >= 0) { |
531 | 5 | zend_object_iterator *sub_iter = object->iterators[object->level].iterator; |
532 | 5 | zend_iterator_dtor(sub_iter); |
533 | 5 | zval_ptr_dtor(&object->iterators[object->level].zobject); |
534 | 5 | object->level--; |
535 | 5 | } |
536 | 5 | efree(object->iterators); |
537 | 5 | object->iterators = NULL; |
538 | 5 | } |
539 | 301 | } |
540 | | |
541 | | static void spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *ce_base, zend_class_entry *ce_inner, recursive_it_it_type rit_type) |
542 | 15 | { |
543 | 15 | zval *object = ZEND_THIS; |
544 | 15 | spl_recursive_it_object *intern; |
545 | 15 | zval *iterator; |
546 | 15 | zend_class_entry *ce_iterator; |
547 | 15 | zend_long mode, flags; |
548 | 15 | zval caching_it, aggregate_retval; |
549 | | |
550 | 15 | switch (rit_type) { |
551 | 5 | case RIT_RecursiveTreeIterator: { |
552 | 5 | zend_long user_caching_it_flags = CIT_CATCH_GET_CHILD; |
553 | 5 | mode = RIT_SELF_FIRST; |
554 | 5 | flags = RTIT_BYPASS_KEY; |
555 | | |
556 | 5 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "o|lll", &iterator, &flags, &user_caching_it_flags, &mode) == FAILURE) { |
557 | 5 | RETURN_THROWS(); |
558 | 5 | } |
559 | | |
560 | 0 | if (instanceof_function(Z_OBJCE_P(iterator), zend_ce_aggregate)) { |
561 | 0 | if (spl_get_iterator_from_aggregate( |
562 | 0 | &aggregate_retval, Z_OBJCE_P(iterator), Z_OBJ_P(iterator)) == FAILURE) { |
563 | 0 | RETURN_THROWS(); |
564 | 0 | } |
565 | 0 | iterator = &aggregate_retval; |
566 | 0 | } else { |
567 | 0 | Z_ADDREF_P(iterator); |
568 | 0 | } |
569 | | |
570 | 0 | zval params[2]; |
571 | 0 | ZVAL_COPY_VALUE(¶ms[0], iterator); |
572 | 0 | ZVAL_LONG(¶ms[1], user_caching_it_flags); |
573 | 0 | zend_result is_initialized = object_init_with_constructor(&caching_it, spl_ce_RecursiveCachingIterator, 2, params, NULL); |
574 | 0 | zval_ptr_dtor(¶ms[0]); |
575 | 0 | if (is_initialized == FAILURE) { |
576 | 0 | RETURN_THROWS(); |
577 | 0 | } |
578 | | |
579 | 0 | iterator = &caching_it; |
580 | 0 | break; |
581 | 0 | } |
582 | 10 | case RIT_RecursiveIteratorIterator: |
583 | 10 | default: { |
584 | 10 | mode = RIT_LEAVES_ONLY; |
585 | 10 | flags = 0; |
586 | 10 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "o|ll", &iterator, &mode, &flags) == FAILURE) { |
587 | 5 | RETURN_THROWS(); |
588 | 5 | } |
589 | | |
590 | 5 | if (instanceof_function(Z_OBJCE_P(iterator), zend_ce_aggregate)) { |
591 | 0 | if (spl_get_iterator_from_aggregate( |
592 | 0 | &aggregate_retval, Z_OBJCE_P(iterator), Z_OBJ_P(iterator)) == FAILURE) { |
593 | 0 | RETURN_THROWS(); |
594 | 0 | } |
595 | 0 | iterator = &aggregate_retval; |
596 | 5 | } else { |
597 | 5 | Z_ADDREF_P(iterator); |
598 | 5 | } |
599 | 5 | break; |
600 | 5 | } |
601 | 15 | } |
602 | 5 | if (!instanceof_function(Z_OBJCE_P(iterator), spl_ce_RecursiveIterator)) { |
603 | 0 | if (iterator) { |
604 | 0 | zval_ptr_dtor(iterator); |
605 | 0 | } |
606 | 0 | zend_throw_exception(spl_ce_InvalidArgumentException, "An instance of RecursiveIterator or IteratorAggregate creating it is required", 0); |
607 | 0 | return; |
608 | 0 | } |
609 | | |
610 | 5 | intern = Z_SPLRECURSIVE_IT_P(object); |
611 | 5 | spl_RecursiveIteratorIterator_free_iterators(intern); |
612 | 5 | intern->iterators = emalloc(sizeof(spl_sub_iterator)); |
613 | 5 | intern->level = 0; |
614 | 5 | intern->mode = mode; |
615 | 5 | intern->flags = (int)flags; |
616 | 5 | intern->max_depth = -1; |
617 | 5 | intern->in_iteration = 0; |
618 | 5 | intern->ce = Z_OBJCE_P(object); |
619 | | |
620 | 5 | intern->beginIteration = zend_hash_str_find_ptr(&intern->ce->function_table, "beginiteration", sizeof("beginiteration") - 1); |
621 | 5 | if (intern->beginIteration->common.scope == ce_base) { |
622 | 5 | intern->beginIteration = NULL; |
623 | 5 | } |
624 | 5 | intern->endIteration = zend_hash_str_find_ptr(&intern->ce->function_table, "enditeration", sizeof("enditeration") - 1); |
625 | 5 | if (intern->endIteration->common.scope == ce_base) { |
626 | 5 | intern->endIteration = NULL; |
627 | 5 | } |
628 | 5 | intern->callHasChildren = zend_hash_str_find_ptr(&intern->ce->function_table, "callhaschildren", sizeof("callHasChildren") - 1); |
629 | 5 | if (intern->callHasChildren->common.scope == ce_base) { |
630 | 5 | intern->callHasChildren = NULL; |
631 | 5 | } |
632 | 5 | intern->callGetChildren = zend_hash_str_find_ptr(&intern->ce->function_table, "callgetchildren", sizeof("callGetChildren") - 1); |
633 | 5 | if (intern->callGetChildren->common.scope == ce_base) { |
634 | 5 | intern->callGetChildren = NULL; |
635 | 5 | } |
636 | 5 | intern->beginChildren = zend_hash_str_find_ptr(&intern->ce->function_table, "beginchildren", sizeof("beginchildren") - 1); |
637 | 5 | if (intern->beginChildren->common.scope == ce_base) { |
638 | 5 | intern->beginChildren = NULL; |
639 | 5 | } |
640 | 5 | intern->endChildren = zend_hash_str_find_ptr(&intern->ce->function_table, "endchildren", sizeof("endchildren") - 1); |
641 | 5 | if (intern->endChildren->common.scope == ce_base) { |
642 | 5 | intern->endChildren = NULL; |
643 | 5 | } |
644 | 5 | intern->nextElement = zend_hash_str_find_ptr(&intern->ce->function_table, "nextelement", sizeof("nextElement") - 1); |
645 | 5 | if (intern->nextElement->common.scope == ce_base) { |
646 | 5 | intern->nextElement = NULL; |
647 | 5 | } |
648 | | |
649 | 5 | ce_iterator = Z_OBJCE_P(iterator); /* respect inheritance, don't use spl_ce_RecursiveIterator */ |
650 | 5 | intern->iterators[0].iterator = ce_iterator->get_iterator(ce_iterator, iterator, 0); |
651 | 5 | ZVAL_OBJ(&intern->iterators[0].zobject, Z_OBJ_P(iterator)); |
652 | 5 | intern->iterators[0].ce = ce_iterator; |
653 | 5 | intern->iterators[0].state = RS_START; |
654 | 5 | intern->iterators[0].haschildren = NULL; |
655 | 5 | intern->iterators[0].getchildren = NULL; |
656 | | |
657 | 5 | if (EG(exception)) { |
658 | 0 | spl_RecursiveIteratorIterator_free_iterators(intern); |
659 | 0 | } |
660 | 5 | } |
661 | | |
662 | | /* {{{ Creates a RecursiveIteratorIterator from a RecursiveIterator. */ |
663 | | PHP_METHOD(RecursiveIteratorIterator, __construct) |
664 | 10 | { |
665 | 10 | spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveIteratorIterator, zend_ce_iterator, RIT_RecursiveIteratorIterator); |
666 | 10 | } /* }}} */ |
667 | | |
668 | | /* {{{ Rewind the iterator to the first element of the top level inner iterator. */ |
669 | | PHP_METHOD(RecursiveIteratorIterator, rewind) |
670 | 0 | { |
671 | 0 | spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS); |
672 | |
|
673 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
674 | 0 | spl_recursive_it_rewind_ex(object, ZEND_THIS); |
675 | 0 | } /* }}} */ |
676 | | |
677 | | /* {{{ Check whether the current position is valid */ |
678 | | PHP_METHOD(RecursiveIteratorIterator, valid) |
679 | 0 | { |
680 | 0 | spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS); |
681 | |
|
682 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
683 | 0 | RETURN_BOOL(spl_recursive_it_valid_ex(object, ZEND_THIS) == SUCCESS); |
684 | 0 | } /* }}} */ |
685 | | |
686 | | /* {{{ Access the current key */ |
687 | | PHP_METHOD(RecursiveIteratorIterator, key) |
688 | 0 | { |
689 | 0 | spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS); |
690 | 0 | zend_object_iterator *iterator; |
691 | |
|
692 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
693 | | |
694 | 0 | SPL_FETCH_SUB_ITERATOR(iterator, object); |
695 | | |
696 | 0 | if (iterator->funcs->get_current_key) { |
697 | 0 | iterator->funcs->get_current_key(iterator, return_value); |
698 | 0 | } else { |
699 | 0 | RETURN_NULL(); |
700 | 0 | } |
701 | 0 | } /* }}} */ |
702 | | |
703 | | /* {{{ Access the current element value */ |
704 | | PHP_METHOD(RecursiveIteratorIterator, current) |
705 | 0 | { |
706 | 0 | spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS); |
707 | 0 | zend_object_iterator *iterator; |
708 | 0 | zval *data; |
709 | |
|
710 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
711 | | |
712 | 0 | SPL_FETCH_SUB_ITERATOR(iterator, object); |
713 | | |
714 | 0 | data = iterator->funcs->get_current_data(iterator); |
715 | 0 | if (data) { |
716 | 0 | RETURN_COPY_DEREF(data); |
717 | 0 | } |
718 | 0 | } /* }}} */ |
719 | | |
720 | | /* {{{ Move forward to the next element */ |
721 | | PHP_METHOD(RecursiveIteratorIterator, next) |
722 | 0 | { |
723 | 0 | spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS); |
724 | |
|
725 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
726 | 0 | spl_recursive_it_move_forward_ex(object, ZEND_THIS); |
727 | 0 | } /* }}} */ |
728 | | |
729 | | /* {{{ Get the current depth of the recursive iteration */ |
730 | | PHP_METHOD(RecursiveIteratorIterator, getDepth) |
731 | 0 | { |
732 | 0 | spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS); |
733 | |
|
734 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
735 | 0 | RETURN_LONG(object->level); |
736 | 0 | } /* }}} */ |
737 | | |
738 | | /* {{{ The current active sub iterator or the iterator at specified level */ |
739 | | PHP_METHOD(RecursiveIteratorIterator, getSubIterator) |
740 | 0 | { |
741 | 0 | spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS); |
742 | 0 | zend_long level; |
743 | 0 | bool level_is_null = 1; |
744 | 0 | zval *value; |
745 | |
|
746 | 0 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l!", &level, &level_is_null) == FAILURE) { |
747 | 0 | RETURN_THROWS(); |
748 | 0 | } |
749 | | |
750 | 0 | if (level_is_null) { |
751 | 0 | level = object->level; |
752 | 0 | } else if (level < 0 || level > object->level) { |
753 | 0 | RETURN_NULL(); |
754 | 0 | } |
755 | | |
756 | 0 | if(!object->iterators) { |
757 | 0 | zend_throw_error(NULL, "The object is in an invalid state as the parent constructor was not called"); |
758 | 0 | RETURN_THROWS(); |
759 | 0 | } |
760 | | |
761 | 0 | value = &object->iterators[level].zobject; |
762 | 0 | RETURN_COPY_DEREF(value); |
763 | 0 | } /* }}} */ |
764 | | |
765 | | /* {{{ The current active sub iterator */ |
766 | | PHP_METHOD(RecursiveIteratorIterator, getInnerIterator) |
767 | 0 | { |
768 | 0 | spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS); |
769 | 0 | zval *zobject; |
770 | |
|
771 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
772 | 0 | SPL_FETCH_SUB_ELEMENT_ADDR(zobject, object, zobject); |
773 | 0 | RETURN_COPY_DEREF(zobject); |
774 | 0 | } /* }}} */ |
775 | | |
776 | | /* {{{ Called when iteration begins (after first rewind() call) */ |
777 | | PHP_METHOD(RecursiveIteratorIterator, beginIteration) |
778 | 0 | { |
779 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
780 | | /* nothing to do */ |
781 | 0 | } /* }}} */ |
782 | | |
783 | | /* {{{ Called when iteration ends (when valid() first returns false */ |
784 | | PHP_METHOD(RecursiveIteratorIterator, endIteration) |
785 | 0 | { |
786 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
787 | | /* nothing to do */ |
788 | 0 | } /* }}} */ |
789 | | |
790 | | /* {{{ Called for each element to test whether it has children */ |
791 | | PHP_METHOD(RecursiveIteratorIterator, callHasChildren) |
792 | 0 | { |
793 | 0 | spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS); |
794 | 0 | zend_class_entry *ce; |
795 | 0 | zval *zobject; |
796 | |
|
797 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
798 | | |
799 | 0 | if (!object->iterators) { |
800 | 0 | RETURN_FALSE; |
801 | 0 | } |
802 | | |
803 | 0 | SPL_FETCH_SUB_ELEMENT(ce, object, ce); |
804 | | |
805 | 0 | zobject = &object->iterators[object->level].zobject; |
806 | 0 | if (Z_TYPE_P(zobject) == IS_UNDEF) { |
807 | 0 | RETURN_FALSE; |
808 | 0 | } else { |
809 | 0 | zend_call_method_with_0_params(Z_OBJ_P(zobject), ce, &object->iterators[object->level].haschildren, "haschildren", return_value); |
810 | 0 | if (Z_TYPE_P(return_value) == IS_UNDEF) { |
811 | 0 | RETURN_FALSE; |
812 | 0 | } |
813 | 0 | } |
814 | 0 | } /* }}} */ |
815 | | |
816 | | /* {{{ Return children of current element */ |
817 | | PHP_METHOD(RecursiveIteratorIterator, callGetChildren) |
818 | 0 | { |
819 | 0 | spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS); |
820 | 0 | zend_class_entry *ce; |
821 | 0 | zval *zobject; |
822 | |
|
823 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
824 | | |
825 | 0 | SPL_FETCH_SUB_ELEMENT(ce, object, ce); |
826 | | |
827 | 0 | zobject = &object->iterators[object->level].zobject; |
828 | 0 | if (Z_TYPE_P(zobject) == IS_UNDEF) { |
829 | 0 | RETURN_NULL(); |
830 | 0 | } else { |
831 | 0 | zend_call_method_with_0_params(Z_OBJ_P(zobject), ce, &object->iterators[object->level].getchildren, "getchildren", return_value); |
832 | 0 | if (Z_TYPE_P(return_value) == IS_UNDEF) { |
833 | 0 | RETURN_NULL(); |
834 | 0 | } |
835 | 0 | } |
836 | 0 | } /* }}} */ |
837 | | |
838 | | /* {{{ Called when recursing one level down */ |
839 | | PHP_METHOD(RecursiveIteratorIterator, beginChildren) |
840 | 0 | { |
841 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
842 | | /* nothing to do */ |
843 | 0 | } /* }}} */ |
844 | | |
845 | | /* {{{ Called when end recursing one level */ |
846 | | PHP_METHOD(RecursiveIteratorIterator, endChildren) |
847 | 0 | { |
848 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
849 | | /* nothing to do */ |
850 | 0 | } /* }}} */ |
851 | | |
852 | | /* {{{ Called when the next element is available */ |
853 | | PHP_METHOD(RecursiveIteratorIterator, nextElement) |
854 | 0 | { |
855 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
856 | | /* nothing to do */ |
857 | 0 | } /* }}} */ |
858 | | |
859 | | /* {{{ Set the maximum allowed depth (or any depth if pmax_depth = -1] */ |
860 | | PHP_METHOD(RecursiveIteratorIterator, setMaxDepth) |
861 | 0 | { |
862 | 0 | spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS); |
863 | 0 | zend_long max_depth = -1; |
864 | |
|
865 | 0 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &max_depth) == FAILURE) { |
866 | 0 | RETURN_THROWS(); |
867 | 0 | } |
868 | 0 | if (max_depth < -1) { |
869 | 0 | zend_argument_value_error(1, "must be greater than or equal to -1"); |
870 | 0 | RETURN_THROWS(); |
871 | 0 | } else if (max_depth > INT_MAX) { |
872 | 0 | max_depth = INT_MAX; |
873 | 0 | } |
874 | | |
875 | 0 | object->max_depth = (int)max_depth; |
876 | 0 | } /* }}} */ |
877 | | |
878 | | /* {{{ Return the maximum accepted depth or false if any depth is allowed */ |
879 | | PHP_METHOD(RecursiveIteratorIterator, getMaxDepth) |
880 | 0 | { |
881 | 0 | spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS); |
882 | |
|
883 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
884 | | |
885 | 0 | if (object->max_depth == -1) { |
886 | 0 | RETURN_FALSE; |
887 | 0 | } else { |
888 | 0 | RETURN_LONG(object->max_depth); |
889 | 0 | } |
890 | 0 | } /* }}} */ |
891 | | |
892 | | static zend_function *spl_recursive_it_get_method(zend_object **zobject, zend_string *method, const zval *key) |
893 | 0 | { |
894 | 0 | zend_function *function_handler; |
895 | 0 | spl_recursive_it_object *object = spl_recursive_it_from_obj(*zobject); |
896 | 0 | zend_long level = object->level; |
897 | 0 | zval *zobj; |
898 | |
|
899 | 0 | if (!object->iterators) { |
900 | 0 | zend_throw_error(NULL, "The %s instance wasn't initialized properly", ZSTR_VAL((*zobject)->ce->name)); |
901 | 0 | return NULL; |
902 | 0 | } |
903 | 0 | zobj = &object->iterators[level].zobject; |
904 | |
|
905 | 0 | function_handler = zend_std_get_method(zobject, method, key); |
906 | 0 | if (!function_handler) { |
907 | 0 | if ((function_handler = zend_hash_find_ptr(&Z_OBJCE_P(zobj)->function_table, method)) == NULL) { |
908 | 0 | *zobject = Z_OBJ_P(zobj); |
909 | 0 | function_handler = (*zobject)->handlers->get_method(zobject, method, key); |
910 | 0 | } else { |
911 | 0 | *zobject = Z_OBJ_P(zobj); |
912 | 0 | } |
913 | 0 | } |
914 | 0 | return function_handler; |
915 | 0 | } |
916 | | |
917 | | /* {{{ spl_RecursiveIteratorIterator_free_storage */ |
918 | | static void spl_RecursiveIteratorIterator_free_storage(zend_object *_object) |
919 | 296 | { |
920 | 296 | spl_recursive_it_object *object = spl_recursive_it_from_obj(_object); |
921 | | |
922 | 296 | spl_RecursiveIteratorIterator_free_iterators(object); |
923 | | |
924 | 296 | zend_object_std_dtor(&object->std); |
925 | 2.07k | for (size_t i = 0; i < 6; i++) { |
926 | 1.77k | if (object->prefix[i]) { |
927 | 90 | zend_string_release(object->prefix[i]); |
928 | 90 | } |
929 | 1.77k | } |
930 | | |
931 | 296 | if (object->postfix[0]) { |
932 | 15 | zend_string_release(object->postfix[0]); |
933 | 15 | } |
934 | 296 | } |
935 | | /* }}} */ |
936 | | |
937 | | static HashTable *spl_RecursiveIteratorIterator_get_gc(zend_object *obj, zval **table, int *n) |
938 | 811 | { |
939 | 811 | spl_recursive_it_object *object = spl_recursive_it_from_obj(obj); |
940 | 811 | zend_get_gc_buffer *gc_buffer = zend_get_gc_buffer_create(); |
941 | | |
942 | 811 | if (object->iterators) { |
943 | 20 | for (int level = 0; level <= object->level; level++) { |
944 | 10 | zend_get_gc_buffer_add_zval(gc_buffer, &object->iterators[level].zobject); |
945 | 10 | zend_get_gc_buffer_add_obj(gc_buffer, &object->iterators[level].iterator->std); |
946 | 10 | } |
947 | 10 | } |
948 | | |
949 | 811 | zend_get_gc_buffer_use(gc_buffer, table, n); |
950 | 811 | return zend_std_get_properties(obj); |
951 | 811 | } |
952 | | |
953 | | /* {{{ spl_RecursiveIteratorIterator_new_ex */ |
954 | | static zend_object *spl_RecursiveIteratorIterator_new_ex(zend_class_entry *class_type, int init_prefix) |
955 | 296 | { |
956 | 296 | spl_recursive_it_object *intern; |
957 | | |
958 | 296 | intern = zend_object_alloc(sizeof(spl_recursive_it_object), class_type); |
959 | | |
960 | 296 | if (init_prefix) { |
961 | 15 | intern->prefix[0] = ZSTR_EMPTY_ALLOC(); |
962 | 15 | intern->prefix[1] = ZSTR_INIT_LITERAL("| ", 0); |
963 | 15 | intern->prefix[2] = ZSTR_INIT_LITERAL(" ", 0); |
964 | 15 | intern->prefix[3] = ZSTR_INIT_LITERAL("|-", 0); |
965 | 15 | intern->prefix[4] = ZSTR_INIT_LITERAL("\\-", 0); |
966 | 15 | intern->prefix[5] = ZSTR_EMPTY_ALLOC(); |
967 | | |
968 | 15 | intern->postfix[0] = ZSTR_EMPTY_ALLOC(); |
969 | 15 | } |
970 | | |
971 | 296 | zend_object_std_init(&intern->std, class_type); |
972 | 296 | object_properties_init(&intern->std, class_type); |
973 | | |
974 | 296 | return &intern->std; |
975 | 296 | } |
976 | | /* }}} */ |
977 | | |
978 | | /* {{{ spl_RecursiveIteratorIterator_new */ |
979 | | static zend_object *spl_RecursiveIteratorIterator_new(zend_class_entry *class_type) |
980 | 281 | { |
981 | 281 | return spl_RecursiveIteratorIterator_new_ex(class_type, 0); |
982 | 281 | } |
983 | | /* }}} */ |
984 | | |
985 | | /* {{{ spl_RecursiveTreeIterator_new */ |
986 | | static zend_object *spl_RecursiveTreeIterator_new(zend_class_entry *class_type) |
987 | 15 | { |
988 | 15 | return spl_RecursiveIteratorIterator_new_ex(class_type, 1); |
989 | 15 | } |
990 | | /* }}} */ |
991 | | |
992 | | static zend_string *spl_recursive_tree_iterator_get_prefix(spl_recursive_it_object *object) |
993 | 0 | { |
994 | 0 | smart_str str = {0}; |
995 | 0 | zval has_next; |
996 | 0 | int level; |
997 | |
|
998 | 0 | smart_str_append(&str, object->prefix[0]); |
999 | |
|
1000 | 0 | for (level = 0; level < object->level; ++level) { |
1001 | 0 | zend_call_method_with_0_params(Z_OBJ(object->iterators[level].zobject), object->iterators[level].ce, NULL, "hasnext", &has_next); |
1002 | 0 | if (Z_TYPE(has_next) != IS_UNDEF) { |
1003 | 0 | if (Z_TYPE(has_next) == IS_TRUE) { |
1004 | 0 | smart_str_append(&str, object->prefix[1]); |
1005 | 0 | } else { |
1006 | 0 | smart_str_append(&str, object->prefix[2]); |
1007 | 0 | } |
1008 | 0 | zval_ptr_dtor(&has_next); |
1009 | 0 | } |
1010 | 0 | } |
1011 | 0 | zend_call_method_with_0_params(Z_OBJ(object->iterators[level].zobject), object->iterators[level].ce, NULL, "hasnext", &has_next); |
1012 | 0 | if (Z_TYPE(has_next) != IS_UNDEF) { |
1013 | 0 | if (Z_TYPE(has_next) == IS_TRUE) { |
1014 | 0 | smart_str_append(&str, object->prefix[3]); |
1015 | 0 | } else { |
1016 | 0 | smart_str_append(&str, object->prefix[4]); |
1017 | 0 | } |
1018 | 0 | zval_ptr_dtor(&has_next); |
1019 | 0 | } |
1020 | |
|
1021 | 0 | smart_str_append(&str, object->prefix[5]); |
1022 | 0 | smart_str_0(&str); |
1023 | |
|
1024 | 0 | return str.s; |
1025 | 0 | } |
1026 | | |
1027 | | static zend_string *spl_recursive_tree_iterator_get_entry(spl_recursive_it_object *object) |
1028 | 0 | { |
1029 | 0 | zend_object_iterator *iterator = object->iterators[object->level].iterator; |
1030 | 0 | zval *data = iterator->funcs->get_current_data(iterator); |
1031 | 0 | if (!data) { |
1032 | 0 | return NULL; |
1033 | 0 | } |
1034 | | |
1035 | 0 | ZVAL_DEREF(data); |
1036 | 0 | if (Z_TYPE_P(data) == IS_ARRAY) { |
1037 | | /* TODO: Remove this special case? */ |
1038 | 0 | return ZSTR_KNOWN(ZEND_STR_ARRAY_CAPITALIZED); |
1039 | 0 | } |
1040 | 0 | return zval_get_string(data); |
1041 | 0 | } |
1042 | | |
1043 | | static zend_string *spl_recursive_tree_iterator_get_postfix(spl_recursive_it_object *object) |
1044 | 0 | { |
1045 | 0 | return zend_string_copy(object->postfix[0]); |
1046 | 0 | } |
1047 | | |
1048 | | /* {{{ RecursiveIteratorIterator to generate ASCII graphic trees for the entries in a RecursiveIterator */ |
1049 | | PHP_METHOD(RecursiveTreeIterator, __construct) |
1050 | 5 | { |
1051 | 5 | spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveTreeIterator, zend_ce_iterator, RIT_RecursiveTreeIterator); |
1052 | 5 | } /* }}} */ |
1053 | | |
1054 | | /* {{{ Sets prefix parts as used in getPrefix() */ |
1055 | | PHP_METHOD(RecursiveTreeIterator, setPrefixPart) |
1056 | 0 | { |
1057 | 0 | zend_long part; |
1058 | 0 | zend_string *prefix; |
1059 | 0 | spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS); |
1060 | |
|
1061 | 0 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "lS", &part, &prefix) == FAILURE) { |
1062 | 0 | RETURN_THROWS(); |
1063 | 0 | } |
1064 | | |
1065 | 0 | if (0 > part || part > 5) { |
1066 | 0 | zend_argument_value_error(1, "must be a RecursiveTreeIterator::PREFIX_* constant"); |
1067 | 0 | RETURN_THROWS(); |
1068 | 0 | } |
1069 | | |
1070 | 0 | zend_string_release(object->prefix[part]); |
1071 | 0 | object->prefix[part] = zend_string_copy(prefix); |
1072 | 0 | } /* }}} */ |
1073 | | |
1074 | | /* {{{ Returns the string to place in front of current element */ |
1075 | | PHP_METHOD(RecursiveTreeIterator, getPrefix) |
1076 | 0 | { |
1077 | 0 | spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS); |
1078 | |
|
1079 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
1080 | | |
1081 | 0 | if(!object->iterators) { |
1082 | 0 | zend_throw_error(NULL, "The object is in an invalid state as the parent constructor was not called"); |
1083 | 0 | RETURN_THROWS(); |
1084 | 0 | } |
1085 | | |
1086 | 0 | RETURN_STR(spl_recursive_tree_iterator_get_prefix(object)); |
1087 | 0 | } /* }}} */ |
1088 | | |
1089 | | /* {{{ Sets postfix as used in getPostfix() */ |
1090 | | PHP_METHOD(RecursiveTreeIterator, setPostfix) |
1091 | 0 | { |
1092 | 0 | spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS); |
1093 | 0 | zend_string *postfix; |
1094 | |
|
1095 | 0 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &postfix) == FAILURE) { |
1096 | 0 | RETURN_THROWS(); |
1097 | 0 | } |
1098 | | |
1099 | 0 | zend_string_release(object->postfix[0]); |
1100 | 0 | object->postfix[0] = zend_string_copy(postfix); |
1101 | 0 | } /* }}} */ |
1102 | | |
1103 | | /* {{{ Returns the string presentation built for current element */ |
1104 | | PHP_METHOD(RecursiveTreeIterator, getEntry) |
1105 | 0 | { |
1106 | 0 | spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS); |
1107 | |
|
1108 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
1109 | | |
1110 | 0 | if(!object->iterators) { |
1111 | 0 | zend_throw_error(NULL, "The object is in an invalid state as the parent constructor was not called"); |
1112 | 0 | RETURN_THROWS(); |
1113 | 0 | } |
1114 | | |
1115 | 0 | zend_string *entry = spl_recursive_tree_iterator_get_entry(object); |
1116 | 0 | if (!entry) { |
1117 | | // TODO: Can this happen? It's not in the stubs. |
1118 | 0 | RETURN_NULL(); |
1119 | 0 | } |
1120 | 0 | RETURN_STR(entry); |
1121 | 0 | } /* }}} */ |
1122 | | |
1123 | | /* {{{ Returns the string to place after the current element */ |
1124 | | PHP_METHOD(RecursiveTreeIterator, getPostfix) |
1125 | 0 | { |
1126 | 0 | spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS); |
1127 | |
|
1128 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
1129 | | |
1130 | 0 | if(!object->iterators) { |
1131 | 0 | zend_throw_error(NULL, "The object is in an invalid state as the parent constructor was not called"); |
1132 | 0 | RETURN_THROWS(); |
1133 | 0 | } |
1134 | | |
1135 | 0 | RETURN_STR(spl_recursive_tree_iterator_get_postfix(object)); |
1136 | 0 | } /* }}} */ |
1137 | | |
1138 | | /* {{{ Returns the current element prefixed and postfixed */ |
1139 | | PHP_METHOD(RecursiveTreeIterator, current) |
1140 | 0 | { |
1141 | 0 | spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS); |
1142 | |
|
1143 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
1144 | | |
1145 | 0 | if(!object->iterators) { |
1146 | 0 | zend_throw_error(NULL, "The object is in an invalid state as the parent constructor was not called"); |
1147 | 0 | RETURN_THROWS(); |
1148 | 0 | } |
1149 | | |
1150 | 0 | if (object->flags & RTIT_BYPASS_CURRENT) { |
1151 | 0 | zend_object_iterator *iterator; |
1152 | 0 | zval *data; |
1153 | |
|
1154 | 0 | SPL_FETCH_SUB_ITERATOR(iterator, object); |
1155 | 0 | data = iterator->funcs->get_current_data(iterator); |
1156 | 0 | if (data) { |
1157 | 0 | RETURN_COPY_DEREF(data); |
1158 | 0 | } else { |
1159 | 0 | RETURN_NULL(); |
1160 | 0 | } |
1161 | 0 | } |
1162 | | |
1163 | 0 | zend_string *entry = spl_recursive_tree_iterator_get_entry(object); |
1164 | 0 | if (!entry) { |
1165 | 0 | RETURN_NULL(); |
1166 | 0 | } |
1167 | | |
1168 | 0 | zend_string *prefix = spl_recursive_tree_iterator_get_prefix(object); |
1169 | 0 | zend_string *postfix = spl_recursive_tree_iterator_get_postfix(object); |
1170 | |
|
1171 | 0 | zend_string *result = zend_string_concat3( |
1172 | 0 | ZSTR_VAL(prefix), ZSTR_LEN(prefix), |
1173 | 0 | ZSTR_VAL(entry), ZSTR_LEN(entry), |
1174 | 0 | ZSTR_VAL(postfix), ZSTR_LEN(postfix)); |
1175 | |
|
1176 | 0 | zend_string_release(entry); |
1177 | 0 | zend_string_release(prefix); |
1178 | 0 | zend_string_release(postfix); |
1179 | |
|
1180 | 0 | RETURN_NEW_STR(result); |
1181 | 0 | } /* }}} */ |
1182 | | |
1183 | | /* {{{ Returns the current key prefixed and postfixed */ |
1184 | | PHP_METHOD(RecursiveTreeIterator, key) |
1185 | 0 | { |
1186 | 0 | spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(ZEND_THIS); |
1187 | 0 | zend_object_iterator *iterator; |
1188 | 0 | zval key; |
1189 | |
|
1190 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
1191 | | |
1192 | 0 | SPL_FETCH_SUB_ITERATOR(iterator, object); |
1193 | | |
1194 | 0 | if (iterator->funcs->get_current_key) { |
1195 | 0 | iterator->funcs->get_current_key(iterator, &key); |
1196 | 0 | } else { |
1197 | 0 | ZVAL_NULL(&key); |
1198 | 0 | } |
1199 | |
|
1200 | 0 | if (object->flags & RTIT_BYPASS_KEY) { |
1201 | 0 | RETURN_COPY_VALUE(&key); |
1202 | 0 | } |
1203 | | |
1204 | 0 | zend_string *key_str = zval_get_string(&key); |
1205 | 0 | zend_string *prefix = spl_recursive_tree_iterator_get_prefix(object); |
1206 | 0 | zend_string *postfix = spl_recursive_tree_iterator_get_postfix(object); |
1207 | |
|
1208 | 0 | zend_string *result = zend_string_concat3( |
1209 | 0 | ZSTR_VAL(prefix), ZSTR_LEN(prefix), |
1210 | 0 | ZSTR_VAL(key_str), ZSTR_LEN(key_str), |
1211 | 0 | ZSTR_VAL(postfix), ZSTR_LEN(postfix)); |
1212 | |
|
1213 | 0 | zend_string_release(key_str); |
1214 | 0 | zend_string_release(prefix); |
1215 | 0 | zend_string_release(postfix); |
1216 | 0 | zval_ptr_dtor(&key); |
1217 | |
|
1218 | 0 | RETURN_NEW_STR(result); |
1219 | 0 | } /* }}} */ |
1220 | | |
1221 | | static zend_function *spl_dual_it_get_method(zend_object **object, zend_string *method, const zval *key) |
1222 | 68 | { |
1223 | 68 | zend_function *function_handler; |
1224 | 68 | spl_dual_it_object *intern; |
1225 | | |
1226 | 68 | intern = spl_dual_it_from_obj(*object); |
1227 | | |
1228 | 68 | function_handler = zend_std_get_method(object, method, key); |
1229 | 68 | if (!function_handler && intern->inner.ce) { |
1230 | 39 | if ((function_handler = zend_hash_find_ptr(&intern->inner.ce->function_table, method)) == NULL) { |
1231 | 39 | if (Z_OBJ_HT(intern->inner.zobject)->get_method) { |
1232 | 39 | *object = Z_OBJ(intern->inner.zobject); |
1233 | 39 | function_handler = (*object)->handlers->get_method(object, method, key); |
1234 | 39 | } |
1235 | 39 | } else { |
1236 | 0 | *object = Z_OBJ(intern->inner.zobject); |
1237 | 0 | } |
1238 | 39 | } |
1239 | 68 | return function_handler; |
1240 | 68 | } |
1241 | | |
1242 | | #define SPL_CHECK_CTOR(intern, classname) \ |
1243 | 0 | if (intern->dit_type == DIT_Unknown) { \ |
1244 | 0 | /* TODO Normal Error? */ \ |
1245 | 0 | zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Classes derived from %s must call %s::__construct()", \ |
1246 | 0 | ZSTR_VAL((spl_ce_##classname)->name), ZSTR_VAL((spl_ce_##classname)->name)); \ |
1247 | 0 | RETURN_THROWS(); \ |
1248 | 0 | } |
1249 | | |
1250 | 0 | #define APPENDIT_CHECK_CTOR(intern) SPL_CHECK_CTOR(intern, AppendIterator) |
1251 | | |
1252 | | static inline zend_result spl_dual_it_fetch(spl_dual_it_object *intern, int check_more); |
1253 | | |
1254 | | static inline zend_result spl_cit_check_flags(zend_long flags) |
1255 | 0 | { |
1256 | 0 | zend_long cnt = 0; |
1257 | |
|
1258 | 0 | cnt += (flags & CIT_CALL_TOSTRING) ? 1 : 0; |
1259 | 0 | cnt += (flags & CIT_TOSTRING_USE_KEY) ? 1 : 0; |
1260 | 0 | cnt += (flags & CIT_TOSTRING_USE_CURRENT) ? 1 : 0; |
1261 | 0 | cnt += (flags & CIT_TOSTRING_USE_INNER) ? 1 : 0; |
1262 | |
|
1263 | 0 | return cnt <= 1 ? SUCCESS : FAILURE; |
1264 | 0 | } |
1265 | | |
1266 | | static spl_dual_it_object* spl_dual_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *ce_base, zend_class_entry *ce_inner, dual_it_type dit_type) |
1267 | 135 | { |
1268 | 135 | zval *zobject, retval; |
1269 | 135 | spl_dual_it_object *intern; |
1270 | 135 | zend_class_entry *ce = NULL; |
1271 | 135 | int inc_refcount = 1; |
1272 | 135 | zend_error_handling error_handling; |
1273 | | |
1274 | 135 | intern = Z_SPLDUAL_IT_P(ZEND_THIS); |
1275 | | |
1276 | 135 | if (intern->dit_type != DIT_Unknown) { |
1277 | 0 | zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s::getIterator() must be called exactly once per instance", ZSTR_VAL(ce_base->name)); |
1278 | 0 | return NULL; |
1279 | 0 | } |
1280 | | |
1281 | 135 | switch (dit_type) { |
1282 | 10 | case DIT_LimitIterator: { |
1283 | 10 | intern->u.limit.offset = 0; /* start at beginning */ |
1284 | 10 | intern->u.limit.count = -1; /* get all */ |
1285 | 10 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|ll", &zobject, ce_inner, &intern->u.limit.offset, &intern->u.limit.count) == FAILURE) { |
1286 | 10 | return NULL; |
1287 | 10 | } |
1288 | 0 | if (intern->u.limit.offset < 0) { |
1289 | 0 | zend_argument_value_error(2, "must be greater than or equal to 0"); |
1290 | 0 | return NULL; |
1291 | 0 | } |
1292 | 0 | if (intern->u.limit.count < -1) { |
1293 | 0 | zend_argument_value_error(3, "must be greater than or equal to -1"); |
1294 | 0 | return NULL; |
1295 | 0 | } |
1296 | 0 | break; |
1297 | 0 | } |
1298 | 5 | case DIT_CachingIterator: |
1299 | 10 | case DIT_RecursiveCachingIterator: { |
1300 | 10 | zend_long flags = CIT_CALL_TOSTRING; |
1301 | 10 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|l", &zobject, ce_inner, &flags) == FAILURE) { |
1302 | 10 | return NULL; |
1303 | 10 | } |
1304 | 0 | if (spl_cit_check_flags(flags) != SUCCESS) { |
1305 | 0 | zend_argument_value_error(2, "must contain only one of CachingIterator::CALL_TOSTRING, " |
1306 | 0 | "CachingIterator::TOSTRING_USE_KEY, CachingIterator::TOSTRING_USE_CURRENT, " |
1307 | 0 | "or CachingIterator::TOSTRING_USE_INNER"); |
1308 | 0 | return NULL; |
1309 | 0 | } |
1310 | 0 | intern->u.caching.flags |= flags & CIT_PUBLIC; |
1311 | 0 | array_init(&intern->u.caching.zcache); |
1312 | 0 | break; |
1313 | 0 | } |
1314 | 45 | case DIT_IteratorIterator: { |
1315 | 45 | zend_class_entry *ce_cast; |
1316 | 45 | zend_string *class_name = NULL; |
1317 | | |
1318 | 45 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|S!", &zobject, ce_inner, &class_name) == FAILURE) { |
1319 | 11 | return NULL; |
1320 | 11 | } |
1321 | 34 | ce = Z_OBJCE_P(zobject); |
1322 | 34 | if (!instanceof_function(ce, zend_ce_iterator)) { |
1323 | 0 | if (class_name) { |
1324 | 0 | if (!(ce_cast = zend_lookup_class(class_name)) |
1325 | 0 | || !instanceof_function(ce, ce_cast) |
1326 | 0 | || !ce_cast->get_iterator |
1327 | 0 | ) { |
1328 | 0 | zend_throw_exception(spl_ce_LogicException, "Class to downcast to not found or not base class or does not implement Traversable", 0); |
1329 | 0 | return NULL; |
1330 | 0 | } |
1331 | 0 | ce = ce_cast; |
1332 | 0 | } |
1333 | 0 | if (instanceof_function(ce, zend_ce_aggregate)) { |
1334 | 0 | if (spl_get_iterator_from_aggregate(&retval, ce, Z_OBJ_P(zobject)) == FAILURE) { |
1335 | 0 | return NULL; |
1336 | 0 | } |
1337 | 0 | zobject = &retval; |
1338 | 0 | ce = Z_OBJCE_P(zobject); |
1339 | 0 | inc_refcount = 0; |
1340 | 0 | } |
1341 | 0 | } |
1342 | 34 | break; |
1343 | 34 | } |
1344 | 34 | case DIT_AppendIterator: |
1345 | 5 | if (zend_parse_parameters_none() == FAILURE) { |
1346 | 0 | return NULL; |
1347 | 0 | } |
1348 | 5 | intern->dit_type = DIT_AppendIterator; |
1349 | 5 | object_init_ex(&intern->u.append.zarrayit, spl_ce_ArrayIterator); |
1350 | 5 | zend_call_method_with_0_params(Z_OBJ(intern->u.append.zarrayit), spl_ce_ArrayIterator, &spl_ce_ArrayIterator->constructor, "__construct", NULL); |
1351 | 5 | intern->u.append.iterator = spl_ce_ArrayIterator->get_iterator(spl_ce_ArrayIterator, &intern->u.append.zarrayit, 0); |
1352 | 5 | return intern; |
1353 | 5 | case DIT_RegexIterator: |
1354 | 10 | case DIT_RecursiveRegexIterator: { |
1355 | 10 | zend_string *regex; |
1356 | 10 | zend_long mode = REGIT_MODE_MATCH; |
1357 | | |
1358 | 10 | intern->u.regex.flags = 0; |
1359 | 10 | intern->u.regex.preg_flags = 0; |
1360 | 10 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "OS|lll", &zobject, ce_inner, ®ex, &mode, &intern->u.regex.flags, &intern->u.regex.preg_flags) == FAILURE) { |
1361 | 10 | return NULL; |
1362 | 10 | } |
1363 | 0 | if (mode < 0 || mode >= REGIT_MODE_MAX) { |
1364 | 0 | zend_argument_value_error(3, "must be RegexIterator::MATCH, RegexIterator::GET_MATCH, " |
1365 | 0 | "RegexIterator::ALL_MATCHES, RegexIterator::SPLIT, or RegexIterator::REPLACE"); |
1366 | 0 | return NULL; |
1367 | 0 | } |
1368 | | |
1369 | | /* pcre_get_compiled_regex_cache() might emit E_WARNINGs that we want to promote to exception */ |
1370 | 0 | zend_replace_error_handling(EH_THROW, spl_ce_InvalidArgumentException, &error_handling); |
1371 | 0 | intern->u.regex.pce = pcre_get_compiled_regex_cache(regex); |
1372 | 0 | zend_restore_error_handling(&error_handling); |
1373 | |
|
1374 | 0 | if (intern->u.regex.pce == NULL) { |
1375 | | /* pcre_get_compiled_regex_cache has already sent error */ |
1376 | 0 | return NULL; |
1377 | 0 | } |
1378 | 0 | intern->u.regex.mode = mode; |
1379 | 0 | intern->u.regex.regex = zend_string_copy(regex); |
1380 | 0 | php_pcre_pce_incref(intern->u.regex.pce); |
1381 | 0 | break; |
1382 | 0 | } |
1383 | 40 | case DIT_CallbackFilterIterator: |
1384 | 45 | case DIT_RecursiveCallbackFilterIterator: { |
1385 | 45 | zend_fcall_info fci; |
1386 | 45 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "OF", &zobject, ce_inner, &fci, &intern->u.callback_filter) == FAILURE) { |
1387 | 10 | return NULL; |
1388 | 10 | } |
1389 | 35 | zend_fcc_addref(&intern->u.callback_filter); |
1390 | 35 | break; |
1391 | 45 | } |
1392 | 10 | default: |
1393 | 10 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &zobject, ce_inner) == FAILURE) { |
1394 | 10 | return NULL; |
1395 | 10 | } |
1396 | 0 | break; |
1397 | 135 | } |
1398 | | |
1399 | 69 | intern->dit_type = dit_type; |
1400 | 69 | if (inc_refcount) { |
1401 | 69 | Z_ADDREF_P(zobject); |
1402 | 69 | } |
1403 | 69 | ZVAL_OBJ(&intern->inner.zobject, Z_OBJ_P(zobject)); |
1404 | | |
1405 | 69 | intern->inner.ce = dit_type == DIT_IteratorIterator ? ce : Z_OBJCE_P(zobject); |
1406 | 69 | intern->inner.object = Z_OBJ_P(zobject); |
1407 | 69 | intern->inner.iterator = intern->inner.ce->get_iterator(intern->inner.ce, zobject, 0); |
1408 | | |
1409 | 69 | return intern; |
1410 | 135 | } |
1411 | | |
1412 | | /* {{{ Create an Iterator from another iterator */ |
1413 | | PHP_METHOD(FilterIterator, __construct) |
1414 | 0 | { |
1415 | 0 | spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_FilterIterator, zend_ce_iterator, DIT_FilterIterator); |
1416 | 0 | } /* }}} */ |
1417 | | |
1418 | | /* {{{ Create an Iterator from another iterator */ |
1419 | | PHP_METHOD(CallbackFilterIterator, __construct) |
1420 | 40 | { |
1421 | 40 | spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_CallbackFilterIterator, zend_ce_iterator, DIT_CallbackFilterIterator); |
1422 | 40 | } /* }}} */ |
1423 | | |
1424 | | /* {{{ Get the inner iterator */ |
1425 | | PHP_METHOD(IteratorIterator, getInnerIterator) |
1426 | 8 | { |
1427 | 8 | spl_dual_it_object *intern; |
1428 | | |
1429 | 8 | ZEND_PARSE_PARAMETERS_NONE(); |
1430 | | |
1431 | 8 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
1432 | | |
1433 | 8 | if (!Z_ISUNDEF(intern->inner.zobject)) { |
1434 | 8 | zval *value = &intern->inner.zobject; |
1435 | 8 | RETURN_COPY_DEREF(value); |
1436 | 8 | } else { |
1437 | 0 | RETURN_NULL(); |
1438 | 0 | } |
1439 | 8 | } /* }}} */ |
1440 | | |
1441 | | static inline void spl_dual_it_free(spl_dual_it_object *intern) |
1442 | 579 | { |
1443 | 579 | if (intern->inner.iterator && intern->inner.iterator->funcs->invalidate_current) { |
1444 | 70 | intern->inner.iterator->funcs->invalidate_current(intern->inner.iterator); |
1445 | 70 | } |
1446 | 579 | if (Z_TYPE(intern->current.data) != IS_UNDEF) { |
1447 | 100 | zval_ptr_dtor(&intern->current.data); |
1448 | 100 | ZVAL_UNDEF(&intern->current.data); |
1449 | 100 | } |
1450 | 579 | if (Z_TYPE(intern->current.key) != IS_UNDEF) { |
1451 | 100 | zval_ptr_dtor(&intern->current.key); |
1452 | 100 | ZVAL_UNDEF(&intern->current.key); |
1453 | 100 | } |
1454 | 579 | if (intern->dit_type == DIT_CachingIterator || intern->dit_type == DIT_RecursiveCachingIterator) { |
1455 | 0 | if (intern->u.caching.zstr) { |
1456 | 0 | zend_string_release(intern->u.caching.zstr); |
1457 | 0 | intern->u.caching.zstr = NULL; |
1458 | 0 | } |
1459 | 0 | if (Z_TYPE(intern->u.caching.zchildren) != IS_UNDEF) { |
1460 | 0 | zval_ptr_dtor(&intern->u.caching.zchildren); |
1461 | 0 | ZVAL_UNDEF(&intern->u.caching.zchildren); |
1462 | 0 | } |
1463 | 0 | } |
1464 | 579 | } |
1465 | | |
1466 | | static inline void spl_dual_it_rewind(spl_dual_it_object *intern) |
1467 | 74 | { |
1468 | 74 | spl_dual_it_free(intern); |
1469 | 74 | intern->current.pos = 0; |
1470 | 74 | if (intern->inner.iterator && intern->inner.iterator->funcs->rewind) { |
1471 | 74 | intern->inner.iterator->funcs->rewind(intern->inner.iterator); |
1472 | 74 | } |
1473 | 74 | } |
1474 | | |
1475 | | static inline zend_result spl_dual_it_valid(spl_dual_it_object *intern) |
1476 | 138 | { |
1477 | 138 | if (!intern->inner.iterator) { |
1478 | 0 | return FAILURE; |
1479 | 0 | } |
1480 | | /* FAILURE / SUCCESS */ |
1481 | 138 | return intern->inner.iterator->funcs->valid(intern->inner.iterator); |
1482 | 138 | } |
1483 | | |
1484 | | static inline zend_result spl_dual_it_fetch(spl_dual_it_object *intern, int check_more) |
1485 | 138 | { |
1486 | 138 | zval *data; |
1487 | | |
1488 | 138 | spl_dual_it_free(intern); |
1489 | 138 | if (!check_more || spl_dual_it_valid(intern) == SUCCESS) { |
1490 | 100 | data = intern->inner.iterator->funcs->get_current_data(intern->inner.iterator); |
1491 | 100 | if (data) { |
1492 | 100 | ZVAL_COPY(&intern->current.data, data); |
1493 | 100 | } |
1494 | | |
1495 | 100 | if (intern->inner.iterator->funcs->get_current_key) { |
1496 | 100 | intern->inner.iterator->funcs->get_current_key(intern->inner.iterator, &intern->current.key); |
1497 | 100 | if (EG(exception)) { |
1498 | 0 | zval_ptr_dtor(&intern->current.key); |
1499 | 0 | ZVAL_UNDEF(&intern->current.key); |
1500 | 0 | } |
1501 | 100 | } else { |
1502 | 0 | ZVAL_LONG(&intern->current.key, intern->current.pos); |
1503 | 0 | } |
1504 | 100 | return EG(exception) ? FAILURE : SUCCESS; |
1505 | 100 | } |
1506 | 38 | return FAILURE; |
1507 | 138 | } |
1508 | | |
1509 | | static inline void spl_dual_it_next(spl_dual_it_object *intern, int do_free) |
1510 | 64 | { |
1511 | 64 | if (do_free) { |
1512 | 64 | spl_dual_it_free(intern); |
1513 | 64 | } else if (!intern->inner.iterator) { |
1514 | 0 | zend_throw_error(NULL, "The inner constructor wasn't initialized with an iterator instance"); |
1515 | 0 | return; |
1516 | 0 | } |
1517 | 64 | intern->inner.iterator->funcs->move_forward(intern->inner.iterator); |
1518 | 64 | intern->current.pos++; |
1519 | 64 | } |
1520 | | |
1521 | | /* {{{ Rewind the iterator */ |
1522 | | PHP_METHOD(IteratorIterator, rewind) |
1523 | 23 | { |
1524 | 23 | spl_dual_it_object *intern; |
1525 | | |
1526 | 23 | ZEND_PARSE_PARAMETERS_NONE(); |
1527 | | |
1528 | 23 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
1529 | | |
1530 | 23 | spl_dual_it_rewind(intern); |
1531 | 23 | spl_dual_it_fetch(intern, 1); |
1532 | 23 | } /* }}} */ |
1533 | | |
1534 | | /* {{{ Check whether the current element is valid */ |
1535 | | PHP_METHOD(IteratorIterator, valid) |
1536 | 107 | { |
1537 | 107 | spl_dual_it_object *intern; |
1538 | | |
1539 | 107 | ZEND_PARSE_PARAMETERS_NONE(); |
1540 | | |
1541 | 107 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
1542 | | |
1543 | 107 | RETURN_BOOL(Z_TYPE(intern->current.data) != IS_UNDEF); |
1544 | 107 | } /* }}} */ |
1545 | | |
1546 | | /* {{{ Get the current key */ |
1547 | | PHP_METHOD(IteratorIterator, key) |
1548 | 35 | { |
1549 | 35 | spl_dual_it_object *intern; |
1550 | | |
1551 | 35 | ZEND_PARSE_PARAMETERS_NONE(); |
1552 | | |
1553 | 35 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
1554 | | |
1555 | 35 | if (Z_TYPE(intern->current.key) != IS_UNDEF) { |
1556 | 35 | RETURN_COPY_DEREF(&intern->current.key); |
1557 | 35 | } else { |
1558 | 0 | RETURN_NULL(); |
1559 | 0 | } |
1560 | 35 | } /* }}} */ |
1561 | | |
1562 | | /* {{{ Get the current element value */ |
1563 | | PHP_METHOD(IteratorIterator, current) |
1564 | 79 | { |
1565 | 79 | spl_dual_it_object *intern; |
1566 | | |
1567 | 79 | ZEND_PARSE_PARAMETERS_NONE(); |
1568 | | |
1569 | 79 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
1570 | | |
1571 | 79 | if (Z_TYPE(intern->current.data) != IS_UNDEF) { |
1572 | 79 | RETURN_COPY_DEREF(&intern->current.data); |
1573 | 79 | } else { |
1574 | 0 | RETURN_NULL(); |
1575 | 0 | } |
1576 | 79 | } /* }}} */ |
1577 | | |
1578 | | /* {{{ Move the iterator forward */ |
1579 | | PHP_METHOD(IteratorIterator, next) |
1580 | 44 | { |
1581 | 44 | spl_dual_it_object *intern; |
1582 | | |
1583 | 44 | ZEND_PARSE_PARAMETERS_NONE(); |
1584 | | |
1585 | 44 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
1586 | | |
1587 | 44 | spl_dual_it_next(intern, 1); |
1588 | 44 | spl_dual_it_fetch(intern, 1); |
1589 | 44 | } /* }}} */ |
1590 | | |
1591 | | static inline void spl_filter_it_fetch(zval *zthis, spl_dual_it_object *intern) |
1592 | 71 | { |
1593 | 71 | zval retval; |
1594 | | |
1595 | 71 | while (spl_dual_it_fetch(intern, 1) == SUCCESS) { |
1596 | 46 | zend_call_method_with_0_params(Z_OBJ_P(zthis), intern->std.ce, NULL, "accept", &retval); |
1597 | 46 | if (Z_TYPE(retval) != IS_UNDEF) { |
1598 | 46 | if (zend_is_true(&retval)) { |
1599 | 46 | zval_ptr_dtor(&retval); |
1600 | 46 | return; |
1601 | 46 | } |
1602 | 0 | zval_ptr_dtor(&retval); |
1603 | 0 | } |
1604 | 0 | if (EG(exception)) { |
1605 | 0 | return; |
1606 | 0 | } |
1607 | 0 | intern->inner.iterator->funcs->move_forward(intern->inner.iterator); |
1608 | 0 | } |
1609 | 25 | spl_dual_it_free(intern); |
1610 | 25 | } |
1611 | | |
1612 | | static inline void spl_filter_it_rewind(zval *zthis, spl_dual_it_object *intern) |
1613 | 51 | { |
1614 | 51 | spl_dual_it_rewind(intern); |
1615 | 51 | spl_filter_it_fetch(zthis, intern); |
1616 | 51 | } |
1617 | | |
1618 | | static inline void spl_filter_it_next(zval *zthis, spl_dual_it_object *intern) |
1619 | 20 | { |
1620 | 20 | spl_dual_it_next(intern, 1); |
1621 | 20 | spl_filter_it_fetch(zthis, intern); |
1622 | 20 | } |
1623 | | |
1624 | | /* {{{ Rewind the iterator */ |
1625 | | PHP_METHOD(FilterIterator, rewind) |
1626 | 51 | { |
1627 | 51 | spl_dual_it_object *intern; |
1628 | | |
1629 | 51 | ZEND_PARSE_PARAMETERS_NONE(); |
1630 | | |
1631 | 51 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
1632 | 51 | spl_filter_it_rewind(ZEND_THIS, intern); |
1633 | 51 | } /* }}} */ |
1634 | | |
1635 | | /* {{{ Move the iterator forward */ |
1636 | | PHP_METHOD(FilterIterator, next) |
1637 | 20 | { |
1638 | 20 | spl_dual_it_object *intern; |
1639 | | |
1640 | 20 | ZEND_PARSE_PARAMETERS_NONE(); |
1641 | | |
1642 | 20 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
1643 | 20 | spl_filter_it_next(ZEND_THIS, intern); |
1644 | 20 | } /* }}} */ |
1645 | | |
1646 | | /* {{{ Create a RecursiveCallbackFilterIterator from a RecursiveIterator */ |
1647 | | PHP_METHOD(RecursiveCallbackFilterIterator, __construct) |
1648 | 5 | { |
1649 | 5 | spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveCallbackFilterIterator, spl_ce_RecursiveIterator, DIT_RecursiveCallbackFilterIterator); |
1650 | 5 | } /* }}} */ |
1651 | | |
1652 | | |
1653 | | /* {{{ Create a RecursiveFilterIterator from a RecursiveIterator */ |
1654 | | PHP_METHOD(RecursiveFilterIterator, __construct) |
1655 | 0 | { |
1656 | 0 | spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveFilterIterator, spl_ce_RecursiveIterator, DIT_RecursiveFilterIterator); |
1657 | 0 | } /* }}} */ |
1658 | | |
1659 | | /* {{{ Check whether the inner iterator's current element has children */ |
1660 | | PHP_METHOD(RecursiveFilterIterator, hasChildren) |
1661 | 0 | { |
1662 | 0 | spl_dual_it_object *intern; |
1663 | |
|
1664 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
1665 | | |
1666 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
1667 | | |
1668 | 0 | zend_call_method_with_0_params(Z_OBJ(intern->inner.zobject), intern->inner.ce, NULL, "haschildren", return_value); |
1669 | 0 | } /* }}} */ |
1670 | | |
1671 | | /* {{{ Return the inner iterator's children contained in a RecursiveFilterIterator */ |
1672 | | PHP_METHOD(RecursiveFilterIterator, getChildren) |
1673 | 0 | { |
1674 | 0 | spl_dual_it_object *intern; |
1675 | |
|
1676 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
1677 | | |
1678 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
1679 | | |
1680 | 0 | zval childrens; |
1681 | 0 | zend_call_method_with_0_params(Z_OBJ(intern->inner.zobject), intern->inner.ce, NULL, "getchildren", &childrens); |
1682 | 0 | if (Z_TYPE(childrens) == IS_UNDEF) { |
1683 | 0 | RETURN_THROWS(); |
1684 | 0 | } |
1685 | | |
1686 | 0 | zend_result is_initialized = object_init_with_constructor(return_value, Z_OBJCE_P(ZEND_THIS), 1, &childrens, NULL); |
1687 | 0 | zval_ptr_dtor(&childrens); |
1688 | 0 | if (is_initialized == FAILURE) { |
1689 | 0 | RETURN_THROWS(); |
1690 | 0 | } |
1691 | 0 | } /* }}} */ |
1692 | | |
1693 | | /* {{{ Return the inner iterator's children contained in a RecursiveCallbackFilterIterator */ |
1694 | | PHP_METHOD(RecursiveCallbackFilterIterator, getChildren) |
1695 | 0 | { |
1696 | 0 | spl_dual_it_object *intern; |
1697 | |
|
1698 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
1699 | | |
1700 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
1701 | | |
1702 | 0 | zval params[2]; |
1703 | 0 | zend_call_method_with_0_params(Z_OBJ(intern->inner.zobject), intern->inner.ce, NULL, "getchildren", ¶ms[0]); |
1704 | 0 | if (Z_TYPE(params[0]) == IS_UNDEF) { |
1705 | 0 | RETURN_THROWS(); |
1706 | 0 | } |
1707 | | |
1708 | | /* Get callable to pass to the constructor */ |
1709 | 0 | zend_get_callable_zval_from_fcc(&intern->u.callback_filter, ¶ms[1]); |
1710 | |
|
1711 | 0 | zend_result is_initialized = object_init_with_constructor(return_value, Z_OBJCE_P(ZEND_THIS), 2, params, NULL); |
1712 | 0 | zval_ptr_dtor(¶ms[0]); |
1713 | 0 | zval_ptr_dtor(¶ms[1]); |
1714 | 0 | if (is_initialized == FAILURE) { |
1715 | 0 | RETURN_THROWS(); |
1716 | 0 | } |
1717 | 0 | } /* }}} */ |
1718 | | /* {{{ Create a ParentIterator from a RecursiveIterator */ |
1719 | | PHP_METHOD(ParentIterator, __construct) |
1720 | 5 | { |
1721 | 5 | spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_ParentIterator, spl_ce_RecursiveIterator, DIT_ParentIterator); |
1722 | 5 | } /* }}} */ |
1723 | | |
1724 | | /* {{{ Create an RegexIterator from another iterator and a regular expression */ |
1725 | | PHP_METHOD(RegexIterator, __construct) |
1726 | 5 | { |
1727 | 5 | spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RegexIterator, zend_ce_iterator, DIT_RegexIterator); |
1728 | 5 | } /* }}} */ |
1729 | | |
1730 | | /* {{{ Calls the callback with the current value, the current key and the inner iterator as arguments */ |
1731 | | PHP_METHOD(CallbackFilterIterator, accept) |
1732 | 46 | { |
1733 | 46 | spl_dual_it_object *intern; |
1734 | | |
1735 | 46 | ZEND_PARSE_PARAMETERS_NONE(); |
1736 | | |
1737 | 46 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
1738 | | |
1739 | 46 | if (Z_TYPE(intern->current.data) == IS_UNDEF || Z_TYPE(intern->current.key) == IS_UNDEF) { |
1740 | 0 | RETURN_FALSE; |
1741 | 0 | } |
1742 | | |
1743 | 46 | zval params[3]; |
1744 | 46 | ZVAL_COPY_VALUE(¶ms[0], &intern->current.data); |
1745 | 46 | ZVAL_COPY_VALUE(¶ms[1], &intern->current.key); |
1746 | 46 | ZVAL_COPY_VALUE(¶ms[2], &intern->inner.zobject); |
1747 | | |
1748 | 46 | zend_fcall_info_cache *fcc = &intern->u.callback_filter; |
1749 | | |
1750 | 46 | zend_call_known_fcc(fcc, return_value, 3, params, NULL); |
1751 | 46 | if (Z_ISUNDEF_P(return_value)) { |
1752 | 0 | RETURN_FALSE; |
1753 | 46 | } else if (Z_ISREF_P(return_value)) { |
1754 | 11 | zend_unwrap_reference(return_value); |
1755 | 11 | } |
1756 | 46 | } |
1757 | | /* }}} */ |
1758 | | |
1759 | | /* {{{ Match (string)current() against regular expression */ |
1760 | | PHP_METHOD(RegexIterator, accept) |
1761 | 0 | { |
1762 | 0 | spl_dual_it_object *intern; |
1763 | 0 | zend_string *result, *subject; |
1764 | 0 | size_t count = 0; |
1765 | 0 | zval zcount, rv; |
1766 | 0 | pcre2_match_data *match_data; |
1767 | 0 | pcre2_code *re; |
1768 | 0 | int rc; |
1769 | |
|
1770 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
1771 | | |
1772 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
1773 | | |
1774 | 0 | if (Z_TYPE(intern->current.data) == IS_UNDEF) { |
1775 | 0 | RETURN_FALSE; |
1776 | 0 | } |
1777 | | |
1778 | 0 | if (intern->u.regex.flags & REGIT_USE_KEY) { |
1779 | 0 | subject = zval_get_string(&intern->current.key); |
1780 | 0 | } else { |
1781 | 0 | if (Z_TYPE(intern->current.data) == IS_ARRAY) { |
1782 | 0 | RETURN_FALSE; |
1783 | 0 | } |
1784 | 0 | subject = zval_get_string(&intern->current.data); |
1785 | 0 | } |
1786 | | |
1787 | | /* Exception during string conversion. */ |
1788 | 0 | if (EG(exception)) { |
1789 | 0 | RETURN_THROWS(); |
1790 | 0 | } |
1791 | | |
1792 | 0 | switch (intern->u.regex.mode) |
1793 | 0 | { |
1794 | 0 | case REGIT_MODE_MAX: /* won't happen but makes compiler happy */ |
1795 | 0 | case REGIT_MODE_MATCH: |
1796 | 0 | re = php_pcre_pce_re(intern->u.regex.pce); |
1797 | 0 | match_data = php_pcre_create_match_data(0, re); |
1798 | 0 | if (!match_data) { |
1799 | 0 | RETURN_FALSE; |
1800 | 0 | } |
1801 | 0 | rc = pcre2_match(re, (PCRE2_SPTR)ZSTR_VAL(subject), ZSTR_LEN(subject), 0, 0, match_data, php_pcre_mctx()); |
1802 | 0 | RETVAL_BOOL(rc >= 0); |
1803 | 0 | php_pcre_free_match_data(match_data); |
1804 | 0 | break; |
1805 | | |
1806 | 0 | case REGIT_MODE_ALL_MATCHES: |
1807 | 0 | case REGIT_MODE_GET_MATCH: |
1808 | 0 | zval_ptr_dtor(&intern->current.data); |
1809 | 0 | ZVAL_UNDEF(&intern->current.data); |
1810 | 0 | php_pcre_match_impl(intern->u.regex.pce, subject, &zcount, |
1811 | 0 | &intern->current.data, intern->u.regex.mode == REGIT_MODE_ALL_MATCHES, intern->u.regex.preg_flags, 0); |
1812 | 0 | RETVAL_BOOL(Z_LVAL(zcount) > 0); |
1813 | 0 | break; |
1814 | | |
1815 | 0 | case REGIT_MODE_SPLIT: |
1816 | 0 | zval_ptr_dtor(&intern->current.data); |
1817 | 0 | ZVAL_UNDEF(&intern->current.data); |
1818 | 0 | php_pcre_split_impl(intern->u.regex.pce, subject, &intern->current.data, -1, intern->u.regex.preg_flags); |
1819 | 0 | count = zend_hash_num_elements(Z_ARRVAL(intern->current.data)); |
1820 | 0 | RETVAL_BOOL(count > 1); |
1821 | 0 | break; |
1822 | | |
1823 | 0 | case REGIT_MODE_REPLACE: { |
1824 | 0 | zval *replacement = zend_read_property(intern->std.ce, Z_OBJ_P(ZEND_THIS), "replacement", sizeof("replacement")-1, 1, &rv); |
1825 | 0 | zend_string *replacement_str = zval_try_get_string(replacement); |
1826 | | |
1827 | | /* Property type is ?string, so this should always succeed. */ |
1828 | 0 | ZEND_ASSERT(replacement_str != NULL); |
1829 | | |
1830 | 0 | result = php_pcre_replace_impl(intern->u.regex.pce, subject, ZSTR_VAL(subject), ZSTR_LEN(subject), replacement_str, -1, &count); |
1831 | |
|
1832 | 0 | if (UNEXPECTED(!result)) { |
1833 | 0 | zend_string_release(replacement_str); |
1834 | 0 | zend_string_release_ex(subject, false); |
1835 | 0 | RETURN_FALSE; |
1836 | 0 | } |
1837 | | |
1838 | 0 | if (intern->u.regex.flags & REGIT_USE_KEY) { |
1839 | 0 | zval_ptr_dtor(&intern->current.key); |
1840 | 0 | ZVAL_STR(&intern->current.key, result); |
1841 | 0 | } else { |
1842 | 0 | zval_ptr_dtor(&intern->current.data); |
1843 | 0 | ZVAL_STR(&intern->current.data, result); |
1844 | 0 | } |
1845 | |
|
1846 | 0 | zend_string_release(replacement_str); |
1847 | 0 | RETVAL_BOOL(count > 0); |
1848 | 0 | } |
1849 | 0 | } |
1850 | | |
1851 | 0 | if (intern->u.regex.flags & REGIT_INVERTED) { |
1852 | 0 | RETVAL_BOOL(Z_TYPE_P(return_value) != IS_TRUE); |
1853 | 0 | } |
1854 | 0 | zend_string_release_ex(subject, false); |
1855 | 0 | } /* }}} */ |
1856 | | |
1857 | | /* {{{ Returns current regular expression */ |
1858 | | PHP_METHOD(RegexIterator, getRegex) |
1859 | 0 | { |
1860 | 0 | spl_dual_it_object *intern; |
1861 | |
|
1862 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
1863 | | |
1864 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
1865 | | |
1866 | 0 | RETURN_STR_COPY(intern->u.regex.regex); |
1867 | 0 | } /* }}} */ |
1868 | | |
1869 | | /* {{{ Returns current operation mode */ |
1870 | | PHP_METHOD(RegexIterator, getMode) |
1871 | 0 | { |
1872 | 0 | spl_dual_it_object *intern; |
1873 | |
|
1874 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
1875 | | |
1876 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
1877 | | |
1878 | 0 | RETURN_LONG(intern->u.regex.mode); |
1879 | 0 | } /* }}} */ |
1880 | | |
1881 | | /* {{{ Set new operation mode */ |
1882 | | PHP_METHOD(RegexIterator, setMode) |
1883 | 0 | { |
1884 | 0 | spl_dual_it_object *intern; |
1885 | 0 | zend_long mode; |
1886 | |
|
1887 | 0 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &mode) == FAILURE) { |
1888 | 0 | RETURN_THROWS(); |
1889 | 0 | } |
1890 | | |
1891 | 0 | if (mode < 0 || mode >= REGIT_MODE_MAX) { |
1892 | 0 | zend_argument_value_error(1, "must be RegexIterator::MATCH, RegexIterator::GET_MATCH, " |
1893 | 0 | "RegexIterator::ALL_MATCHES, RegexIterator::SPLIT, or RegexIterator::REPLACE"); |
1894 | 0 | RETURN_THROWS(); |
1895 | 0 | } |
1896 | | |
1897 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
1898 | | |
1899 | 0 | intern->u.regex.mode = mode; |
1900 | 0 | } /* }}} */ |
1901 | | |
1902 | | /* {{{ Returns current operation flags */ |
1903 | | PHP_METHOD(RegexIterator, getFlags) |
1904 | 0 | { |
1905 | 0 | spl_dual_it_object *intern; |
1906 | |
|
1907 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
1908 | | |
1909 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
1910 | | |
1911 | 0 | RETURN_LONG(intern->u.regex.flags); |
1912 | 0 | } /* }}} */ |
1913 | | |
1914 | | /* {{{ Set operation flags */ |
1915 | | PHP_METHOD(RegexIterator, setFlags) |
1916 | 0 | { |
1917 | 0 | spl_dual_it_object *intern; |
1918 | 0 | zend_long flags; |
1919 | |
|
1920 | 0 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &flags) == FAILURE) { |
1921 | 0 | RETURN_THROWS(); |
1922 | 0 | } |
1923 | | |
1924 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
1925 | | |
1926 | 0 | intern->u.regex.flags = flags; |
1927 | 0 | } /* }}} */ |
1928 | | |
1929 | | /* {{{ Returns current PREG flags (if in use or NULL) */ |
1930 | | PHP_METHOD(RegexIterator, getPregFlags) |
1931 | 0 | { |
1932 | 0 | spl_dual_it_object *intern; |
1933 | |
|
1934 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
1935 | | |
1936 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
1937 | | |
1938 | 0 | RETURN_LONG(intern->u.regex.preg_flags); |
1939 | 0 | } /* }}} */ |
1940 | | |
1941 | | /* {{{ Set PREG flags */ |
1942 | | PHP_METHOD(RegexIterator, setPregFlags) |
1943 | 0 | { |
1944 | 0 | spl_dual_it_object *intern; |
1945 | 0 | zend_long preg_flags; |
1946 | |
|
1947 | 0 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &preg_flags) == FAILURE) { |
1948 | 0 | RETURN_THROWS(); |
1949 | 0 | } |
1950 | | |
1951 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
1952 | | |
1953 | 0 | intern->u.regex.preg_flags = preg_flags; |
1954 | 0 | } /* }}} */ |
1955 | | |
1956 | | /* {{{ Create an RecursiveRegexIterator from another recursive iterator and a regular expression */ |
1957 | | PHP_METHOD(RecursiveRegexIterator, __construct) |
1958 | 5 | { |
1959 | 5 | spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveRegexIterator, spl_ce_RecursiveIterator, DIT_RecursiveRegexIterator); |
1960 | 5 | } /* }}} */ |
1961 | | |
1962 | | /* {{{ Return the inner iterator's children contained in a RecursiveRegexIterator */ |
1963 | | PHP_METHOD(RecursiveRegexIterator, getChildren) |
1964 | 0 | { |
1965 | 0 | spl_dual_it_object *intern; |
1966 | 0 | zval retval; |
1967 | |
|
1968 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
1969 | | |
1970 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
1971 | | |
1972 | 0 | zend_call_method_with_0_params(Z_OBJ(intern->inner.zobject), intern->inner.ce, NULL, "getchildren", &retval); |
1973 | 0 | if (EG(exception)) { |
1974 | 0 | zval_ptr_dtor(&retval); |
1975 | 0 | RETURN_THROWS(); |
1976 | 0 | } |
1977 | | |
1978 | 0 | zval args[5]; |
1979 | 0 | ZVAL_COPY_VALUE(&args[0], &retval); |
1980 | 0 | ZVAL_STR_COPY(&args[1], intern->u.regex.regex); |
1981 | 0 | ZVAL_LONG(&args[2], intern->u.regex.mode); |
1982 | 0 | ZVAL_LONG(&args[3], intern->u.regex.flags); |
1983 | 0 | ZVAL_LONG(&args[4], intern->u.regex.preg_flags); |
1984 | |
|
1985 | 0 | zend_result is_initialized = object_init_with_constructor(return_value, Z_OBJCE_P(ZEND_THIS), 5, args, NULL); |
1986 | |
|
1987 | 0 | zval_ptr_dtor(&args[0]); |
1988 | 0 | zval_ptr_dtor_str(&args[1]); |
1989 | 0 | if (is_initialized == FAILURE) { |
1990 | 0 | RETURN_THROWS(); |
1991 | 0 | } |
1992 | 0 | } /* }}} */ |
1993 | | |
1994 | | PHP_METHOD(RecursiveRegexIterator, accept) |
1995 | 0 | { |
1996 | 0 | spl_dual_it_object *intern; |
1997 | |
|
1998 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
1999 | | |
2000 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
2001 | | |
2002 | 0 | if (Z_TYPE(intern->current.data) == IS_UNDEF) { |
2003 | 0 | RETURN_FALSE; |
2004 | 0 | } else if (Z_TYPE(intern->current.data) == IS_ARRAY) { |
2005 | 0 | RETURN_BOOL(zend_hash_num_elements(Z_ARRVAL(intern->current.data)) > 0); |
2006 | 0 | } |
2007 | | |
2008 | 0 | zend_call_method_with_0_params(Z_OBJ_P(ZEND_THIS), spl_ce_RegexIterator, NULL, "accept", return_value); |
2009 | 0 | } |
2010 | | |
2011 | | /* {{{ spl_dual_it_free_storage */ |
2012 | | static void spl_dual_it_free_storage(zend_object *_object) |
2013 | 278 | { |
2014 | 278 | spl_dual_it_object *object = spl_dual_it_from_obj(_object); |
2015 | | |
2016 | 278 | spl_dual_it_free(object); |
2017 | | |
2018 | 278 | if (object->inner.iterator) { |
2019 | 69 | zend_iterator_dtor(object->inner.iterator); |
2020 | 69 | } |
2021 | | |
2022 | 278 | if (!Z_ISUNDEF(object->inner.zobject)) { |
2023 | 69 | zval_ptr_dtor(&object->inner.zobject); |
2024 | 69 | } |
2025 | | |
2026 | 278 | if (object->dit_type == DIT_AppendIterator) { |
2027 | 5 | zend_iterator_dtor(object->u.append.iterator); |
2028 | 5 | if (Z_TYPE(object->u.append.zarrayit) != IS_UNDEF) { |
2029 | 5 | zval_ptr_dtor(&object->u.append.zarrayit); |
2030 | 5 | } |
2031 | 5 | } |
2032 | | |
2033 | 278 | if (object->dit_type == DIT_CachingIterator || object->dit_type == DIT_RecursiveCachingIterator) { |
2034 | 0 | zval_ptr_dtor(&object->u.caching.zcache); |
2035 | 0 | } |
2036 | | |
2037 | 278 | if (object->dit_type == DIT_RegexIterator || object->dit_type == DIT_RecursiveRegexIterator) { |
2038 | 0 | if (object->u.regex.pce) { |
2039 | 0 | php_pcre_pce_decref(object->u.regex.pce); |
2040 | 0 | } |
2041 | 0 | if (object->u.regex.regex) { |
2042 | 0 | zend_string_release_ex(object->u.regex.regex, 0); |
2043 | 0 | } |
2044 | 0 | } |
2045 | | |
2046 | 278 | if (object->dit_type == DIT_CallbackFilterIterator || object->dit_type == DIT_RecursiveCallbackFilterIterator) { |
2047 | 35 | if (ZEND_FCC_INITIALIZED(object->u.callback_filter)) { |
2048 | 35 | zend_fcc_dtor(&object->u.callback_filter); |
2049 | 35 | } |
2050 | 35 | } |
2051 | | |
2052 | 278 | zend_object_std_dtor(&object->std); |
2053 | 278 | } |
2054 | | /* }}} */ |
2055 | | |
2056 | | static HashTable *spl_dual_it_get_gc(zend_object *obj, zval **table, int *n) |
2057 | 569 | { |
2058 | 569 | spl_dual_it_object *object = spl_dual_it_from_obj(obj); |
2059 | 569 | zend_get_gc_buffer *gc_buffer = zend_get_gc_buffer_create(); |
2060 | | |
2061 | 569 | if (object->inner.iterator) { |
2062 | 188 | zend_get_gc_buffer_add_obj(gc_buffer, &object->inner.iterator->std); |
2063 | 188 | } |
2064 | | |
2065 | 569 | zend_get_gc_buffer_add_zval(gc_buffer, &object->current.data); |
2066 | 569 | zend_get_gc_buffer_add_zval(gc_buffer, &object->current.key); |
2067 | 569 | zend_get_gc_buffer_add_zval(gc_buffer, &object->inner.zobject); |
2068 | | |
2069 | 569 | switch (object->dit_type) { |
2070 | 381 | case DIT_Unknown: |
2071 | 381 | case DIT_Default: |
2072 | 431 | case DIT_IteratorIterator: |
2073 | 431 | case DIT_NoRewindIterator: |
2074 | 431 | case DIT_InfiniteIterator: |
2075 | 431 | case DIT_LimitIterator: |
2076 | 431 | case DIT_RegexIterator: |
2077 | 431 | case DIT_RecursiveRegexIterator: |
2078 | | /* Nothing to do */ |
2079 | 431 | break; |
2080 | 0 | case DIT_AppendIterator: |
2081 | 0 | zend_get_gc_buffer_add_obj(gc_buffer, &object->u.append.iterator->std); |
2082 | 0 | if (Z_TYPE(object->u.append.zarrayit) != IS_UNDEF) { |
2083 | 0 | zend_get_gc_buffer_add_zval(gc_buffer, &object->u.append.zarrayit); |
2084 | 0 | } |
2085 | 0 | break; |
2086 | 0 | case DIT_CachingIterator: |
2087 | 0 | case DIT_RecursiveCachingIterator: |
2088 | 0 | zend_get_gc_buffer_add_zval(gc_buffer, &object->u.caching.zcache); |
2089 | 0 | zend_get_gc_buffer_add_zval(gc_buffer, &object->u.caching.zchildren); |
2090 | 0 | break; |
2091 | 138 | case DIT_CallbackFilterIterator: |
2092 | 138 | case DIT_RecursiveCallbackFilterIterator: |
2093 | 138 | if (ZEND_FCC_INITIALIZED(object->u.callback_filter)) { |
2094 | 138 | zend_get_gc_buffer_add_fcc(gc_buffer, &object->u.callback_filter); |
2095 | 138 | } |
2096 | 138 | break; |
2097 | 569 | } |
2098 | | |
2099 | 569 | zend_get_gc_buffer_use(gc_buffer, table, n); |
2100 | 569 | return zend_std_get_properties(obj); |
2101 | 569 | } |
2102 | | |
2103 | | /* {{{ spl_dual_it_new */ |
2104 | | static zend_object *spl_dual_it_new(zend_class_entry *class_type) |
2105 | 278 | { |
2106 | 278 | spl_dual_it_object *intern; |
2107 | | |
2108 | 278 | intern = zend_object_alloc(sizeof(spl_dual_it_object), class_type); |
2109 | 278 | intern->dit_type = DIT_Unknown; |
2110 | | |
2111 | 278 | zend_object_std_init(&intern->std, class_type); |
2112 | 278 | object_properties_init(&intern->std, class_type); |
2113 | | |
2114 | 278 | return &intern->std; |
2115 | 278 | } |
2116 | | /* }}} */ |
2117 | | |
2118 | | static inline zend_result spl_limit_it_valid(spl_dual_it_object *intern) |
2119 | 0 | { |
2120 | | /* FAILURE / SUCCESS */ |
2121 | 0 | if (intern->u.limit.count != -1 && intern->current.pos >= intern->u.limit.offset + intern->u.limit.count) { |
2122 | 0 | return FAILURE; |
2123 | 0 | } else { |
2124 | 0 | return spl_dual_it_valid(intern); |
2125 | 0 | } |
2126 | 0 | } |
2127 | | |
2128 | | static inline void spl_limit_it_seek(spl_dual_it_object *intern, zend_long pos) |
2129 | 0 | { |
2130 | 0 | zval zpos; |
2131 | |
|
2132 | 0 | spl_dual_it_free(intern); |
2133 | 0 | if (pos < intern->u.limit.offset) { |
2134 | 0 | zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0, "Cannot seek to " ZEND_LONG_FMT " which is below the offset " ZEND_LONG_FMT, pos, intern->u.limit.offset); |
2135 | 0 | return; |
2136 | 0 | } |
2137 | 0 | if (pos - intern->u.limit.offset >= intern->u.limit.count && intern->u.limit.count != -1) { |
2138 | 0 | zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0, "Cannot seek to " ZEND_LONG_FMT " which is behind offset " ZEND_LONG_FMT " plus count " ZEND_LONG_FMT, pos, intern->u.limit.offset, intern->u.limit.count); |
2139 | 0 | return; |
2140 | 0 | } |
2141 | 0 | if (pos != intern->current.pos && instanceof_function(intern->inner.ce, spl_ce_SeekableIterator)) { |
2142 | 0 | ZVAL_LONG(&zpos, pos); |
2143 | 0 | spl_dual_it_free(intern); |
2144 | 0 | zend_call_method_with_1_params(Z_OBJ(intern->inner.zobject), intern->inner.ce, NULL, "seek", NULL, &zpos); |
2145 | 0 | if (!EG(exception)) { |
2146 | 0 | intern->current.pos = pos; |
2147 | 0 | if (spl_limit_it_valid(intern) == SUCCESS) { |
2148 | 0 | spl_dual_it_fetch(intern, 0); |
2149 | 0 | } |
2150 | 0 | } |
2151 | 0 | } else { |
2152 | | /* emulate the forward seek, by next() calls */ |
2153 | | /* a back ward seek is done by a previous rewind() */ |
2154 | 0 | if (pos < intern->current.pos) { |
2155 | 0 | spl_dual_it_rewind(intern); |
2156 | 0 | } |
2157 | 0 | while (pos > intern->current.pos && spl_dual_it_valid(intern) == SUCCESS) { |
2158 | 0 | spl_dual_it_next(intern, 1); |
2159 | 0 | } |
2160 | 0 | if (spl_dual_it_valid(intern) == SUCCESS) { |
2161 | 0 | spl_dual_it_fetch(intern, 1); |
2162 | 0 | } |
2163 | 0 | } |
2164 | 0 | } |
2165 | | |
2166 | | /* {{{ Construct a LimitIterator from an Iterator with a given starting offset and optionally a maximum count */ |
2167 | | PHP_METHOD(LimitIterator, __construct) |
2168 | 10 | { |
2169 | 10 | spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_LimitIterator, zend_ce_iterator, DIT_LimitIterator); |
2170 | 10 | } /* }}} */ |
2171 | | |
2172 | | /* {{{ Rewind the iterator to the specified starting offset */ |
2173 | | PHP_METHOD(LimitIterator, rewind) |
2174 | 0 | { |
2175 | 0 | spl_dual_it_object *intern; |
2176 | |
|
2177 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
2178 | | |
2179 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
2180 | 0 | spl_dual_it_rewind(intern); |
2181 | 0 | spl_limit_it_seek(intern, intern->u.limit.offset); |
2182 | 0 | } /* }}} */ |
2183 | | |
2184 | | /* {{{ Check whether the current element is valid */ |
2185 | | PHP_METHOD(LimitIterator, valid) |
2186 | 0 | { |
2187 | 0 | spl_dual_it_object *intern; |
2188 | |
|
2189 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
2190 | | |
2191 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
2192 | | |
2193 | | /* RETURN_BOOL(spl_limit_it_valid(intern) == SUCCESS);*/ |
2194 | 0 | RETURN_BOOL((intern->u.limit.count == -1 || intern->current.pos < intern->u.limit.offset + intern->u.limit.count) && Z_TYPE(intern->current.data) != IS_UNDEF); |
2195 | 0 | } /* }}} */ |
2196 | | |
2197 | | /* {{{ Move the iterator forward */ |
2198 | | PHP_METHOD(LimitIterator, next) |
2199 | 0 | { |
2200 | 0 | spl_dual_it_object *intern; |
2201 | |
|
2202 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
2203 | | |
2204 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
2205 | | |
2206 | 0 | spl_dual_it_next(intern, 1); |
2207 | 0 | if (intern->u.limit.count == -1 || intern->current.pos < intern->u.limit.offset + intern->u.limit.count) { |
2208 | 0 | spl_dual_it_fetch(intern, 1); |
2209 | 0 | } |
2210 | 0 | } /* }}} */ |
2211 | | |
2212 | | /* {{{ Seek to the given position */ |
2213 | | PHP_METHOD(LimitIterator, seek) |
2214 | 0 | { |
2215 | 0 | spl_dual_it_object *intern; |
2216 | 0 | zend_long pos; |
2217 | |
|
2218 | 0 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &pos) == FAILURE) { |
2219 | 0 | RETURN_THROWS(); |
2220 | 0 | } |
2221 | | |
2222 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
2223 | 0 | spl_limit_it_seek(intern, pos); |
2224 | 0 | RETURN_LONG(intern->current.pos); |
2225 | 0 | } /* }}} */ |
2226 | | |
2227 | | /* {{{ Return the current position */ |
2228 | | PHP_METHOD(LimitIterator, getPosition) |
2229 | 0 | { |
2230 | 0 | spl_dual_it_object *intern; |
2231 | |
|
2232 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
2233 | | |
2234 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
2235 | 0 | RETURN_LONG(intern->current.pos); |
2236 | 0 | } /* }}} */ |
2237 | | |
2238 | | static inline int spl_caching_it_valid(spl_dual_it_object *intern) |
2239 | 0 | { |
2240 | 0 | return intern->u.caching.flags & CIT_VALID ? SUCCESS : FAILURE; |
2241 | 0 | } |
2242 | | |
2243 | | static inline int spl_caching_it_has_next(spl_dual_it_object *intern) |
2244 | 0 | { |
2245 | 0 | return spl_dual_it_valid(intern); |
2246 | 0 | } |
2247 | | |
2248 | | static inline void spl_caching_it_next(spl_dual_it_object *intern) |
2249 | 0 | { |
2250 | 0 | if (spl_dual_it_fetch(intern, 1) == SUCCESS) { |
2251 | 0 | intern->u.caching.flags |= CIT_VALID; |
2252 | | /* Full cache ? */ |
2253 | 0 | if (intern->u.caching.flags & CIT_FULL_CACHE) { |
2254 | 0 | zval *key = &intern->current.key; |
2255 | 0 | zval *data = &intern->current.data; |
2256 | |
|
2257 | 0 | ZVAL_DEREF(data); |
2258 | 0 | array_set_zval_key(Z_ARRVAL(intern->u.caching.zcache), key, data); |
2259 | 0 | } |
2260 | | /* Recursion ? */ |
2261 | 0 | if (intern->dit_type == DIT_RecursiveCachingIterator) { |
2262 | 0 | zval retval; |
2263 | 0 | zend_call_method_with_0_params(Z_OBJ(intern->inner.zobject), intern->inner.ce, NULL, "haschildren", &retval); |
2264 | 0 | if (EG(exception)) { |
2265 | 0 | zval_ptr_dtor(&retval); |
2266 | 0 | if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) { |
2267 | 0 | zend_clear_exception(); |
2268 | 0 | } else { |
2269 | 0 | return; |
2270 | 0 | } |
2271 | 0 | } else { |
2272 | 0 | bool has_children = zend_is_true(&retval); |
2273 | 0 | zval_ptr_dtor(&retval); |
2274 | |
|
2275 | 0 | if (has_children) { |
2276 | 0 | zval args[2]; |
2277 | | |
2278 | | /* Store the children in the first constructor argument */ |
2279 | 0 | zend_call_method_with_0_params(Z_OBJ(intern->inner.zobject), intern->inner.ce, NULL, "getchildren", &args[0]); |
2280 | 0 | if (EG(exception)) { |
2281 | 0 | zval_ptr_dtor(&args[0]); |
2282 | 0 | if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) { |
2283 | 0 | zend_clear_exception(); |
2284 | 0 | } else { |
2285 | 0 | return; |
2286 | 0 | } |
2287 | 0 | } else { |
2288 | 0 | ZVAL_LONG(&args[1], intern->u.caching.flags & CIT_PUBLIC); |
2289 | |
|
2290 | 0 | zend_result is_initialized = object_init_with_constructor( |
2291 | 0 | &intern->u.caching.zchildren, |
2292 | 0 | spl_ce_RecursiveCachingIterator, |
2293 | 0 | 2, |
2294 | 0 | args, |
2295 | 0 | NULL |
2296 | 0 | ); |
2297 | 0 | zval_ptr_dtor(&args[0]); |
2298 | 0 | if (is_initialized == FAILURE) { |
2299 | 0 | if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) { |
2300 | 0 | zend_clear_exception(); |
2301 | 0 | } else { |
2302 | 0 | return; |
2303 | 0 | } |
2304 | 0 | } |
2305 | 0 | } |
2306 | 0 | } |
2307 | 0 | } |
2308 | 0 | } |
2309 | 0 | if (intern->u.caching.flags & (CIT_TOSTRING_USE_INNER|CIT_CALL_TOSTRING)) { |
2310 | 0 | if (intern->u.caching.flags & CIT_TOSTRING_USE_INNER) { |
2311 | 0 | intern->u.caching.zstr = zval_get_string(&intern->inner.zobject); |
2312 | 0 | } else { |
2313 | 0 | intern->u.caching.zstr = zval_get_string(&intern->current.data); |
2314 | 0 | } |
2315 | 0 | } |
2316 | 0 | spl_dual_it_next(intern, 0); |
2317 | 0 | } else { |
2318 | 0 | intern->u.caching.flags &= ~CIT_VALID; |
2319 | 0 | } |
2320 | 0 | } |
2321 | | |
2322 | | static inline void spl_caching_it_rewind(spl_dual_it_object *intern) |
2323 | 0 | { |
2324 | 0 | spl_dual_it_rewind(intern); |
2325 | 0 | zend_hash_clean(Z_ARRVAL(intern->u.caching.zcache)); |
2326 | 0 | spl_caching_it_next(intern); |
2327 | 0 | } |
2328 | | |
2329 | | /* {{{ Construct a CachingIterator from an Iterator */ |
2330 | | PHP_METHOD(CachingIterator, __construct) |
2331 | 5 | { |
2332 | 5 | spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_CachingIterator, zend_ce_iterator, DIT_CachingIterator); |
2333 | 5 | } /* }}} */ |
2334 | | |
2335 | | /* {{{ Rewind the iterator */ |
2336 | | PHP_METHOD(CachingIterator, rewind) |
2337 | 0 | { |
2338 | 0 | spl_dual_it_object *intern; |
2339 | |
|
2340 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
2341 | | |
2342 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
2343 | | |
2344 | 0 | spl_caching_it_rewind(intern); |
2345 | 0 | } /* }}} */ |
2346 | | |
2347 | | /* {{{ Check whether the current element is valid */ |
2348 | | PHP_METHOD(CachingIterator, valid) |
2349 | 0 | { |
2350 | 0 | spl_dual_it_object *intern; |
2351 | |
|
2352 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
2353 | | |
2354 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
2355 | | |
2356 | 0 | RETURN_BOOL(spl_caching_it_valid(intern) == SUCCESS); |
2357 | 0 | } /* }}} */ |
2358 | | |
2359 | | /* {{{ Move the iterator forward */ |
2360 | | PHP_METHOD(CachingIterator, next) |
2361 | 0 | { |
2362 | 0 | spl_dual_it_object *intern; |
2363 | |
|
2364 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
2365 | | |
2366 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
2367 | | |
2368 | 0 | spl_caching_it_next(intern); |
2369 | 0 | } /* }}} */ |
2370 | | |
2371 | | /* {{{ Check whether the inner iterator has a valid next element */ |
2372 | | PHP_METHOD(CachingIterator, hasNext) |
2373 | 0 | { |
2374 | 0 | spl_dual_it_object *intern; |
2375 | |
|
2376 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
2377 | | |
2378 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
2379 | | |
2380 | 0 | RETURN_BOOL(spl_caching_it_has_next(intern) == SUCCESS); |
2381 | 0 | } /* }}} */ |
2382 | | |
2383 | | /* {{{ Return the string representation of the current element */ |
2384 | | PHP_METHOD(CachingIterator, __toString) |
2385 | 0 | { |
2386 | 0 | spl_dual_it_object *intern; |
2387 | |
|
2388 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
2389 | | |
2390 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
2391 | | |
2392 | 0 | if (!(intern->u.caching.flags & (CIT_CALL_TOSTRING|CIT_TOSTRING_USE_KEY|CIT_TOSTRING_USE_CURRENT|CIT_TOSTRING_USE_INNER))) { |
2393 | 0 | zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s does not fetch string value (see CachingIterator::__construct)", ZSTR_VAL(Z_OBJCE_P(ZEND_THIS)->name)); |
2394 | 0 | RETURN_THROWS(); |
2395 | 0 | } |
2396 | | |
2397 | 0 | if (intern->u.caching.flags & CIT_TOSTRING_USE_KEY) { |
2398 | 0 | ZVAL_COPY(return_value, &intern->current.key); |
2399 | 0 | convert_to_string(return_value); |
2400 | 0 | return; |
2401 | 0 | } else if (intern->u.caching.flags & CIT_TOSTRING_USE_CURRENT) { |
2402 | 0 | ZVAL_COPY(return_value, &intern->current.data); |
2403 | 0 | convert_to_string(return_value); |
2404 | 0 | return; |
2405 | 0 | } |
2406 | 0 | if (intern->u.caching.zstr) { |
2407 | 0 | RETURN_STR_COPY(intern->u.caching.zstr); |
2408 | 0 | } else { |
2409 | 0 | RETURN_EMPTY_STRING(); |
2410 | 0 | } |
2411 | 0 | } /* }}} */ |
2412 | | |
2413 | | /* {{{ Set given index in cache */ |
2414 | | PHP_METHOD(CachingIterator, offsetSet) |
2415 | 0 | { |
2416 | 0 | spl_dual_it_object *intern; |
2417 | 0 | zend_string *key; |
2418 | 0 | zval *value; |
2419 | |
|
2420 | 0 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sz", &key, &value) == FAILURE) { |
2421 | 0 | RETURN_THROWS(); |
2422 | 0 | } |
2423 | | |
2424 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
2425 | | |
2426 | 0 | if (!(intern->u.caching.flags & CIT_FULL_CACHE)) { |
2427 | 0 | zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s does not use a full cache (see CachingIterator::__construct)", ZSTR_VAL(Z_OBJCE_P(ZEND_THIS)->name)); |
2428 | 0 | RETURN_THROWS(); |
2429 | 0 | } |
2430 | | |
2431 | 0 | Z_TRY_ADDREF_P(value); |
2432 | 0 | zend_symtable_update(Z_ARRVAL(intern->u.caching.zcache), key, value); |
2433 | 0 | } |
2434 | | /* }}} */ |
2435 | | |
2436 | | /* {{{ Return the internal cache if used */ |
2437 | | PHP_METHOD(CachingIterator, offsetGet) |
2438 | 0 | { |
2439 | 0 | spl_dual_it_object *intern; |
2440 | 0 | zend_string *key; |
2441 | 0 | zval *value; |
2442 | |
|
2443 | 0 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &key) == FAILURE) { |
2444 | 0 | RETURN_THROWS(); |
2445 | 0 | } |
2446 | | |
2447 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
2448 | | |
2449 | 0 | if (!(intern->u.caching.flags & CIT_FULL_CACHE)) { |
2450 | 0 | zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s does not use a full cache (see CachingIterator::__construct)", ZSTR_VAL(Z_OBJCE_P(ZEND_THIS)->name)); |
2451 | 0 | RETURN_THROWS(); |
2452 | 0 | } |
2453 | | |
2454 | 0 | if ((value = zend_symtable_find(Z_ARRVAL(intern->u.caching.zcache), key)) == NULL) { |
2455 | 0 | zend_error(E_WARNING, "Undefined array key \"%s\"", ZSTR_VAL(key)); |
2456 | 0 | return; |
2457 | 0 | } |
2458 | | |
2459 | 0 | RETURN_COPY_DEREF(value); |
2460 | 0 | } |
2461 | | /* }}} */ |
2462 | | |
2463 | | /* {{{ Unset given index in cache */ |
2464 | | PHP_METHOD(CachingIterator, offsetUnset) |
2465 | 0 | { |
2466 | 0 | spl_dual_it_object *intern; |
2467 | 0 | zend_string *key; |
2468 | |
|
2469 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
2470 | | |
2471 | 0 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &key) == FAILURE) { |
2472 | 0 | RETURN_THROWS(); |
2473 | 0 | } |
2474 | | |
2475 | 0 | if (!(intern->u.caching.flags & CIT_FULL_CACHE)) { |
2476 | 0 | zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s does not use a full cache (see CachingIterator::__construct)", ZSTR_VAL(Z_OBJCE_P(ZEND_THIS)->name)); |
2477 | 0 | RETURN_THROWS(); |
2478 | 0 | } |
2479 | | |
2480 | 0 | zend_symtable_del(Z_ARRVAL(intern->u.caching.zcache), key); |
2481 | 0 | } |
2482 | | /* }}} */ |
2483 | | |
2484 | | /* {{{ Return whether the requested index exists */ |
2485 | | PHP_METHOD(CachingIterator, offsetExists) |
2486 | 0 | { |
2487 | 0 | spl_dual_it_object *intern; |
2488 | 0 | zend_string *key; |
2489 | |
|
2490 | 0 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &key) == FAILURE) { |
2491 | 0 | RETURN_THROWS(); |
2492 | 0 | } |
2493 | | |
2494 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
2495 | | |
2496 | 0 | if (!(intern->u.caching.flags & CIT_FULL_CACHE)) { |
2497 | 0 | zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s does not use a full cache (see CachingIterator::__construct)", ZSTR_VAL(Z_OBJCE_P(ZEND_THIS)->name)); |
2498 | 0 | RETURN_THROWS(); |
2499 | 0 | } |
2500 | | |
2501 | 0 | RETURN_BOOL(zend_symtable_exists(Z_ARRVAL(intern->u.caching.zcache), key)); |
2502 | 0 | } |
2503 | | /* }}} */ |
2504 | | |
2505 | | /* {{{ Return the cache */ |
2506 | | PHP_METHOD(CachingIterator, getCache) |
2507 | 0 | { |
2508 | 0 | spl_dual_it_object *intern; |
2509 | |
|
2510 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
2511 | | |
2512 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
2513 | | |
2514 | 0 | if (!(intern->u.caching.flags & CIT_FULL_CACHE)) { |
2515 | 0 | zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s does not use a full cache (see CachingIterator::__construct)", ZSTR_VAL(Z_OBJCE_P(ZEND_THIS)->name)); |
2516 | 0 | RETURN_THROWS(); |
2517 | 0 | } |
2518 | | |
2519 | 0 | ZVAL_COPY(return_value, &intern->u.caching.zcache); |
2520 | 0 | } |
2521 | | /* }}} */ |
2522 | | |
2523 | | /* {{{ Return the internal flags */ |
2524 | | PHP_METHOD(CachingIterator, getFlags) |
2525 | 0 | { |
2526 | 0 | spl_dual_it_object *intern; |
2527 | |
|
2528 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
2529 | | |
2530 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
2531 | | |
2532 | 0 | RETURN_LONG(intern->u.caching.flags); |
2533 | 0 | } |
2534 | | /* }}} */ |
2535 | | |
2536 | | /* {{{ Set the internal flags */ |
2537 | | PHP_METHOD(CachingIterator, setFlags) |
2538 | 0 | { |
2539 | 0 | spl_dual_it_object *intern; |
2540 | 0 | zend_long flags; |
2541 | |
|
2542 | 0 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &flags) == FAILURE) { |
2543 | 0 | RETURN_THROWS(); |
2544 | 0 | } |
2545 | | |
2546 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
2547 | | |
2548 | 0 | if (spl_cit_check_flags(flags) != SUCCESS) { |
2549 | 0 | zend_argument_value_error(1, "must contain only one of CachingIterator::CALL_TOSTRING, " |
2550 | 0 | "CachingIterator::TOSTRING_USE_KEY, CachingIterator::TOSTRING_USE_CURRENT, " |
2551 | 0 | "or CachingIterator::TOSTRING_USE_INNER"); |
2552 | 0 | RETURN_THROWS(); |
2553 | 0 | } |
2554 | 0 | if ((intern->u.caching.flags & CIT_CALL_TOSTRING) != 0 && (flags & CIT_CALL_TOSTRING) == 0) { |
2555 | 0 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unsetting flag CALL_TO_STRING is not possible", 0); |
2556 | 0 | RETURN_THROWS(); |
2557 | 0 | } |
2558 | 0 | if ((intern->u.caching.flags & CIT_TOSTRING_USE_INNER) != 0 && (flags & CIT_TOSTRING_USE_INNER) == 0) { |
2559 | 0 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unsetting flag TOSTRING_USE_INNER is not possible", 0); |
2560 | 0 | RETURN_THROWS(); |
2561 | 0 | } |
2562 | 0 | if ((flags & CIT_FULL_CACHE) != 0 && (intern->u.caching.flags & CIT_FULL_CACHE) == 0) { |
2563 | | /* clear on (re)enable */ |
2564 | 0 | zend_hash_clean(Z_ARRVAL(intern->u.caching.zcache)); |
2565 | 0 | } |
2566 | 0 | intern->u.caching.flags = (intern->u.caching.flags & ~CIT_PUBLIC) | (flags & CIT_PUBLIC); |
2567 | 0 | } |
2568 | | /* }}} */ |
2569 | | |
2570 | | /* {{{ Number of cached elements */ |
2571 | | PHP_METHOD(CachingIterator, count) |
2572 | 0 | { |
2573 | 0 | spl_dual_it_object *intern; |
2574 | |
|
2575 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
2576 | | |
2577 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
2578 | | |
2579 | 0 | if (!(intern->u.caching.flags & CIT_FULL_CACHE)) { |
2580 | 0 | zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s does not use a full cache (see CachingIterator::__construct)", ZSTR_VAL(Z_OBJCE_P(ZEND_THIS)->name)); |
2581 | 0 | RETURN_THROWS(); |
2582 | 0 | } |
2583 | | |
2584 | 0 | RETURN_LONG(zend_hash_num_elements(Z_ARRVAL(intern->u.caching.zcache))); |
2585 | 0 | } |
2586 | | /* }}} */ |
2587 | | |
2588 | | /* {{{ Create an iterator from a RecursiveIterator */ |
2589 | | PHP_METHOD(RecursiveCachingIterator, __construct) |
2590 | 5 | { |
2591 | 5 | spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveCachingIterator, spl_ce_RecursiveIterator, DIT_RecursiveCachingIterator); |
2592 | 5 | } /* }}} */ |
2593 | | |
2594 | | /* {{{ Check whether the current element of the inner iterator has children */ |
2595 | | PHP_METHOD(RecursiveCachingIterator, hasChildren) |
2596 | 0 | { |
2597 | 0 | spl_dual_it_object *intern; |
2598 | |
|
2599 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
2600 | | |
2601 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
2602 | | |
2603 | 0 | RETURN_BOOL(Z_TYPE(intern->u.caching.zchildren) != IS_UNDEF); |
2604 | 0 | } /* }}} */ |
2605 | | |
2606 | | /* {{{ Return the inner iterator's children as a RecursiveCachingIterator */ |
2607 | | PHP_METHOD(RecursiveCachingIterator, getChildren) |
2608 | 0 | { |
2609 | 0 | spl_dual_it_object *intern; |
2610 | |
|
2611 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
2612 | | |
2613 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
2614 | | |
2615 | 0 | if (Z_TYPE(intern->u.caching.zchildren) != IS_UNDEF) { |
2616 | 0 | zval *value = &intern->u.caching.zchildren; |
2617 | |
|
2618 | 0 | RETURN_COPY_DEREF(value); |
2619 | 0 | } else { |
2620 | 0 | RETURN_NULL(); |
2621 | 0 | } |
2622 | 0 | } /* }}} */ |
2623 | | |
2624 | | /* {{{ Create an iterator from anything that is traversable */ |
2625 | | PHP_METHOD(IteratorIterator, __construct) |
2626 | 45 | { |
2627 | 45 | spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_IteratorIterator, zend_ce_traversable, DIT_IteratorIterator); |
2628 | 45 | } /* }}} */ |
2629 | | |
2630 | | /* {{{ Create an iterator from another iterator */ |
2631 | | PHP_METHOD(NoRewindIterator, __construct) |
2632 | 5 | { |
2633 | 5 | spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_NoRewindIterator, zend_ce_iterator, DIT_NoRewindIterator); |
2634 | 5 | } /* }}} */ |
2635 | | |
2636 | | /* {{{ Prevent a call to inner iterators rewind() */ |
2637 | | PHP_METHOD(NoRewindIterator, rewind) |
2638 | 0 | { |
2639 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
2640 | | /* nothing to do */ |
2641 | 0 | } /* }}} */ |
2642 | | |
2643 | | /* {{{ Return inner iterators valid() */ |
2644 | | PHP_METHOD(NoRewindIterator, valid) |
2645 | 0 | { |
2646 | 0 | spl_dual_it_object *intern; |
2647 | |
|
2648 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
2649 | | |
2650 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
2651 | 0 | RETURN_BOOL(intern->inner.iterator->funcs->valid(intern->inner.iterator) == SUCCESS); |
2652 | 0 | } /* }}} */ |
2653 | | |
2654 | | /* {{{ Return inner iterators key() */ |
2655 | | PHP_METHOD(NoRewindIterator, key) |
2656 | 0 | { |
2657 | 0 | spl_dual_it_object *intern; |
2658 | |
|
2659 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
2660 | | |
2661 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
2662 | | |
2663 | 0 | if (intern->inner.iterator->funcs->get_current_key) { |
2664 | 0 | intern->inner.iterator->funcs->get_current_key(intern->inner.iterator, return_value); |
2665 | 0 | } else { |
2666 | 0 | RETURN_NULL(); |
2667 | 0 | } |
2668 | 0 | } /* }}} */ |
2669 | | |
2670 | | /* {{{ Return inner iterators current() */ |
2671 | | PHP_METHOD(NoRewindIterator, current) |
2672 | 0 | { |
2673 | 0 | spl_dual_it_object *intern; |
2674 | 0 | zval *data; |
2675 | |
|
2676 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
2677 | | |
2678 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
2679 | 0 | data = intern->inner.iterator->funcs->get_current_data(intern->inner.iterator); |
2680 | 0 | if (data) { |
2681 | 0 | RETURN_COPY_DEREF(data); |
2682 | 0 | } |
2683 | 0 | } /* }}} */ |
2684 | | |
2685 | | /* {{{ Return inner iterators next() */ |
2686 | | PHP_METHOD(NoRewindIterator, next) |
2687 | 0 | { |
2688 | 0 | spl_dual_it_object *intern; |
2689 | |
|
2690 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
2691 | | |
2692 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
2693 | 0 | intern->inner.iterator->funcs->move_forward(intern->inner.iterator); |
2694 | 0 | } /* }}} */ |
2695 | | |
2696 | | /* {{{ Create an iterator from another iterator */ |
2697 | | PHP_METHOD(InfiniteIterator, __construct) |
2698 | 0 | { |
2699 | 0 | spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_InfiniteIterator, zend_ce_iterator, DIT_InfiniteIterator); |
2700 | 0 | } /* }}} */ |
2701 | | |
2702 | | /* {{{ Prevent a call to inner iterators rewind() (internally the current data will be fetched if valid()) */ |
2703 | | PHP_METHOD(InfiniteIterator, next) |
2704 | 0 | { |
2705 | 0 | spl_dual_it_object *intern; |
2706 | |
|
2707 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
2708 | | |
2709 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
2710 | | |
2711 | 0 | spl_dual_it_next(intern, 1); |
2712 | 0 | if (spl_dual_it_valid(intern) == SUCCESS) { |
2713 | 0 | spl_dual_it_fetch(intern, 0); |
2714 | 0 | } else { |
2715 | 0 | spl_dual_it_rewind(intern); |
2716 | 0 | if (spl_dual_it_valid(intern) == SUCCESS) { |
2717 | 0 | spl_dual_it_fetch(intern, 0); |
2718 | 0 | } |
2719 | 0 | } |
2720 | 0 | } /* }}} */ |
2721 | | |
2722 | | /* {{{ Does nothing */ |
2723 | | PHP_METHOD(EmptyIterator, rewind) |
2724 | 0 | { |
2725 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
2726 | 0 | } /* }}} */ |
2727 | | |
2728 | | /* {{{ Return false */ |
2729 | | PHP_METHOD(EmptyIterator, valid) |
2730 | 0 | { |
2731 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
2732 | 0 | RETURN_FALSE; |
2733 | 0 | } /* }}} */ |
2734 | | |
2735 | | /* {{{ Throws exception BadMethodCallException */ |
2736 | | PHP_METHOD(EmptyIterator, key) |
2737 | 0 | { |
2738 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
2739 | 0 | zend_throw_exception(spl_ce_BadMethodCallException, "Accessing the key of an EmptyIterator", 0); |
2740 | 0 | } /* }}} */ |
2741 | | |
2742 | | /* {{{ Throws exception BadMethodCallException */ |
2743 | | PHP_METHOD(EmptyIterator, current) |
2744 | 0 | { |
2745 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
2746 | 0 | zend_throw_exception(spl_ce_BadMethodCallException, "Accessing the value of an EmptyIterator", 0); |
2747 | 0 | } /* }}} */ |
2748 | | |
2749 | | /* {{{ Does nothing */ |
2750 | | PHP_METHOD(EmptyIterator, next) |
2751 | 0 | { |
2752 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
2753 | 0 | } /* }}} */ |
2754 | | |
2755 | | static zend_result spl_append_it_next_iterator(spl_dual_it_object *intern) /* {{{*/ |
2756 | 0 | { |
2757 | 0 | spl_dual_it_free(intern); |
2758 | |
|
2759 | 0 | if (!Z_ISUNDEF(intern->inner.zobject)) { |
2760 | 0 | zval_ptr_dtor(&intern->inner.zobject); |
2761 | 0 | ZVAL_UNDEF(&intern->inner.zobject); |
2762 | 0 | intern->inner.ce = NULL; |
2763 | 0 | if (intern->inner.iterator) { |
2764 | 0 | zend_iterator_dtor(intern->inner.iterator); |
2765 | 0 | intern->inner.iterator = NULL; |
2766 | 0 | } |
2767 | 0 | } |
2768 | 0 | if (intern->u.append.iterator->funcs->valid(intern->u.append.iterator) == SUCCESS) { |
2769 | 0 | zval *it; |
2770 | |
|
2771 | 0 | it = intern->u.append.iterator->funcs->get_current_data(intern->u.append.iterator); |
2772 | 0 | ZVAL_COPY(&intern->inner.zobject, it); |
2773 | 0 | intern->inner.ce = Z_OBJCE_P(it); |
2774 | 0 | intern->inner.iterator = intern->inner.ce->get_iterator(intern->inner.ce, it, 0); |
2775 | 0 | spl_dual_it_rewind(intern); |
2776 | 0 | return SUCCESS; |
2777 | 0 | } else { |
2778 | 0 | return FAILURE; |
2779 | 0 | } |
2780 | 0 | } /* }}} */ |
2781 | | |
2782 | | static void spl_append_it_fetch(spl_dual_it_object *intern) /* {{{*/ |
2783 | 0 | { |
2784 | 0 | while (spl_dual_it_valid(intern) != SUCCESS) { |
2785 | 0 | intern->u.append.iterator->funcs->move_forward(intern->u.append.iterator); |
2786 | 0 | if (spl_append_it_next_iterator(intern) != SUCCESS) { |
2787 | 0 | return; |
2788 | 0 | } |
2789 | 0 | } |
2790 | 0 | spl_dual_it_fetch(intern, 0); |
2791 | 0 | } /* }}} */ |
2792 | | |
2793 | | static void spl_append_it_next(spl_dual_it_object *intern) /* {{{ */ |
2794 | 0 | { |
2795 | 0 | if (spl_dual_it_valid(intern) == SUCCESS) { |
2796 | 0 | spl_dual_it_next(intern, 1); |
2797 | 0 | } |
2798 | 0 | spl_append_it_fetch(intern); |
2799 | 0 | } /* }}} */ |
2800 | | |
2801 | | /* {{{ Create an AppendIterator */ |
2802 | | PHP_METHOD(AppendIterator, __construct) |
2803 | 5 | { |
2804 | 5 | spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_AppendIterator, zend_ce_iterator, DIT_AppendIterator); |
2805 | 5 | } /* }}} */ |
2806 | | |
2807 | | /* {{{ Append an iterator */ |
2808 | | PHP_METHOD(AppendIterator, append) |
2809 | 0 | { |
2810 | 0 | spl_dual_it_object *intern; |
2811 | 0 | zval *it; |
2812 | |
|
2813 | 0 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &it, zend_ce_iterator) == FAILURE) { |
2814 | 0 | RETURN_THROWS(); |
2815 | 0 | } |
2816 | | |
2817 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
2818 | | |
2819 | 0 | if (intern->u.append.iterator->funcs->valid(intern->u.append.iterator) == SUCCESS && spl_dual_it_valid(intern) != SUCCESS) { |
2820 | 0 | spl_array_iterator_append(&intern->u.append.zarrayit, it); |
2821 | 0 | intern->u.append.iterator->funcs->move_forward(intern->u.append.iterator); |
2822 | 0 | }else{ |
2823 | 0 | spl_array_iterator_append(&intern->u.append.zarrayit, it); |
2824 | 0 | } |
2825 | |
|
2826 | 0 | if (!intern->inner.iterator || spl_dual_it_valid(intern) != SUCCESS) { |
2827 | 0 | if (intern->u.append.iterator->funcs->valid(intern->u.append.iterator) != SUCCESS) { |
2828 | 0 | intern->u.append.iterator->funcs->rewind(intern->u.append.iterator); |
2829 | 0 | } |
2830 | 0 | do { |
2831 | 0 | spl_append_it_next_iterator(intern); |
2832 | 0 | } while (Z_OBJ(intern->inner.zobject) != Z_OBJ_P(it)); |
2833 | 0 | spl_append_it_fetch(intern); |
2834 | 0 | } |
2835 | 0 | } /* }}} */ |
2836 | | |
2837 | | /* {{{ Get the current element value */ |
2838 | | PHP_METHOD(AppendIterator, current) |
2839 | 0 | { |
2840 | 0 | spl_dual_it_object *intern; |
2841 | |
|
2842 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
2843 | | |
2844 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
2845 | | |
2846 | 0 | spl_dual_it_fetch(intern, 1); |
2847 | 0 | if (Z_TYPE(intern->current.data) != IS_UNDEF) { |
2848 | 0 | RETURN_COPY_DEREF(&intern->current.data); |
2849 | 0 | } else { |
2850 | 0 | RETURN_NULL(); |
2851 | 0 | } |
2852 | 0 | } /* }}} */ |
2853 | | |
2854 | | /* {{{ Rewind to the first iterator and rewind the first iterator, too */ |
2855 | | PHP_METHOD(AppendIterator, rewind) |
2856 | 0 | { |
2857 | 0 | spl_dual_it_object *intern; |
2858 | |
|
2859 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
2860 | | |
2861 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
2862 | | |
2863 | 0 | intern->u.append.iterator->funcs->rewind(intern->u.append.iterator); |
2864 | 0 | if (spl_append_it_next_iterator(intern) == SUCCESS) { |
2865 | 0 | spl_append_it_fetch(intern); |
2866 | 0 | } |
2867 | 0 | } /* }}} */ |
2868 | | |
2869 | | /* {{{ Check if the current state is valid */ |
2870 | | PHP_METHOD(AppendIterator, valid) |
2871 | 0 | { |
2872 | 0 | spl_dual_it_object *intern; |
2873 | |
|
2874 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
2875 | | |
2876 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
2877 | | |
2878 | 0 | RETURN_BOOL(Z_TYPE(intern->current.data) != IS_UNDEF); |
2879 | 0 | } /* }}} */ |
2880 | | |
2881 | | /* {{{ Forward to next element */ |
2882 | | PHP_METHOD(AppendIterator, next) |
2883 | 0 | { |
2884 | 0 | spl_dual_it_object *intern; |
2885 | |
|
2886 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
2887 | | |
2888 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
2889 | | |
2890 | 0 | spl_append_it_next(intern); |
2891 | 0 | } /* }}} */ |
2892 | | |
2893 | | /* {{{ Get index of iterator */ |
2894 | | PHP_METHOD(AppendIterator, getIteratorIndex) |
2895 | 0 | { |
2896 | 0 | spl_dual_it_object *intern; |
2897 | |
|
2898 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
2899 | | |
2900 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
2901 | | |
2902 | 0 | APPENDIT_CHECK_CTOR(intern); |
2903 | 0 | spl_array_iterator_key(&intern->u.append.zarrayit, return_value); |
2904 | 0 | } /* }}} */ |
2905 | | |
2906 | | /* {{{ Get access to inner ArrayIterator */ |
2907 | | PHP_METHOD(AppendIterator, getArrayIterator) |
2908 | 0 | { |
2909 | 0 | spl_dual_it_object *intern; |
2910 | 0 | zval *value; |
2911 | |
|
2912 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
2913 | | |
2914 | 0 | SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS); |
2915 | | |
2916 | 0 | value = &intern->u.append.zarrayit; |
2917 | 0 | RETURN_COPY_DEREF(value); |
2918 | 0 | } /* }}} */ |
2919 | | |
2920 | | PHPAPI zend_result spl_iterator_apply(zval *obj, spl_iterator_apply_func_t apply_func, void *puser) |
2921 | 50 | { |
2922 | 50 | zend_object_iterator *iter; |
2923 | 50 | zend_class_entry *ce = Z_OBJCE_P(obj); |
2924 | | |
2925 | 50 | iter = ce->get_iterator(ce, obj, 0); |
2926 | | |
2927 | 50 | if (EG(exception)) { |
2928 | 0 | goto done; |
2929 | 0 | } |
2930 | | |
2931 | 50 | iter->index = 0; |
2932 | 50 | if (iter->funcs->rewind) { |
2933 | 50 | iter->funcs->rewind(iter); |
2934 | 50 | if (EG(exception)) { |
2935 | 5 | goto done; |
2936 | 5 | } |
2937 | 50 | } |
2938 | | |
2939 | 137 | while (iter->funcs->valid(iter) == SUCCESS) { |
2940 | 92 | if (EG(exception)) { |
2941 | 0 | goto done; |
2942 | 0 | } |
2943 | 92 | if (apply_func(iter, puser) == ZEND_HASH_APPLY_STOP || EG(exception)) { |
2944 | 0 | goto done; |
2945 | 0 | } |
2946 | 92 | iter->index++; |
2947 | 92 | iter->funcs->move_forward(iter); |
2948 | 92 | if (EG(exception)) { |
2949 | 0 | goto done; |
2950 | 0 | } |
2951 | 92 | } |
2952 | | |
2953 | 50 | done: |
2954 | 50 | if (iter) { |
2955 | 50 | zend_iterator_dtor(iter); |
2956 | 50 | } |
2957 | 50 | return EG(exception) ? FAILURE : SUCCESS; |
2958 | 45 | } |
2959 | | /* }}} */ |
2960 | | |
2961 | | static int spl_iterator_to_array_apply(zend_object_iterator *iter, void *puser) /* {{{ */ |
2962 | 87 | { |
2963 | 87 | zval *data, *return_value = (zval*)puser; |
2964 | | |
2965 | 87 | data = iter->funcs->get_current_data(iter); |
2966 | 87 | if (EG(exception)) { |
2967 | 0 | return ZEND_HASH_APPLY_STOP; |
2968 | 0 | } |
2969 | 87 | if (data == NULL) { |
2970 | 0 | return ZEND_HASH_APPLY_STOP; |
2971 | 0 | } |
2972 | 87 | if (iter->funcs->get_current_key) { |
2973 | 87 | zval key; |
2974 | 87 | iter->funcs->get_current_key(iter, &key); |
2975 | 87 | if (EG(exception)) { |
2976 | 0 | return ZEND_HASH_APPLY_STOP; |
2977 | 0 | } |
2978 | 87 | array_set_zval_key(Z_ARRVAL_P(return_value), &key, data); |
2979 | 87 | zval_ptr_dtor(&key); |
2980 | 87 | } else { |
2981 | 0 | Z_TRY_ADDREF_P(data); |
2982 | 0 | add_next_index_zval(return_value, data); |
2983 | 0 | } |
2984 | 87 | return ZEND_HASH_APPLY_KEEP; |
2985 | 87 | } |
2986 | | /* }}} */ |
2987 | | |
2988 | | static int spl_iterator_to_values_apply(zend_object_iterator *iter, void *puser) /* {{{ */ |
2989 | 5 | { |
2990 | 5 | zval *data, *return_value = (zval*)puser; |
2991 | | |
2992 | 5 | data = iter->funcs->get_current_data(iter); |
2993 | 5 | if (EG(exception)) { |
2994 | 0 | return ZEND_HASH_APPLY_STOP; |
2995 | 0 | } |
2996 | 5 | if (data == NULL) { |
2997 | 0 | return ZEND_HASH_APPLY_STOP; |
2998 | 0 | } |
2999 | 5 | Z_TRY_ADDREF_P(data); |
3000 | 5 | add_next_index_zval(return_value, data); |
3001 | 5 | return ZEND_HASH_APPLY_KEEP; |
3002 | 5 | } |
3003 | | /* }}} */ |
3004 | | |
3005 | | /* {{{ Copy the iterator into an array */ |
3006 | | PHP_FUNCTION(iterator_to_array) |
3007 | 53 | { |
3008 | 53 | zval *obj; |
3009 | 53 | bool use_keys = 1; |
3010 | | |
3011 | 159 | ZEND_PARSE_PARAMETERS_START(1, 2) |
3012 | 212 | Z_PARAM_ITERABLE(obj) |
3013 | 50 | Z_PARAM_OPTIONAL |
3014 | 110 | Z_PARAM_BOOL(use_keys) |
3015 | 53 | ZEND_PARSE_PARAMETERS_END(); |
3016 | | |
3017 | 50 | if (Z_TYPE_P(obj) == IS_ARRAY) { |
3018 | 0 | if (use_keys) { |
3019 | 0 | RETURN_COPY(obj); |
3020 | 0 | } else { |
3021 | 0 | RETURN_ARR(zend_array_to_list(Z_ARRVAL_P(obj))); |
3022 | 0 | } |
3023 | 0 | } |
3024 | | |
3025 | 50 | array_init(return_value); |
3026 | 50 | spl_iterator_apply(obj, use_keys ? spl_iterator_to_array_apply : spl_iterator_to_values_apply, (void*)return_value); |
3027 | 50 | } /* }}} */ |
3028 | | |
3029 | | static int spl_iterator_count_apply(zend_object_iterator *iter, void *puser) /* {{{ */ |
3030 | 0 | { |
3031 | 0 | if (UNEXPECTED(*(zend_long*)puser == ZEND_LONG_MAX)) { |
3032 | 0 | return ZEND_HASH_APPLY_STOP; |
3033 | 0 | } |
3034 | 0 | (*(zend_long*)puser)++; |
3035 | 0 | return ZEND_HASH_APPLY_KEEP; |
3036 | 0 | } |
3037 | | /* }}} */ |
3038 | | |
3039 | | /* {{{ Count the elements in an iterator */ |
3040 | | PHP_FUNCTION(iterator_count) |
3041 | 0 | { |
3042 | 0 | zval *obj; |
3043 | 0 | zend_long count = 0; |
3044 | |
|
3045 | 0 | ZEND_PARSE_PARAMETERS_START(1, 1) |
3046 | 0 | Z_PARAM_ITERABLE(obj) |
3047 | 0 | ZEND_PARSE_PARAMETERS_END(); |
3048 | | |
3049 | 0 | if (Z_TYPE_P(obj) == IS_ARRAY) { |
3050 | 0 | count = zend_hash_num_elements(Z_ARRVAL_P(obj)); |
3051 | 0 | } else { |
3052 | 0 | if (spl_iterator_apply(obj, spl_iterator_count_apply, (void*)&count) == FAILURE) { |
3053 | 0 | RETURN_THROWS(); |
3054 | 0 | } |
3055 | 0 | } |
3056 | | |
3057 | 0 | RETURN_LONG(count); |
3058 | 0 | } |
3059 | | /* }}} */ |
3060 | | |
3061 | | typedef struct { |
3062 | | zend_long count; |
3063 | | HashTable *params_ht; |
3064 | | zend_fcall_info_cache fcc; |
3065 | | } spl_iterator_apply_info; |
3066 | | |
3067 | | static int spl_iterator_func_apply(zend_object_iterator *iter, void *puser) /* {{{ */ |
3068 | 0 | { |
3069 | 0 | zval retval; |
3070 | 0 | spl_iterator_apply_info *apply_info = (spl_iterator_apply_info*)puser; |
3071 | 0 | int result; |
3072 | |
|
3073 | 0 | apply_info->count++; |
3074 | 0 | zend_call_known_fcc(&apply_info->fcc, &retval, 0, NULL, apply_info->params_ht); |
3075 | 0 | result = zend_is_true(&retval) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_STOP; |
3076 | 0 | zval_ptr_dtor(&retval); |
3077 | 0 | return result; |
3078 | 0 | } |
3079 | | /* }}} */ |
3080 | | |
3081 | | /* {{{ Calls a function for every element in an iterator */ |
3082 | | PHP_FUNCTION(iterator_apply) |
3083 | 5 | { |
3084 | 5 | zval *traversable; |
3085 | 5 | zend_fcall_info dummy_fci; |
3086 | 5 | spl_iterator_apply_info apply_info = { |
3087 | 5 | .count = 0, |
3088 | 5 | .params_ht = NULL, |
3089 | 5 | .fcc = { 0 }, |
3090 | 5 | }; |
3091 | | |
3092 | | /* The HashTable is used to determine positional arguments */ |
3093 | 5 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "OF|h!", &traversable, zend_ce_traversable, |
3094 | 5 | &dummy_fci, &apply_info.fcc, &apply_info.params_ht) == FAILURE) { |
3095 | 5 | zend_release_fcall_info_cache(&apply_info.fcc); |
3096 | 5 | RETURN_THROWS(); |
3097 | 5 | } |
3098 | | |
3099 | 0 | if (spl_iterator_apply(traversable, spl_iterator_func_apply, (void*)&apply_info) == FAILURE) { |
3100 | 0 | zend_release_fcall_info_cache(&apply_info.fcc); |
3101 | 0 | RETURN_THROWS(); |
3102 | 0 | } |
3103 | 0 | zend_release_fcall_info_cache(&apply_info.fcc); |
3104 | 0 | RETURN_LONG(apply_info.count); |
3105 | 0 | } |
3106 | | /* }}} */ |
3107 | | |
3108 | | /* {{{ PHP_MINIT_FUNCTION(spl_iterators) */ |
3109 | | PHP_MINIT_FUNCTION(spl_iterators) |
3110 | 16 | { |
3111 | 16 | spl_ce_RecursiveIterator = register_class_RecursiveIterator(zend_ce_iterator); |
3112 | | |
3113 | 16 | spl_ce_OuterIterator = register_class_OuterIterator(zend_ce_iterator); |
3114 | | |
3115 | 16 | spl_ce_RecursiveIteratorIterator = register_class_RecursiveIteratorIterator(spl_ce_OuterIterator); |
3116 | 16 | spl_ce_RecursiveIteratorIterator->create_object = spl_RecursiveIteratorIterator_new; |
3117 | 16 | spl_ce_RecursiveIteratorIterator->default_object_handlers = &spl_handlers_rec_it_it; |
3118 | 16 | spl_ce_RecursiveIteratorIterator->get_iterator = spl_recursive_it_get_iterator; |
3119 | | |
3120 | 16 | memcpy(&spl_handlers_rec_it_it, &std_object_handlers, sizeof(zend_object_handlers)); |
3121 | 16 | spl_handlers_rec_it_it.offset = XtOffsetOf(spl_recursive_it_object, std); |
3122 | 16 | spl_handlers_rec_it_it.get_method = spl_recursive_it_get_method; |
3123 | 16 | spl_handlers_rec_it_it.clone_obj = NULL; |
3124 | 16 | spl_handlers_rec_it_it.free_obj = spl_RecursiveIteratorIterator_free_storage; |
3125 | 16 | spl_handlers_rec_it_it.get_gc = spl_RecursiveIteratorIterator_get_gc; |
3126 | | |
3127 | 16 | memcpy(&spl_handlers_dual_it, &std_object_handlers, sizeof(zend_object_handlers)); |
3128 | 16 | spl_handlers_dual_it.offset = XtOffsetOf(spl_dual_it_object, std); |
3129 | 16 | spl_handlers_dual_it.get_method = spl_dual_it_get_method; |
3130 | 16 | spl_handlers_dual_it.clone_obj = NULL; |
3131 | 16 | spl_handlers_dual_it.free_obj = spl_dual_it_free_storage; |
3132 | 16 | spl_handlers_dual_it.get_gc = spl_dual_it_get_gc; |
3133 | | |
3134 | 16 | spl_ce_IteratorIterator = register_class_IteratorIterator(spl_ce_OuterIterator); |
3135 | 16 | spl_ce_IteratorIterator->create_object = spl_dual_it_new; |
3136 | 16 | spl_ce_IteratorIterator->default_object_handlers = &spl_handlers_dual_it; |
3137 | | |
3138 | 16 | spl_ce_FilterIterator = register_class_FilterIterator(spl_ce_IteratorIterator); |
3139 | 16 | spl_ce_FilterIterator->create_object = spl_dual_it_new; |
3140 | | |
3141 | 16 | spl_ce_RecursiveFilterIterator = register_class_RecursiveFilterIterator(spl_ce_FilterIterator, spl_ce_RecursiveIterator); |
3142 | 16 | spl_ce_RecursiveFilterIterator->create_object = spl_dual_it_new; |
3143 | | |
3144 | 16 | spl_ce_CallbackFilterIterator = register_class_CallbackFilterIterator(spl_ce_FilterIterator); |
3145 | 16 | spl_ce_CallbackFilterIterator->create_object = spl_dual_it_new; |
3146 | | |
3147 | 16 | spl_ce_RecursiveCallbackFilterIterator = register_class_RecursiveCallbackFilterIterator(spl_ce_CallbackFilterIterator, spl_ce_RecursiveIterator); |
3148 | 16 | spl_ce_RecursiveCallbackFilterIterator->create_object = spl_dual_it_new; |
3149 | | |
3150 | 16 | spl_ce_ParentIterator = register_class_ParentIterator(spl_ce_RecursiveFilterIterator); |
3151 | 16 | spl_ce_ParentIterator->create_object = spl_dual_it_new; |
3152 | | |
3153 | 16 | spl_ce_SeekableIterator = register_class_SeekableIterator(zend_ce_iterator); |
3154 | | |
3155 | 16 | spl_ce_LimitIterator = register_class_LimitIterator(spl_ce_IteratorIterator); |
3156 | 16 | spl_ce_LimitIterator->create_object = spl_dual_it_new; |
3157 | | |
3158 | 16 | spl_ce_CachingIterator = register_class_CachingIterator(spl_ce_IteratorIterator, zend_ce_arrayaccess, zend_ce_countable, zend_ce_stringable); |
3159 | 16 | spl_ce_CachingIterator->create_object = spl_dual_it_new; |
3160 | | |
3161 | 16 | spl_ce_RecursiveCachingIterator = register_class_RecursiveCachingIterator(spl_ce_CachingIterator, spl_ce_RecursiveIterator); |
3162 | 16 | spl_ce_RecursiveCachingIterator->create_object = spl_dual_it_new; |
3163 | | |
3164 | 16 | spl_ce_NoRewindIterator = register_class_NoRewindIterator(spl_ce_IteratorIterator); |
3165 | 16 | spl_ce_NoRewindIterator->create_object = spl_dual_it_new; |
3166 | | |
3167 | 16 | spl_ce_AppendIterator = register_class_AppendIterator(spl_ce_IteratorIterator); |
3168 | 16 | spl_ce_AppendIterator->create_object = spl_dual_it_new; |
3169 | | |
3170 | 16 | spl_ce_InfiniteIterator = register_class_InfiniteIterator(spl_ce_IteratorIterator); |
3171 | 16 | spl_ce_InfiniteIterator->create_object = spl_dual_it_new; |
3172 | | |
3173 | 16 | spl_ce_RegexIterator = register_class_RegexIterator(spl_ce_FilterIterator); |
3174 | 16 | spl_ce_RegexIterator->create_object = spl_dual_it_new; |
3175 | | |
3176 | 16 | spl_ce_RecursiveRegexIterator = register_class_RecursiveRegexIterator(spl_ce_RegexIterator, spl_ce_RecursiveIterator); |
3177 | 16 | spl_ce_RecursiveRegexIterator->create_object = spl_dual_it_new; |
3178 | | |
3179 | 16 | spl_ce_EmptyIterator = register_class_EmptyIterator(zend_ce_iterator); |
3180 | | |
3181 | 16 | spl_ce_RecursiveTreeIterator = register_class_RecursiveTreeIterator(spl_ce_RecursiveIteratorIterator); |
3182 | 16 | spl_ce_RecursiveTreeIterator->create_object = spl_RecursiveTreeIterator_new; |
3183 | | |
3184 | 16 | return SUCCESS; |
3185 | 16 | } |
3186 | | /* }}} */ |