This source file includes following definitions.
- spl_recursive_it_from_obj
- spl_recursive_it_dtor
- spl_recursive_it_valid_ex
- spl_recursive_it_valid
- spl_recursive_it_get_current_data
- spl_recursive_it_get_current_key
- spl_recursive_it_move_forward_ex
- spl_recursive_it_rewind_ex
- spl_recursive_it_move_forward
- spl_recursive_it_rewind
- spl_recursive_it_get_iterator
- spl_recursive_it_it_construct
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- spl_recursive_it_get_method
- spl_RecursiveIteratorIterator_dtor
- spl_RecursiveIteratorIterator_free_storage
- spl_RecursiveIteratorIterator_new_ex
- spl_RecursiveIteratorIterator_new
- spl_RecursiveTreeIterator_new
- spl_recursive_tree_iterator_get_prefix
- spl_recursive_tree_iterator_get_entry
- spl_recursive_tree_iterator_get_postfix
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- spl_dual_it_gets_implemented
- spl_dual_it_get_method
- spl_dual_it_call_method
- spl_cit_check_flags
- spl_dual_it_construct
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- spl_dual_it_require
- spl_dual_it_free
- spl_dual_it_rewind
- spl_dual_it_valid
- spl_dual_it_fetch
- spl_dual_it_next
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- spl_filter_it_fetch
- spl_filter_it_rewind
- spl_filter_it_next
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- spl_dual_it_dtor
- spl_dual_it_free_storage
- spl_dual_it_new
- spl_limit_it_valid
- spl_limit_it_seek
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- spl_caching_it_valid
- spl_caching_it_has_next
- spl_caching_it_next
- spl_caching_it_rewind
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- spl_append_it_next_iterator
- spl_append_it_fetch
- spl_append_it_next
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- SPL_METHOD
- spl_iterator_apply
- spl_iterator_to_array_apply
- spl_iterator_to_values_apply
- PHP_FUNCTION
- spl_iterator_count_apply
- PHP_FUNCTION
- spl_iterator_func_apply
- PHP_FUNCTION
- PHP_MINIT_FUNCTION
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
24
25 #include "php.h"
26 #include "php_ini.h"
27 #include "ext/standard/info.h"
28 #include "zend_exceptions.h"
29 #include "zend_interfaces.h"
30
31 #include "php_spl.h"
32 #include "spl_functions.h"
33 #include "spl_engine.h"
34 #include "spl_iterators.h"
35 #include "spl_directory.h"
36 #include "spl_array.h"
37 #include "spl_exceptions.h"
38 #include "zend_smart_str.h"
39
40 #ifdef accept
41 #undef accept
42 #endif
43
44 PHPAPI zend_class_entry *spl_ce_RecursiveIterator;
45 PHPAPI zend_class_entry *spl_ce_RecursiveIteratorIterator;
46 PHPAPI zend_class_entry *spl_ce_FilterIterator;
47 PHPAPI zend_class_entry *spl_ce_CallbackFilterIterator;
48 PHPAPI zend_class_entry *spl_ce_RecursiveFilterIterator;
49 PHPAPI zend_class_entry *spl_ce_RecursiveCallbackFilterIterator;
50 PHPAPI zend_class_entry *spl_ce_ParentIterator;
51 PHPAPI zend_class_entry *spl_ce_SeekableIterator;
52 PHPAPI zend_class_entry *spl_ce_LimitIterator;
53 PHPAPI zend_class_entry *spl_ce_CachingIterator;
54 PHPAPI zend_class_entry *spl_ce_RecursiveCachingIterator;
55 PHPAPI zend_class_entry *spl_ce_OuterIterator;
56 PHPAPI zend_class_entry *spl_ce_IteratorIterator;
57 PHPAPI zend_class_entry *spl_ce_NoRewindIterator;
58 PHPAPI zend_class_entry *spl_ce_InfiniteIterator;
59 PHPAPI zend_class_entry *spl_ce_EmptyIterator;
60 PHPAPI zend_class_entry *spl_ce_AppendIterator;
61 PHPAPI zend_class_entry *spl_ce_RegexIterator;
62 PHPAPI zend_class_entry *spl_ce_RecursiveRegexIterator;
63 PHPAPI zend_class_entry *spl_ce_Countable;
64 PHPAPI zend_class_entry *spl_ce_RecursiveTreeIterator;
65
66 ZEND_BEGIN_ARG_INFO(arginfo_recursive_it_void, 0)
67 ZEND_END_ARG_INFO()
68
69 const zend_function_entry spl_funcs_RecursiveIterator[] = {
70 SPL_ABSTRACT_ME(RecursiveIterator, hasChildren, arginfo_recursive_it_void)
71 SPL_ABSTRACT_ME(RecursiveIterator, getChildren, arginfo_recursive_it_void)
72 PHP_FE_END
73 };
74
75 typedef enum {
76 RIT_LEAVES_ONLY = 0,
77 RIT_SELF_FIRST = 1,
78 RIT_CHILD_FIRST = 2
79 } RecursiveIteratorMode;
80
81 #define RIT_CATCH_GET_CHILD CIT_CATCH_GET_CHILD
82
83 typedef enum {
84 RTIT_BYPASS_CURRENT = 4,
85 RTIT_BYPASS_KEY = 8
86 } RecursiveTreeIteratorFlags;
87
88 typedef enum {
89 RS_NEXT = 0,
90 RS_TEST = 1,
91 RS_SELF = 2,
92 RS_CHILD = 3,
93 RS_START = 4
94 } RecursiveIteratorState;
95
96 typedef struct _spl_sub_iterator {
97 zend_object_iterator *iterator;
98 zval zobject;
99 zend_class_entry *ce;
100 RecursiveIteratorState state;
101 } spl_sub_iterator;
102
103 typedef struct _spl_recursive_it_object {
104 spl_sub_iterator *iterators;
105 int level;
106 RecursiveIteratorMode mode;
107 int flags;
108 int max_depth;
109 zend_bool in_iteration;
110 zend_function *beginIteration;
111 zend_function *endIteration;
112 zend_function *callHasChildren;
113 zend_function *callGetChildren;
114 zend_function *beginChildren;
115 zend_function *endChildren;
116 zend_function *nextElement;
117 zend_class_entry *ce;
118 smart_str prefix[6];
119 smart_str postfix[1];
120 zend_object std;
121 } spl_recursive_it_object;
122
123 typedef struct _spl_recursive_it_iterator {
124 zend_object_iterator intern;
125 } spl_recursive_it_iterator;
126
127 static zend_object_handlers spl_handlers_rec_it_it;
128 static zend_object_handlers spl_handlers_dual_it;
129
130 static inline spl_recursive_it_object *spl_recursive_it_from_obj(zend_object *obj) {
131 return (spl_recursive_it_object*)((char*)(obj) - XtOffsetOf(spl_recursive_it_object, std));
132 }
133
134
135 #define Z_SPLRECURSIVE_IT_P(zv) spl_recursive_it_from_obj(Z_OBJ_P((zv)))
136
137 #define SPL_FETCH_AND_CHECK_DUAL_IT(var, objzval) \
138 do { \
139 spl_dual_it_object *it = Z_SPLDUAL_IT_P(objzval); \
140 if (it->dit_type == DIT_Unknown) { \
141 zend_throw_exception_ex(spl_ce_LogicException, 0, \
142 "The object is in an invalid state as the parent constructor was not called"); \
143 return; \
144 } \
145 (var) = it; \
146 } while (0)
147
148 #define SPL_FETCH_SUB_ELEMENT(var, object, element) \
149 do { \
150 if(!(object)->iterators) { \
151 zend_throw_exception_ex(spl_ce_LogicException, 0, \
152 "The object is in an invalid state as the parent constructor was not called"); \
153 return; \
154 } \
155 (var) = (object)->iterators[(object)->level].element; \
156 } while (0)
157
158 #define SPL_FETCH_SUB_ELEMENT_ADDR(var, object, element) \
159 do { \
160 if(!(object)->iterators) { \
161 zend_throw_exception_ex(spl_ce_LogicException, 0, \
162 "The object is in an invalid state as the parent constructor was not called"); \
163 return; \
164 } \
165 (var) = &(object)->iterators[(object)->level].element; \
166 } while (0)
167
168 #define SPL_FETCH_SUB_ITERATOR(var, object) SPL_FETCH_SUB_ELEMENT(var, object, iterator)
169
170
171 static void spl_recursive_it_dtor(zend_object_iterator *_iter)
172 {
173 spl_recursive_it_iterator *iter = (spl_recursive_it_iterator*)_iter;
174 spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(&iter->intern.data);
175 zend_object_iterator *sub_iter;
176
177 while (object->level > 0) {
178 sub_iter = object->iterators[object->level].iterator;
179 zend_iterator_dtor(sub_iter);
180 zval_ptr_dtor(&object->iterators[object->level--].zobject);
181 }
182 object->iterators = erealloc(object->iterators, sizeof(spl_sub_iterator));
183 object->level = 0;
184
185 zval_ptr_dtor(&iter->intern.data);
186 }
187
188 static int spl_recursive_it_valid_ex(spl_recursive_it_object *object, zval *zthis)
189 {
190 zend_object_iterator *sub_iter;
191 int level = object->level;
192
193 if(!object->iterators) {
194 return FAILURE;
195 }
196 while (level >=0) {
197 sub_iter = object->iterators[level].iterator;
198 if (sub_iter->funcs->valid(sub_iter) == SUCCESS) {
199 return SUCCESS;
200 }
201 level--;
202 }
203 if (object->endIteration && object->in_iteration) {
204 zend_call_method_with_0_params(zthis, object->ce, &object->endIteration, "endIteration", NULL);
205 }
206 object->in_iteration = 0;
207 return FAILURE;
208 }
209
210 static int spl_recursive_it_valid(zend_object_iterator *iter)
211 {
212 return spl_recursive_it_valid_ex(Z_SPLRECURSIVE_IT_P(&iter->data), &iter->data);
213 }
214
215 static zval *spl_recursive_it_get_current_data(zend_object_iterator *iter)
216 {
217 spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(&iter->data);
218 zend_object_iterator *sub_iter = object->iterators[object->level].iterator;
219
220 return sub_iter->funcs->get_current_data(sub_iter);
221 }
222
223 static void spl_recursive_it_get_current_key(zend_object_iterator *iter, zval *key)
224 {
225 spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(&iter->data);
226 zend_object_iterator *sub_iter = object->iterators[object->level].iterator;
227
228 if (sub_iter->funcs->get_current_key) {
229 sub_iter->funcs->get_current_key(sub_iter, key);
230 } else {
231 ZVAL_LONG(key, iter->index);
232 }
233 }
234
235 static void spl_recursive_it_move_forward_ex(spl_recursive_it_object *object, zval *zthis)
236 {
237 zend_object_iterator *iterator;
238 zval *zobject;
239 zend_class_entry *ce;
240 zval retval, child;
241 zend_object_iterator *sub_iter;
242 int has_children;
243
244 SPL_FETCH_SUB_ITERATOR(iterator, object);
245
246 while (!EG(exception)) {
247 next_step:
248 iterator = object->iterators[object->level].iterator;
249 switch (object->iterators[object->level].state) {
250 case RS_NEXT:
251 iterator->funcs->move_forward(iterator);
252 if (EG(exception)) {
253 if (!(object->flags & RIT_CATCH_GET_CHILD)) {
254 return;
255 } else {
256 zend_clear_exception();
257 }
258 }
259
260 case RS_START:
261 if (iterator->funcs->valid(iterator) == FAILURE) {
262 break;
263 }
264 object->iterators[object->level].state = RS_TEST;
265
266 case RS_TEST:
267 ce = object->iterators[object->level].ce;
268 zobject = &object->iterators[object->level].zobject;
269 if (object->callHasChildren) {
270 zend_call_method_with_0_params(zthis, object->ce, &object->callHasChildren, "callHasChildren", &retval);
271 } else {
272 zend_call_method_with_0_params(zobject, ce, NULL, "haschildren", &retval);
273 }
274 if (EG(exception)) {
275 if (!(object->flags & RIT_CATCH_GET_CHILD)) {
276 object->iterators[object->level].state = RS_NEXT;
277 return;
278 } else {
279 zend_clear_exception();
280 }
281 }
282 if (Z_TYPE(retval) != IS_UNDEF) {
283 has_children = zend_is_true(&retval);
284 zval_ptr_dtor(&retval);
285 if (has_children) {
286 if (object->max_depth == -1 || object->max_depth > object->level) {
287 switch (object->mode) {
288 case RIT_LEAVES_ONLY:
289 case RIT_CHILD_FIRST:
290 object->iterators[object->level].state = RS_CHILD;
291 goto next_step;
292 case RIT_SELF_FIRST:
293 object->iterators[object->level].state = RS_SELF;
294 goto next_step;
295 }
296 } else {
297
298 if (object->mode == RIT_LEAVES_ONLY) {
299
300 object->iterators[object->level].state = RS_NEXT;
301 goto next_step;
302 }
303 }
304 }
305 }
306 if (object->nextElement) {
307 zend_call_method_with_0_params(zthis, object->ce, &object->nextElement, "nextelement", NULL);
308 }
309 object->iterators[object->level].state = RS_NEXT;
310 if (EG(exception)) {
311 if (!(object->flags & RIT_CATCH_GET_CHILD)) {
312 return;
313 } else {
314 zend_clear_exception();
315 }
316 }
317 return ;
318 case RS_SELF:
319 if (object->nextElement && (object->mode == RIT_SELF_FIRST || object->mode == RIT_CHILD_FIRST)) {
320 zend_call_method_with_0_params(zthis, object->ce, &object->nextElement, "nextelement", NULL);
321 }
322 if (object->mode == RIT_SELF_FIRST) {
323 object->iterators[object->level].state = RS_CHILD;
324 } else {
325 object->iterators[object->level].state = RS_NEXT;
326 }
327 return ;
328 case RS_CHILD:
329 ce = object->iterators[object->level].ce;
330 zobject = &object->iterators[object->level].zobject;
331 if (object->callGetChildren) {
332 zend_call_method_with_0_params(zthis, object->ce, &object->callGetChildren, "callGetChildren", &child);
333 } else {
334 zend_call_method_with_0_params(zobject, ce, NULL, "getchildren", &child);
335 }
336
337 if (EG(exception)) {
338 if (!(object->flags & RIT_CATCH_GET_CHILD)) {
339 return;
340 } else {
341 zend_clear_exception();
342 zval_ptr_dtor(&child);
343 object->iterators[object->level].state = RS_NEXT;
344 goto next_step;
345 }
346 }
347
348 if (Z_TYPE(child) == IS_UNDEF || Z_TYPE(child) != IS_OBJECT ||
349 !((ce = Z_OBJCE(child)) && instanceof_function(ce, spl_ce_RecursiveIterator))) {
350 zval_ptr_dtor(&child);
351 zend_throw_exception(spl_ce_UnexpectedValueException, "Objects returned by RecursiveIterator::getChildren() must implement RecursiveIterator", 0);
352 return;
353 }
354
355 if (object->mode == RIT_CHILD_FIRST) {
356 object->iterators[object->level].state = RS_SELF;
357 } else {
358 object->iterators[object->level].state = RS_NEXT;
359 }
360 object->iterators = erealloc(object->iterators, sizeof(spl_sub_iterator) * (++object->level+1));
361 sub_iter = ce->get_iterator(ce, &child, 0);
362 ZVAL_COPY_VALUE(&object->iterators[object->level].zobject, &child);
363 object->iterators[object->level].iterator = sub_iter;
364 object->iterators[object->level].ce = ce;
365 object->iterators[object->level].state = RS_START;
366 if (sub_iter->funcs->rewind) {
367 sub_iter->funcs->rewind(sub_iter);
368 }
369 if (object->beginChildren) {
370 zend_call_method_with_0_params(zthis, object->ce, &object->beginChildren, "beginchildren", NULL);
371 if (EG(exception)) {
372 if (!(object->flags & RIT_CATCH_GET_CHILD)) {
373 return;
374 } else {
375 zend_clear_exception();
376 }
377 }
378 }
379 goto next_step;
380 }
381
382 if (object->level > 0) {
383 if (object->endChildren) {
384 zend_call_method_with_0_params(zthis, object->ce, &object->endChildren, "endchildren", NULL);
385 if (EG(exception)) {
386 if (!(object->flags & RIT_CATCH_GET_CHILD)) {
387 return;
388 } else {
389 zend_clear_exception();
390 }
391 }
392 }
393 if (object->level > 0) {
394 zend_iterator_dtor(iterator);
395 zval_ptr_dtor(&object->iterators[object->level].zobject);
396 object->level--;
397 }
398 } else {
399 return;
400 }
401 }
402 }
403
404 static void spl_recursive_it_rewind_ex(spl_recursive_it_object *object, zval *zthis)
405 {
406 zend_object_iterator *sub_iter;
407
408 SPL_FETCH_SUB_ITERATOR(sub_iter, object);
409
410 while (object->level) {
411 sub_iter = object->iterators[object->level].iterator;
412 zend_iterator_dtor(sub_iter);
413 zval_ptr_dtor(&object->iterators[object->level--].zobject);
414 if (!EG(exception) && (!object->endChildren || object->endChildren->common.scope != spl_ce_RecursiveIteratorIterator)) {
415 zend_call_method_with_0_params(zthis, object->ce, &object->endChildren, "endchildren", NULL);
416 }
417 }
418 object->iterators = erealloc(object->iterators, sizeof(spl_sub_iterator));
419 object->iterators[0].state = RS_START;
420 sub_iter = object->iterators[0].iterator;
421 if (sub_iter->funcs->rewind) {
422 sub_iter->funcs->rewind(sub_iter);
423 }
424 if (!EG(exception) && object->beginIteration && !object->in_iteration) {
425 zend_call_method_with_0_params(zthis, object->ce, &object->beginIteration, "beginIteration", NULL);
426 }
427 object->in_iteration = 1;
428 spl_recursive_it_move_forward_ex(object, zthis);
429 }
430
431 static void spl_recursive_it_move_forward(zend_object_iterator *iter)
432 {
433 spl_recursive_it_move_forward_ex(Z_SPLRECURSIVE_IT_P(&iter->data), &iter->data);
434 }
435
436 static void spl_recursive_it_rewind(zend_object_iterator *iter)
437 {
438 spl_recursive_it_rewind_ex(Z_SPLRECURSIVE_IT_P(&iter->data), &iter->data);
439 }
440
441 static zend_object_iterator *spl_recursive_it_get_iterator(zend_class_entry *ce, zval *zobject, int by_ref)
442 {
443 spl_recursive_it_iterator *iterator;
444 spl_recursive_it_object *object;
445
446 if (by_ref) {
447 zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
448 }
449 iterator = emalloc(sizeof(spl_recursive_it_iterator));
450 object = Z_SPLRECURSIVE_IT_P(zobject);
451 if (object->iterators == NULL) {
452 zend_error(E_ERROR, "The object to be iterated is in an invalid state: "
453 "the parent constructor has not been called");
454 }
455
456 zend_iterator_init((zend_object_iterator*)iterator);
457
458 ZVAL_COPY(&iterator->intern.data, zobject);
459 iterator->intern.funcs = ce->iterator_funcs.funcs;
460 return (zend_object_iterator*)iterator;
461 }
462
463 zend_object_iterator_funcs spl_recursive_it_iterator_funcs = {
464 spl_recursive_it_dtor,
465 spl_recursive_it_valid,
466 spl_recursive_it_get_current_data,
467 spl_recursive_it_get_current_key,
468 spl_recursive_it_move_forward,
469 spl_recursive_it_rewind
470 };
471
472 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)
473 {
474 zval *object = getThis();
475 spl_recursive_it_object *intern;
476 zval *iterator;
477 zend_class_entry *ce_iterator;
478 zend_long mode, flags;
479 zend_error_handling error_handling;
480 zval caching_it, aggregate_retval;
481
482 zend_replace_error_handling(EH_THROW, spl_ce_InvalidArgumentException, &error_handling);
483
484 switch (rit_type) {
485 case RIT_RecursiveTreeIterator: {
486 zval caching_it_flags, *user_caching_it_flags = NULL;
487 mode = RIT_SELF_FIRST;
488 flags = RTIT_BYPASS_KEY;
489
490 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "o|lzl", &iterator, &flags, &user_caching_it_flags, &mode) == SUCCESS) {
491 if (instanceof_function(Z_OBJCE_P(iterator), zend_ce_aggregate)) {
492 zend_call_method_with_0_params(iterator, Z_OBJCE_P(iterator), &Z_OBJCE_P(iterator)->iterator_funcs.zf_new_iterator, "getiterator", &aggregate_retval);
493 iterator = &aggregate_retval;
494 } else {
495 Z_ADDREF_P(iterator);
496 }
497
498 if (user_caching_it_flags) {
499 ZVAL_COPY(&caching_it_flags, user_caching_it_flags);
500 } else {
501 ZVAL_LONG(&caching_it_flags, CIT_CATCH_GET_CHILD);
502 }
503 spl_instantiate_arg_ex2(spl_ce_RecursiveCachingIterator, &caching_it, iterator, &caching_it_flags);
504 zval_ptr_dtor(&caching_it_flags);
505
506 zval_ptr_dtor(iterator);
507 iterator = &caching_it;
508 } else {
509 iterator = NULL;
510 }
511 break;
512 }
513 case RIT_RecursiveIteratorIterator:
514 default: {
515 mode = RIT_LEAVES_ONLY;
516 flags = 0;
517
518 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "o|ll", &iterator, &mode, &flags) == SUCCESS) {
519 if (instanceof_function(Z_OBJCE_P(iterator), zend_ce_aggregate)) {
520 zend_call_method_with_0_params(iterator, Z_OBJCE_P(iterator), &Z_OBJCE_P(iterator)->iterator_funcs.zf_new_iterator, "getiterator", &aggregate_retval);
521 iterator = &aggregate_retval;
522 } else {
523 Z_ADDREF_P(iterator);
524 }
525 } else {
526 iterator = NULL;
527 }
528 break;
529 }
530 }
531 if (!iterator || !instanceof_function(Z_OBJCE_P(iterator), spl_ce_RecursiveIterator)) {
532 if (iterator) {
533 zval_ptr_dtor(iterator);
534 }
535 zend_throw_exception(spl_ce_InvalidArgumentException, "An instance of RecursiveIterator or IteratorAggregate creating it is required", 0);
536 zend_restore_error_handling(&error_handling);
537 return;
538 }
539
540 intern = Z_SPLRECURSIVE_IT_P(object);
541 intern->iterators = emalloc(sizeof(spl_sub_iterator));
542 intern->level = 0;
543 intern->mode = mode;
544 intern->flags = (int)flags;
545 intern->max_depth = -1;
546 intern->in_iteration = 0;
547 intern->ce = Z_OBJCE_P(object);
548
549 intern->beginIteration = zend_hash_str_find_ptr(&intern->ce->function_table, "beginiteration", sizeof("beginiteration") - 1);
550 if (intern->beginIteration->common.scope == ce_base) {
551 intern->beginIteration = NULL;
552 }
553 intern->endIteration = zend_hash_str_find_ptr(&intern->ce->function_table, "enditeration", sizeof("enditeration") - 1);
554 if (intern->endIteration->common.scope == ce_base) {
555 intern->endIteration = NULL;
556 }
557 intern->callHasChildren = zend_hash_str_find_ptr(&intern->ce->function_table, "callhaschildren", sizeof("callHasChildren") - 1);
558 if (intern->callHasChildren->common.scope == ce_base) {
559 intern->callHasChildren = NULL;
560 }
561 intern->callGetChildren = zend_hash_str_find_ptr(&intern->ce->function_table, "callgetchildren", sizeof("callGetChildren") - 1);
562 if (intern->callGetChildren->common.scope == ce_base) {
563 intern->callGetChildren = NULL;
564 }
565 intern->beginChildren = zend_hash_str_find_ptr(&intern->ce->function_table, "beginchildren", sizeof("beginchildren") - 1);
566 if (intern->beginChildren->common.scope == ce_base) {
567 intern->beginChildren = NULL;
568 }
569 intern->endChildren = zend_hash_str_find_ptr(&intern->ce->function_table, "endchildren", sizeof("endchildren") - 1);
570 if (intern->endChildren->common.scope == ce_base) {
571 intern->endChildren = NULL;
572 }
573 intern->nextElement = zend_hash_str_find_ptr(&intern->ce->function_table, "nextelement", sizeof("nextElement") - 1);
574 if (intern->nextElement->common.scope == ce_base) {
575 intern->nextElement = NULL;
576 }
577
578 ce_iterator = Z_OBJCE_P(iterator);
579 intern->iterators[0].iterator = ce_iterator->get_iterator(ce_iterator, iterator, 0);
580 ZVAL_COPY_VALUE(&intern->iterators[0].zobject, iterator);
581 intern->iterators[0].ce = ce_iterator;
582 intern->iterators[0].state = RS_START;
583
584 zend_restore_error_handling(&error_handling);
585
586 if (EG(exception)) {
587 zend_object_iterator *sub_iter;
588
589 while (intern->level >= 0) {
590 sub_iter = intern->iterators[intern->level].iterator;
591 zend_iterator_dtor(sub_iter);
592 zval_ptr_dtor(&intern->iterators[intern->level--].zobject);
593 }
594 efree(intern->iterators);
595 intern->iterators = NULL;
596 }
597 }
598
599
600
601 SPL_METHOD(RecursiveIteratorIterator, __construct)
602 {
603 spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveIteratorIterator, zend_ce_iterator, RIT_RecursiveIteratorIterator);
604 }
605
606
607
608 SPL_METHOD(RecursiveIteratorIterator, rewind)
609 {
610 spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(getThis());
611
612 if (zend_parse_parameters_none() == FAILURE) {
613 return;
614 }
615
616 spl_recursive_it_rewind_ex(object, getThis());
617 }
618
619
620
621 SPL_METHOD(RecursiveIteratorIterator, valid)
622 {
623 spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(getThis());
624
625 if (zend_parse_parameters_none() == FAILURE) {
626 return;
627 }
628
629 RETURN_BOOL(spl_recursive_it_valid_ex(object, getThis()) == SUCCESS);
630 }
631
632
633
634 SPL_METHOD(RecursiveIteratorIterator, key)
635 {
636 spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(getThis());
637 zend_object_iterator *iterator;
638
639 if (zend_parse_parameters_none() == FAILURE) {
640 return;
641 }
642
643 SPL_FETCH_SUB_ITERATOR(iterator, object);
644
645 if (iterator->funcs->get_current_key) {
646 iterator->funcs->get_current_key(iterator, return_value);
647 } else {
648 RETURN_NULL();
649 }
650 }
651
652
653
654 SPL_METHOD(RecursiveIteratorIterator, current)
655 {
656 spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(getThis());
657 zend_object_iterator *iterator;
658 zval *data;
659
660 if (zend_parse_parameters_none() == FAILURE) {
661 return;
662 }
663
664 SPL_FETCH_SUB_ITERATOR(iterator, object);
665
666 data = iterator->funcs->get_current_data(iterator);
667 if (data) {
668 ZVAL_DEREF(data);
669 ZVAL_COPY(return_value, data);
670 }
671 }
672
673
674
675 SPL_METHOD(RecursiveIteratorIterator, next)
676 {
677 spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(getThis());
678
679 if (zend_parse_parameters_none() == FAILURE) {
680 return;
681 }
682
683 spl_recursive_it_move_forward_ex(object, getThis());
684 }
685
686
687
688 SPL_METHOD(RecursiveIteratorIterator, getDepth)
689 {
690 spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(getThis());
691
692 if (zend_parse_parameters_none() == FAILURE) {
693 return;
694 }
695
696 RETURN_LONG(object->level);
697 }
698
699
700
701 SPL_METHOD(RecursiveIteratorIterator, getSubIterator)
702 {
703 spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(getThis());
704 zend_long level = object->level;
705 zval *value;
706
707 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &level) == FAILURE) {
708 return;
709 }
710 if (level < 0 || level > object->level) {
711 RETURN_NULL();
712 }
713
714 if(!object->iterators) {
715 zend_throw_exception_ex(spl_ce_LogicException, 0,
716 "The object is in an invalid state as the parent constructor was not called");
717 return;
718 }
719
720 value = &object->iterators[level].zobject;
721 ZVAL_DEREF(value);
722 ZVAL_COPY(return_value, value);
723 }
724
725
726
727 SPL_METHOD(RecursiveIteratorIterator, getInnerIterator)
728 {
729 spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(getThis());
730 zval *zobject;
731
732 if (zend_parse_parameters_none() == FAILURE) {
733 return;
734 }
735
736 SPL_FETCH_SUB_ELEMENT_ADDR(zobject, object, zobject);
737
738 ZVAL_DEREF(zobject);
739 ZVAL_COPY(return_value, zobject);
740 }
741
742
743
744 SPL_METHOD(RecursiveIteratorIterator, beginIteration)
745 {
746 if (zend_parse_parameters_none() == FAILURE) {
747 return;
748 }
749
750 }
751
752
753
754 SPL_METHOD(RecursiveIteratorIterator, endIteration)
755 {
756 if (zend_parse_parameters_none() == FAILURE) {
757 return;
758 }
759
760 }
761
762
763
764 SPL_METHOD(RecursiveIteratorIterator, callHasChildren)
765 {
766 spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(getThis());
767 zend_class_entry *ce;
768 zval *zobject;
769
770 if (zend_parse_parameters_none() == FAILURE) {
771 return;
772 }
773
774 if (!object->iterators) {
775 RETURN_NULL();
776 }
777
778 SPL_FETCH_SUB_ELEMENT(ce, object, ce);
779
780 zobject = &object->iterators[object->level].zobject;
781 if (Z_TYPE_P(zobject) == IS_UNDEF) {
782 RETURN_FALSE;
783 } else {
784 zend_call_method_with_0_params(zobject, ce, NULL, "haschildren", return_value);
785 if (Z_TYPE_P(return_value) == IS_UNDEF) {
786 RETURN_FALSE;
787 }
788 }
789 }
790
791
792
793 SPL_METHOD(RecursiveIteratorIterator, callGetChildren)
794 {
795 spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(getThis());
796 zend_class_entry *ce;
797 zval *zobject;
798
799 if (zend_parse_parameters_none() == FAILURE) {
800 return;
801 }
802
803 SPL_FETCH_SUB_ELEMENT(ce, object, ce);
804
805 zobject = &object->iterators[object->level].zobject;
806 if (Z_TYPE_P(zobject) == IS_UNDEF) {
807 return;
808 } else {
809 zend_call_method_with_0_params(zobject, ce, NULL, "getchildren", return_value);
810 if (Z_TYPE_P(return_value) == IS_UNDEF) {
811 RETURN_NULL();
812 }
813 }
814 }
815
816
817
818 SPL_METHOD(RecursiveIteratorIterator, beginChildren)
819 {
820 if (zend_parse_parameters_none() == FAILURE) {
821 return;
822 }
823
824 }
825
826
827
828 SPL_METHOD(RecursiveIteratorIterator, endChildren)
829 {
830 if (zend_parse_parameters_none() == FAILURE) {
831 return;
832 }
833
834 }
835
836
837
838 SPL_METHOD(RecursiveIteratorIterator, nextElement)
839 {
840 if (zend_parse_parameters_none() == FAILURE) {
841 return;
842 }
843
844 }
845
846
847
848 SPL_METHOD(RecursiveIteratorIterator, setMaxDepth)
849 {
850 spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(getThis());
851 zend_long max_depth = -1;
852
853 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &max_depth) == FAILURE) {
854 return;
855 }
856 if (max_depth < -1) {
857 zend_throw_exception(spl_ce_OutOfRangeException, "Parameter max_depth must be >= -1", 0);
858 return;
859 } else if (max_depth > INT_MAX) {
860 max_depth = INT_MAX;
861 }
862
863 object->max_depth = (int)max_depth;
864 }
865
866
867
868 SPL_METHOD(RecursiveIteratorIterator, getMaxDepth)
869 {
870 spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(getThis());
871
872 if (zend_parse_parameters_none() == FAILURE) {
873 return;
874 }
875
876 if (object->max_depth == -1) {
877 RETURN_FALSE;
878 } else {
879 RETURN_LONG(object->max_depth);
880 }
881 }
882
883 static union _zend_function *spl_recursive_it_get_method(zend_object **zobject, zend_string *method, const zval *key)
884 {
885 union _zend_function *function_handler;
886 spl_recursive_it_object *object = spl_recursive_it_from_obj(*zobject);
887 zend_long level = object->level;
888 zval *zobj;
889
890 if (!object->iterators) {
891 php_error_docref(NULL, E_ERROR, "The %s instance wasn't initialized properly", ZSTR_VAL((*zobject)->ce->name));
892 }
893 zobj = &object->iterators[level].zobject;
894
895 function_handler = std_object_handlers.get_method(zobject, method, key);
896 if (!function_handler) {
897 if ((function_handler = zend_hash_find_ptr(&Z_OBJCE_P(zobj)->function_table, method)) == NULL) {
898 if (Z_OBJ_HT_P(zobj)->get_method) {
899 *zobject = Z_OBJ_P(zobj);
900 function_handler = (*zobject)->handlers->get_method(zobject, method, key);
901 }
902 } else {
903 *zobject = Z_OBJ_P(zobj);
904 }
905 }
906 return function_handler;
907 }
908
909
910 static void spl_RecursiveIteratorIterator_dtor(zend_object *_object)
911 {
912 spl_recursive_it_object *object = spl_recursive_it_from_obj(_object);
913 zend_object_iterator *sub_iter;
914
915
916 zend_objects_destroy_object(_object);
917
918 if (object->iterators) {
919 while (object->level >= 0) {
920 sub_iter = object->iterators[object->level].iterator;
921 zend_iterator_dtor(sub_iter);
922 zval_ptr_dtor(&object->iterators[object->level--].zobject);
923 }
924 efree(object->iterators);
925 object->iterators = NULL;
926 }
927 }
928
929
930
931 static void spl_RecursiveIteratorIterator_free_storage(zend_object *_object)
932 {
933 spl_recursive_it_object *object = spl_recursive_it_from_obj(_object);
934
935 if (object->iterators) {
936 efree(object->iterators);
937 object->iterators = NULL;
938 }
939
940 zend_object_std_dtor(&object->std);
941 smart_str_free(&object->prefix[0]);
942 smart_str_free(&object->prefix[1]);
943 smart_str_free(&object->prefix[2]);
944 smart_str_free(&object->prefix[3]);
945 smart_str_free(&object->prefix[4]);
946 smart_str_free(&object->prefix[5]);
947
948 smart_str_free(&object->postfix[0]);
949 }
950
951
952
953 static zend_object *spl_RecursiveIteratorIterator_new_ex(zend_class_entry *class_type, int init_prefix)
954 {
955 spl_recursive_it_object *intern;
956
957 intern = ecalloc(1, sizeof(spl_recursive_it_object) + zend_object_properties_size(class_type));
958
959 if (init_prefix) {
960 smart_str_appendl(&intern->prefix[0], "", 0);
961 smart_str_appendl(&intern->prefix[1], "| ", 2);
962 smart_str_appendl(&intern->prefix[2], " ", 2);
963 smart_str_appendl(&intern->prefix[3], "|-", 2);
964 smart_str_appendl(&intern->prefix[4], "\\-", 2);
965 smart_str_appendl(&intern->prefix[5], "", 0);
966
967 smart_str_appendl(&intern->postfix[0], "", 0);
968 }
969
970 zend_object_std_init(&intern->std, class_type);
971 object_properties_init(&intern->std, class_type);
972
973 intern->std.handlers = &spl_handlers_rec_it_it;
974 return &intern->std;
975 }
976
977
978
979 static zend_object *spl_RecursiveIteratorIterator_new(zend_class_entry *class_type)
980 {
981 return spl_RecursiveIteratorIterator_new_ex(class_type, 0);
982 }
983
984
985
986 static zend_object *spl_RecursiveTreeIterator_new(zend_class_entry *class_type)
987 {
988 return spl_RecursiveIteratorIterator_new_ex(class_type, 1);
989 }
990
991
992 ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_it___construct, 0, 0, 1)
993 ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0)
994 ZEND_ARG_INFO(0, mode)
995 ZEND_ARG_INFO(0, flags)
996 ZEND_END_ARG_INFO();
997
998 ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_it_getSubIterator, 0, 0, 0)
999 ZEND_ARG_INFO(0, level)
1000 ZEND_END_ARG_INFO();
1001
1002 ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_it_setMaxDepth, 0, 0, 0)
1003 ZEND_ARG_INFO(0, max_depth)
1004 ZEND_END_ARG_INFO();
1005
1006 static const zend_function_entry spl_funcs_RecursiveIteratorIterator[] = {
1007 SPL_ME(RecursiveIteratorIterator, __construct, arginfo_recursive_it___construct, ZEND_ACC_PUBLIC)
1008 SPL_ME(RecursiveIteratorIterator, rewind, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
1009 SPL_ME(RecursiveIteratorIterator, valid, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
1010 SPL_ME(RecursiveIteratorIterator, key, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
1011 SPL_ME(RecursiveIteratorIterator, current, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
1012 SPL_ME(RecursiveIteratorIterator, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
1013 SPL_ME(RecursiveIteratorIterator, getDepth, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
1014 SPL_ME(RecursiveIteratorIterator, getSubIterator, arginfo_recursive_it_getSubIterator, ZEND_ACC_PUBLIC)
1015 SPL_ME(RecursiveIteratorIterator, getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
1016 SPL_ME(RecursiveIteratorIterator, beginIteration, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
1017 SPL_ME(RecursiveIteratorIterator, endIteration, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
1018 SPL_ME(RecursiveIteratorIterator, callHasChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
1019 SPL_ME(RecursiveIteratorIterator, callGetChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
1020 SPL_ME(RecursiveIteratorIterator, beginChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
1021 SPL_ME(RecursiveIteratorIterator, endChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
1022 SPL_ME(RecursiveIteratorIterator, nextElement, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
1023 SPL_ME(RecursiveIteratorIterator, setMaxDepth, arginfo_recursive_it_setMaxDepth, ZEND_ACC_PUBLIC)
1024 SPL_ME(RecursiveIteratorIterator, getMaxDepth, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
1025 PHP_FE_END
1026 };
1027
1028 static void spl_recursive_tree_iterator_get_prefix(spl_recursive_it_object *object, zval *return_value)
1029 {
1030 smart_str str = {0};
1031 zval has_next;
1032 int level;
1033
1034 smart_str_appendl(&str, ZSTR_VAL(object->prefix[0].s), ZSTR_LEN(object->prefix[0].s));
1035
1036 for (level = 0; level < object->level; ++level) {
1037 zend_call_method_with_0_params(&object->iterators[level].zobject, object->iterators[level].ce, NULL, "hasnext", &has_next);
1038 if (Z_TYPE(has_next) != IS_UNDEF) {
1039 if (Z_TYPE(has_next) == IS_TRUE) {
1040 smart_str_appendl(&str, ZSTR_VAL(object->prefix[1].s), ZSTR_LEN(object->prefix[1].s));
1041 } else {
1042 smart_str_appendl(&str, ZSTR_VAL(object->prefix[2].s), ZSTR_LEN(object->prefix[2].s));
1043 }
1044 zval_ptr_dtor(&has_next);
1045 }
1046 }
1047 zend_call_method_with_0_params(&object->iterators[level].zobject, object->iterators[level].ce, NULL, "hasnext", &has_next);
1048 if (Z_TYPE(has_next) != IS_UNDEF) {
1049 if (Z_TYPE(has_next) == IS_TRUE) {
1050 smart_str_appendl(&str, ZSTR_VAL(object->prefix[3].s), ZSTR_LEN(object->prefix[3].s));
1051 } else {
1052 smart_str_appendl(&str, ZSTR_VAL(object->prefix[4].s), ZSTR_LEN(object->prefix[4].s));
1053 }
1054 zval_ptr_dtor(&has_next);
1055 }
1056
1057 smart_str_appendl(&str, ZSTR_VAL(object->prefix[5].s), ZSTR_LEN(object->prefix[5].s));
1058 smart_str_0(&str);
1059
1060 RETURN_NEW_STR(str.s);
1061 }
1062
1063 static void spl_recursive_tree_iterator_get_entry(spl_recursive_it_object *object, zval *return_value)
1064 {
1065 zend_object_iterator *iterator = object->iterators[object->level].iterator;
1066 zval *data;
1067 zend_error_handling error_handling;
1068
1069 data = iterator->funcs->get_current_data(iterator);
1070
1071
1072
1073 zend_replace_error_handling(EH_THROW, spl_ce_UnexpectedValueException, &error_handling);
1074 if (data) {
1075 ZVAL_DEREF(data);
1076 if (Z_TYPE_P(data) == IS_ARRAY) {
1077 ZVAL_STRINGL(return_value, "Array", sizeof("Array")-1);
1078 } else {
1079 ZVAL_COPY(return_value, data);
1080 convert_to_string(return_value);
1081 }
1082 }
1083 zend_restore_error_handling(&error_handling);
1084 }
1085
1086 static void spl_recursive_tree_iterator_get_postfix(spl_recursive_it_object *object, zval *return_value)
1087 {
1088 RETVAL_STR(object->postfix[0].s);
1089 Z_ADDREF_P(return_value);
1090 }
1091
1092
1093
1094 SPL_METHOD(RecursiveTreeIterator, __construct)
1095 {
1096 spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveTreeIterator, zend_ce_iterator, RIT_RecursiveTreeIterator);
1097 }
1098
1099
1100
1101 SPL_METHOD(RecursiveTreeIterator, setPrefixPart)
1102 {
1103 zend_long part;
1104 char* prefix;
1105 size_t prefix_len;
1106 spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(getThis());
1107
1108 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ls", &part, &prefix, &prefix_len) == FAILURE) {
1109 return;
1110 }
1111
1112 if (0 > part || part > 5) {
1113 zend_throw_exception_ex(spl_ce_OutOfRangeException, 0, "Use RecursiveTreeIterator::PREFIX_* constant");
1114 return;
1115 }
1116
1117 smart_str_free(&object->prefix[part]);
1118 smart_str_appendl(&object->prefix[part], prefix, prefix_len);
1119 }
1120
1121
1122
1123 SPL_METHOD(RecursiveTreeIterator, getPrefix)
1124 {
1125 spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(getThis());
1126
1127 if (zend_parse_parameters_none() == FAILURE) {
1128 return;
1129 }
1130
1131 if(!object->iterators) {
1132 zend_throw_exception_ex(spl_ce_LogicException, 0,
1133 "The object is in an invalid state as the parent constructor was not called");
1134 return;
1135 }
1136
1137 spl_recursive_tree_iterator_get_prefix(object, return_value);
1138 }
1139
1140
1141
1142 SPL_METHOD(RecursiveTreeIterator, setPostfix)
1143 {
1144 spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(getThis());
1145 char* postfix;
1146 size_t postfix_len;
1147
1148 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &postfix, &postfix_len) == FAILURE) {
1149 return;
1150 }
1151
1152 smart_str_free(&object->postfix[0]);
1153 smart_str_appendl(&object->postfix[0], postfix, postfix_len);
1154 }
1155
1156
1157
1158 SPL_METHOD(RecursiveTreeIterator, getEntry)
1159 {
1160 spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(getThis());
1161
1162 if (zend_parse_parameters_none() == FAILURE) {
1163 return;
1164 }
1165
1166 if(!object->iterators) {
1167 zend_throw_exception_ex(spl_ce_LogicException, 0,
1168 "The object is in an invalid state as the parent constructor was not called");
1169 return;
1170 }
1171
1172 spl_recursive_tree_iterator_get_entry(object, return_value);
1173 }
1174
1175
1176
1177 SPL_METHOD(RecursiveTreeIterator, getPostfix)
1178 {
1179 spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(getThis());
1180
1181 if (zend_parse_parameters_none() == FAILURE) {
1182 return;
1183 }
1184
1185 if(!object->iterators) {
1186 zend_throw_exception_ex(spl_ce_LogicException, 0,
1187 "The object is in an invalid state as the parent constructor was not called");
1188 return;
1189 }
1190
1191 spl_recursive_tree_iterator_get_postfix(object, return_value);
1192 }
1193
1194
1195
1196 SPL_METHOD(RecursiveTreeIterator, current)
1197 {
1198 spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(getThis());
1199 zval prefix, entry, postfix;
1200 char *ptr;
1201 zend_string *str;
1202
1203 if (zend_parse_parameters_none() == FAILURE) {
1204 return;
1205 }
1206
1207 if(!object->iterators) {
1208 zend_throw_exception_ex(spl_ce_LogicException, 0,
1209 "The object is in an invalid state as the parent constructor was not called");
1210 return;
1211 }
1212
1213 if (object->flags & RTIT_BYPASS_CURRENT) {
1214 zend_object_iterator *iterator = object->iterators[object->level].iterator;
1215 zval *data;
1216
1217 SPL_FETCH_SUB_ITERATOR(iterator, object);
1218 data = iterator->funcs->get_current_data(iterator);
1219 if (data) {
1220 ZVAL_DEREF(data);
1221 ZVAL_COPY(return_value, data);
1222 return;
1223 } else {
1224 RETURN_NULL();
1225 }
1226 }
1227
1228 ZVAL_NULL(&prefix);
1229 ZVAL_NULL(&entry);
1230 spl_recursive_tree_iterator_get_prefix(object, &prefix);
1231 spl_recursive_tree_iterator_get_entry(object, &entry);
1232 if (Z_TYPE(entry) != IS_STRING) {
1233 zval_ptr_dtor(&prefix);
1234 zval_ptr_dtor(&entry);
1235 RETURN_NULL();
1236 }
1237 spl_recursive_tree_iterator_get_postfix(object, &postfix);
1238
1239 str = zend_string_alloc(Z_STRLEN(prefix) + Z_STRLEN(entry) + Z_STRLEN(postfix), 0);
1240 ptr = ZSTR_VAL(str);
1241
1242 memcpy(ptr, Z_STRVAL(prefix), Z_STRLEN(prefix));
1243 ptr += Z_STRLEN(prefix);
1244 memcpy(ptr, Z_STRVAL(entry), Z_STRLEN(entry));
1245 ptr += Z_STRLEN(entry);
1246 memcpy(ptr, Z_STRVAL(postfix), Z_STRLEN(postfix));
1247 ptr += Z_STRLEN(postfix);
1248 *ptr = 0;
1249
1250 zval_ptr_dtor(&prefix);
1251 zval_ptr_dtor(&entry);
1252 zval_ptr_dtor(&postfix);
1253
1254 RETURN_NEW_STR(str);
1255 }
1256
1257
1258
1259 SPL_METHOD(RecursiveTreeIterator, key)
1260 {
1261 spl_recursive_it_object *object = Z_SPLRECURSIVE_IT_P(getThis());
1262 zend_object_iterator *iterator;
1263 zval prefix, key, postfix, key_copy;
1264 char *ptr;
1265 zend_string *str;
1266
1267 if (zend_parse_parameters_none() == FAILURE) {
1268 return;
1269 }
1270
1271 SPL_FETCH_SUB_ITERATOR(iterator, object);
1272
1273 if (iterator->funcs->get_current_key) {
1274 iterator->funcs->get_current_key(iterator, &key);
1275 } else {
1276 ZVAL_NULL(&key);
1277 }
1278
1279 if (object->flags & RTIT_BYPASS_KEY) {
1280 RETVAL_ZVAL(&key, 1, 1);
1281 return;
1282 }
1283
1284 if (Z_TYPE(key) != IS_STRING) {
1285 if (zend_make_printable_zval(&key, &key_copy)) {
1286 key = key_copy;
1287 }
1288 }
1289
1290 spl_recursive_tree_iterator_get_prefix(object, &prefix);
1291 spl_recursive_tree_iterator_get_postfix(object, &postfix);
1292
1293 str = zend_string_alloc(Z_STRLEN(prefix) + Z_STRLEN(key) + Z_STRLEN(postfix), 0);
1294 ptr = ZSTR_VAL(str);
1295
1296 memcpy(ptr, Z_STRVAL(prefix), Z_STRLEN(prefix));
1297 ptr += Z_STRLEN(prefix);
1298 memcpy(ptr, Z_STRVAL(key), Z_STRLEN(key));
1299 ptr += Z_STRLEN(key);
1300 memcpy(ptr, Z_STRVAL(postfix), Z_STRLEN(postfix));
1301 ptr += Z_STRLEN(postfix);
1302 *ptr = 0;
1303
1304 zval_ptr_dtor(&prefix);
1305 zval_ptr_dtor(&key);
1306 zval_ptr_dtor(&postfix);
1307
1308 RETURN_NEW_STR(str);
1309 }
1310
1311 ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_tree_it___construct, 0, 0, 1)
1312 ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0)
1313 ZEND_ARG_INFO(0, flags)
1314 ZEND_ARG_INFO(0, caching_it_flags)
1315 ZEND_ARG_INFO(0, mode)
1316 ZEND_END_ARG_INFO();
1317
1318 ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_tree_it_setPrefixPart, 0, 0, 2)
1319 ZEND_ARG_INFO(0, part)
1320 ZEND_ARG_INFO(0, value)
1321 ZEND_END_ARG_INFO();
1322
1323 static const zend_function_entry spl_funcs_RecursiveTreeIterator[] = {
1324 SPL_ME(RecursiveTreeIterator, __construct, arginfo_recursive_tree_it___construct, ZEND_ACC_PUBLIC)
1325 SPL_ME(RecursiveIteratorIterator, rewind, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
1326 SPL_ME(RecursiveIteratorIterator, valid, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
1327 SPL_ME(RecursiveTreeIterator, key, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
1328 SPL_ME(RecursiveTreeIterator, current, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
1329 SPL_ME(RecursiveIteratorIterator, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
1330 SPL_ME(RecursiveIteratorIterator, beginIteration, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
1331 SPL_ME(RecursiveIteratorIterator, endIteration, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
1332 SPL_ME(RecursiveIteratorIterator, callHasChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
1333 SPL_ME(RecursiveIteratorIterator, callGetChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
1334 SPL_ME(RecursiveIteratorIterator, beginChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
1335 SPL_ME(RecursiveIteratorIterator, endChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
1336 SPL_ME(RecursiveIteratorIterator, nextElement, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
1337 SPL_ME(RecursiveTreeIterator, getPrefix, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
1338 SPL_ME(RecursiveTreeIterator, setPrefixPart, arginfo_recursive_tree_it_setPrefixPart, ZEND_ACC_PUBLIC)
1339 SPL_ME(RecursiveTreeIterator, getEntry, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
1340 SPL_ME(RecursiveTreeIterator, setPostfix, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
1341 SPL_ME(RecursiveTreeIterator, getPostfix, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
1342 PHP_FE_END
1343 };
1344
1345 #if MBO_0
1346 static int spl_dual_it_gets_implemented(zend_class_entry *interface, zend_class_entry *class_type)
1347 {
1348 class_type->iterator_funcs.zf_valid = NULL;
1349 class_type->iterator_funcs.zf_current = NULL;
1350 class_type->iterator_funcs.zf_key = NULL;
1351 class_type->iterator_funcs.zf_next = NULL;
1352 class_type->iterator_funcs.zf_rewind = NULL;
1353 if (!class_type->iterator_funcs.funcs) {
1354 class_type->iterator_funcs.funcs = &zend_interface_iterator_funcs_iterator;
1355 }
1356
1357 return SUCCESS;
1358 }
1359 #endif
1360
1361 static union _zend_function *spl_dual_it_get_method(zend_object **object, zend_string *method, const zval *key)
1362 {
1363 union _zend_function *function_handler;
1364 spl_dual_it_object *intern;
1365
1366 intern = spl_dual_it_from_obj(*object);
1367
1368 function_handler = std_object_handlers.get_method(object, method, key);
1369 if (!function_handler && intern->inner.ce) {
1370 if ((function_handler = zend_hash_find_ptr(&intern->inner.ce->function_table, method)) == NULL) {
1371 if (Z_OBJ_HT(intern->inner.zobject)->get_method) {
1372 *object = Z_OBJ(intern->inner.zobject);
1373 function_handler = (*object)->handlers->get_method(object, method, key);
1374 }
1375 } else {
1376 *object = Z_OBJ(intern->inner.zobject);
1377 }
1378 }
1379 return function_handler;
1380 }
1381
1382 #if MBO_0
1383 int spl_dual_it_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS)
1384 {
1385 zval ***func_params, func;
1386 zval retval;
1387 int arg_count;
1388 int current = 0;
1389 int success;
1390 void **p;
1391 spl_dual_it_object *intern;
1392
1393 intern = Z_SPLDUAL_IT_P(getThis());
1394
1395 ZVAL_STRING(&func, method, 0);
1396 if (!zend_is_callable(&func, 0, &method)) {
1397 php_error_docref(NULL, E_ERROR, "Method %s::%s() does not exist", intern->inner.ce->name, method);
1398 return FAILURE;
1399 }
1400
1401 p = EG(argument_stack).top_element-2;
1402 arg_count = (zend_ulong) *p;
1403
1404 func_params = safe_emalloc(sizeof(zval **), arg_count, 0);
1405
1406 current = 0;
1407 while (arg_count-- > 0) {
1408 func_params[current] = (zval **) p - (arg_count-current);
1409 current++;
1410 }
1411 arg_count = current;
1412
1413 if (call_user_function_ex(EG(function_table), NULL, &func, &retval, arg_count, func_params, 0, NULL) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
1414 RETURN_ZVAL(&retval, 0, 0);
1415
1416 success = SUCCESS;
1417 } else {
1418 php_error_docref(NULL, E_ERROR, "Unable to call %s::%s()", intern->inner.ce->name, method);
1419 success = FAILURE;
1420 }
1421
1422 efree(func_params);
1423 return success;
1424 }
1425 #endif
1426
1427 #define SPL_CHECK_CTOR(intern, classname) \
1428 if (intern->dit_type == DIT_Unknown) { \
1429 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Classes derived from %s must call %s::__construct()", \
1430 ZSTR_VAL((spl_ce_##classname)->name), ZSTR_VAL((spl_ce_##classname)->name)); \
1431 return; \
1432 }
1433
1434 #define APPENDIT_CHECK_CTOR(intern) SPL_CHECK_CTOR(intern, AppendIterator)
1435
1436 static inline int spl_dual_it_fetch(spl_dual_it_object *intern, int check_more);
1437
1438 static inline int spl_cit_check_flags(zend_long flags)
1439 {
1440 zend_long cnt = 0;
1441
1442 cnt += (flags & CIT_CALL_TOSTRING) ? 1 : 0;
1443 cnt += (flags & CIT_TOSTRING_USE_KEY) ? 1 : 0;
1444 cnt += (flags & CIT_TOSTRING_USE_CURRENT) ? 1 : 0;
1445 cnt += (flags & CIT_TOSTRING_USE_INNER) ? 1 : 0;
1446
1447 return cnt <= 1 ? SUCCESS : FAILURE;
1448 }
1449
1450 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)
1451 {
1452 zval *zobject, retval;
1453 spl_dual_it_object *intern;
1454 zend_class_entry *ce = NULL;
1455 int inc_refcount = 1;
1456 zend_error_handling error_handling;
1457
1458 intern = Z_SPLDUAL_IT_P(getThis());
1459
1460 if (intern->dit_type != DIT_Unknown) {
1461 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s::getIterator() must be called exactly once per instance", ZSTR_VAL(ce_base->name));
1462 return NULL;
1463 }
1464
1465 intern->dit_type = dit_type;
1466 switch (dit_type) {
1467 case DIT_LimitIterator: {
1468 intern->u.limit.offset = 0;
1469 intern->u.limit.count = -1;
1470 if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "O|ll", &zobject, ce_inner, &intern->u.limit.offset, &intern->u.limit.count) == FAILURE) {
1471 return NULL;
1472 }
1473 if (intern->u.limit.offset < 0) {
1474 zend_throw_exception(spl_ce_OutOfRangeException, "Parameter offset must be >= 0", 0);
1475 return NULL;
1476 }
1477 if (intern->u.limit.count < 0 && intern->u.limit.count != -1) {
1478 zend_throw_exception(spl_ce_OutOfRangeException, "Parameter count must either be -1 or a value greater than or equal 0", 0);
1479 return NULL;
1480 }
1481 break;
1482 }
1483 case DIT_CachingIterator:
1484 case DIT_RecursiveCachingIterator: {
1485 zend_long flags = CIT_CALL_TOSTRING;
1486 if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "O|l", &zobject, ce_inner, &flags) == FAILURE) {
1487 return NULL;
1488 }
1489 if (spl_cit_check_flags(flags) != SUCCESS) {
1490 zend_throw_exception(spl_ce_InvalidArgumentException, "Flags must contain only one of CALL_TOSTRING, TOSTRING_USE_KEY, TOSTRING_USE_CURRENT, TOSTRING_USE_INNER", 0);
1491 return NULL;
1492 }
1493 intern->u.caching.flags |= flags & CIT_PUBLIC;
1494 array_init(&intern->u.caching.zcache);
1495 break;
1496 }
1497 case DIT_IteratorIterator: {
1498 zend_class_entry *ce_cast;
1499 zend_string *class_name;
1500
1501 if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "O|S", &zobject, ce_inner, &class_name) == FAILURE) {
1502 return NULL;
1503 }
1504 ce = Z_OBJCE_P(zobject);
1505 if (!instanceof_function(ce, zend_ce_iterator)) {
1506 if (ZEND_NUM_ARGS() > 1) {
1507 if (!(ce_cast = zend_lookup_class(class_name))
1508 || !instanceof_function(ce, ce_cast)
1509 || !ce_cast->get_iterator
1510 ) {
1511 zend_throw_exception(spl_ce_LogicException, "Class to downcast to not found or not base class or does not implement Traversable", 0);
1512 return NULL;
1513 }
1514 ce = ce_cast;
1515 }
1516 if (instanceof_function(ce, zend_ce_aggregate)) {
1517 zend_call_method_with_0_params(zobject, ce, &ce->iterator_funcs.zf_new_iterator, "getiterator", &retval);
1518 if (EG(exception)) {
1519 zval_ptr_dtor(&retval);
1520 return NULL;
1521 }
1522 if (Z_TYPE(retval) != IS_OBJECT || !instanceof_function(Z_OBJCE(retval), zend_ce_traversable)) {
1523 zend_throw_exception_ex(spl_ce_LogicException, 0, "%s::getIterator() must return an object that implements Traversable", ZSTR_VAL(ce->name));
1524 return NULL;
1525 }
1526 zobject = &retval;
1527 ce = Z_OBJCE_P(zobject);
1528 inc_refcount = 0;
1529 }
1530 }
1531 break;
1532 }
1533 case DIT_AppendIterator:
1534 zend_replace_error_handling(EH_THROW, spl_ce_InvalidArgumentException, &error_handling);
1535 spl_instantiate(spl_ce_ArrayIterator, &intern->u.append.zarrayit);
1536 zend_call_method_with_0_params(&intern->u.append.zarrayit, spl_ce_ArrayIterator, &spl_ce_ArrayIterator->constructor, "__construct", NULL);
1537 intern->u.append.iterator = spl_ce_ArrayIterator->get_iterator(spl_ce_ArrayIterator, &intern->u.append.zarrayit, 0);
1538 zend_restore_error_handling(&error_handling);
1539 return intern;
1540 #if HAVE_PCRE || HAVE_BUNDLED_PCRE
1541 case DIT_RegexIterator:
1542 case DIT_RecursiveRegexIterator: {
1543 zend_string *regex;
1544 zend_long mode = REGIT_MODE_MATCH;
1545
1546 intern->u.regex.use_flags = ZEND_NUM_ARGS() >= 5;
1547 intern->u.regex.flags = 0;
1548 intern->u.regex.preg_flags = 0;
1549 if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "OS|lll", &zobject, ce_inner, ®ex, &mode, &intern->u.regex.flags, &intern->u.regex.preg_flags) == FAILURE) {
1550 return NULL;
1551 }
1552 if (mode < 0 || mode >= REGIT_MODE_MAX) {
1553 zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "Illegal mode %pd", mode);
1554 return NULL;
1555 }
1556 intern->u.regex.mode = mode;
1557 intern->u.regex.regex = zend_string_copy(regex);
1558
1559 zend_replace_error_handling(EH_THROW, spl_ce_InvalidArgumentException, &error_handling);
1560 intern->u.regex.pce = pcre_get_compiled_regex_cache(regex);
1561 zend_restore_error_handling(&error_handling);
1562
1563 if (intern->u.regex.pce == NULL) {
1564
1565 return NULL;
1566 }
1567 intern->u.regex.pce->refcount++;
1568 break;
1569 }
1570 #endif
1571 case DIT_CallbackFilterIterator:
1572 case DIT_RecursiveCallbackFilterIterator: {
1573 _spl_cbfilter_it_intern *cfi = emalloc(sizeof(*cfi));
1574 cfi->fci.object = NULL;
1575 if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "Of", &zobject, ce_inner, &cfi->fci, &cfi->fcc) == FAILURE) {
1576 efree(cfi);
1577 return NULL;
1578 }
1579 if (Z_REFCOUNTED_P(&cfi->fci.function_name)) {
1580 Z_ADDREF(cfi->fci.function_name);
1581 }
1582 cfi->object = cfi->fcc.object;
1583 if (cfi->object) GC_REFCOUNT(cfi->object)++;
1584 intern->u.cbfilter = cfi;
1585 break;
1586 }
1587 default:
1588 if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "O", &zobject, ce_inner) == FAILURE) {
1589 return NULL;
1590 }
1591 break;
1592 }
1593
1594 if (inc_refcount) {
1595 ZVAL_COPY(&intern->inner.zobject, zobject);
1596 } else {
1597 ZVAL_COPY_VALUE(&intern->inner.zobject, zobject);
1598 }
1599
1600 intern->inner.ce = dit_type == DIT_IteratorIterator ? ce : Z_OBJCE_P(zobject);
1601 intern->inner.object = Z_OBJ_P(zobject);
1602 intern->inner.iterator = intern->inner.ce->get_iterator(intern->inner.ce, zobject, 0);
1603
1604 return intern;
1605 }
1606
1607
1608
1609 SPL_METHOD(FilterIterator, __construct)
1610 {
1611 spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_FilterIterator, zend_ce_iterator, DIT_FilterIterator);
1612 }
1613
1614
1615
1616 SPL_METHOD(CallbackFilterIterator, __construct)
1617 {
1618 spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_CallbackFilterIterator, zend_ce_iterator, DIT_CallbackFilterIterator);
1619 }
1620
1621
1622
1623
1624
1625
1626 SPL_METHOD(dual_it, getInnerIterator)
1627 {
1628 spl_dual_it_object *intern;
1629
1630 if (zend_parse_parameters_none() == FAILURE) {
1631 return;
1632 }
1633
1634 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
1635
1636 if (!Z_ISUNDEF(intern->inner.zobject)) {
1637 zval *value = &intern->inner.zobject;
1638
1639 ZVAL_DEREF(value);
1640 ZVAL_COPY(return_value, value);
1641 } else {
1642 RETURN_NULL();
1643 }
1644 }
1645
1646 static inline void spl_dual_it_require(spl_dual_it_object *intern)
1647 {
1648 if (!intern->inner.iterator) {
1649 php_error_docref(NULL, E_ERROR, "The inner constructor wasn't initialized with an iterator instance");
1650 }
1651 }
1652
1653 static inline void spl_dual_it_free(spl_dual_it_object *intern)
1654 {
1655 if (intern->inner.iterator && intern->inner.iterator->funcs->invalidate_current) {
1656 intern->inner.iterator->funcs->invalidate_current(intern->inner.iterator);
1657 }
1658 if (Z_TYPE(intern->current.data) != IS_UNDEF) {
1659 zval_ptr_dtor(&intern->current.data);
1660 ZVAL_UNDEF(&intern->current.data);
1661 }
1662 if (Z_TYPE(intern->current.key) != IS_UNDEF) {
1663 zval_ptr_dtor(&intern->current.key);
1664 ZVAL_UNDEF(&intern->current.key);
1665 }
1666 if (intern->dit_type == DIT_CachingIterator || intern->dit_type == DIT_RecursiveCachingIterator) {
1667 if (Z_TYPE(intern->u.caching.zstr) != IS_UNDEF) {
1668 zval_ptr_dtor(&intern->u.caching.zstr);
1669 ZVAL_UNDEF(&intern->u.caching.zstr);
1670 }
1671 if (Z_TYPE(intern->u.caching.zchildren) != IS_UNDEF) {
1672 zval_ptr_dtor(&intern->u.caching.zchildren);
1673 ZVAL_UNDEF(&intern->u.caching.zchildren);
1674 }
1675 }
1676 }
1677
1678 static inline void spl_dual_it_rewind(spl_dual_it_object *intern)
1679 {
1680 spl_dual_it_free(intern);
1681 intern->current.pos = 0;
1682 if (intern->inner.iterator->funcs->rewind) {
1683 intern->inner.iterator->funcs->rewind(intern->inner.iterator);
1684 }
1685 }
1686
1687 static inline int spl_dual_it_valid(spl_dual_it_object *intern)
1688 {
1689 if (!intern->inner.iterator) {
1690 return FAILURE;
1691 }
1692
1693 return intern->inner.iterator->funcs->valid(intern->inner.iterator);
1694 }
1695
1696 static inline int spl_dual_it_fetch(spl_dual_it_object *intern, int check_more)
1697 {
1698 zval *data;
1699
1700 spl_dual_it_free(intern);
1701 if (!check_more || spl_dual_it_valid(intern) == SUCCESS) {
1702 data = intern->inner.iterator->funcs->get_current_data(intern->inner.iterator);
1703 if (data) {
1704 ZVAL_COPY(&intern->current.data, data);
1705 }
1706
1707 if (intern->inner.iterator->funcs->get_current_key) {
1708 intern->inner.iterator->funcs->get_current_key(intern->inner.iterator, &intern->current.key);
1709 if (EG(exception)) {
1710 zval_ptr_dtor(&intern->current.key);
1711 ZVAL_UNDEF(&intern->current.key);
1712 }
1713 } else {
1714 ZVAL_LONG(&intern->current.key, intern->current.pos);
1715 }
1716 return EG(exception) ? FAILURE : SUCCESS;
1717 }
1718 return FAILURE;
1719 }
1720
1721 static inline void spl_dual_it_next(spl_dual_it_object *intern, int do_free)
1722 {
1723 if (do_free) {
1724 spl_dual_it_free(intern);
1725 } else {
1726 spl_dual_it_require(intern);
1727 }
1728 intern->inner.iterator->funcs->move_forward(intern->inner.iterator);
1729 intern->current.pos++;
1730 }
1731
1732
1733
1734
1735
1736 SPL_METHOD(dual_it, rewind)
1737 {
1738 spl_dual_it_object *intern;
1739
1740 if (zend_parse_parameters_none() == FAILURE) {
1741 return;
1742 }
1743
1744 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
1745
1746 spl_dual_it_rewind(intern);
1747 spl_dual_it_fetch(intern, 1);
1748 }
1749
1750
1751
1752
1753
1754
1755 SPL_METHOD(dual_it, valid)
1756 {
1757 spl_dual_it_object *intern;
1758
1759 if (zend_parse_parameters_none() == FAILURE) {
1760 return;
1761 }
1762
1763 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
1764
1765 RETURN_BOOL(Z_TYPE(intern->current.data) != IS_UNDEF);
1766 }
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776 SPL_METHOD(dual_it, key)
1777 {
1778 spl_dual_it_object *intern;
1779
1780 if (zend_parse_parameters_none() == FAILURE) {
1781 return;
1782 }
1783
1784 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
1785
1786 if (Z_TYPE(intern->current.key) != IS_UNDEF) {
1787 zval *value = &intern->current.key;
1788
1789 ZVAL_DEREF(value);
1790 ZVAL_COPY(return_value, value);
1791 } else {
1792 RETURN_NULL();
1793 }
1794 }
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804 SPL_METHOD(dual_it, current)
1805 {
1806 spl_dual_it_object *intern;
1807
1808 if (zend_parse_parameters_none() == FAILURE) {
1809 return;
1810 }
1811
1812 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
1813
1814 if (Z_TYPE(intern->current.data) != IS_UNDEF) {
1815 zval *value = &intern->current.data;
1816
1817 ZVAL_DEREF(value);
1818 ZVAL_COPY(return_value, value);
1819 } else {
1820 RETURN_NULL();
1821 }
1822 }
1823
1824
1825
1826
1827
1828 SPL_METHOD(dual_it, next)
1829 {
1830 spl_dual_it_object *intern;
1831
1832 if (zend_parse_parameters_none() == FAILURE) {
1833 return;
1834 }
1835
1836 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
1837
1838 spl_dual_it_next(intern, 1);
1839 spl_dual_it_fetch(intern, 1);
1840 }
1841
1842 static inline void spl_filter_it_fetch(zval *zthis, spl_dual_it_object *intern)
1843 {
1844 zval retval;
1845
1846 while (spl_dual_it_fetch(intern, 1) == SUCCESS) {
1847 zend_call_method_with_0_params(zthis, intern->std.ce, NULL, "accept", &retval);
1848 if (Z_TYPE(retval) != IS_UNDEF) {
1849 if (zend_is_true(&retval)) {
1850 zval_ptr_dtor(&retval);
1851 return;
1852 }
1853 zval_ptr_dtor(&retval);
1854 }
1855 if (EG(exception)) {
1856 return;
1857 }
1858 intern->inner.iterator->funcs->move_forward(intern->inner.iterator);
1859 }
1860 spl_dual_it_free(intern);
1861 }
1862
1863 static inline void spl_filter_it_rewind(zval *zthis, spl_dual_it_object *intern)
1864 {
1865 spl_dual_it_rewind(intern);
1866 spl_filter_it_fetch(zthis, intern);
1867 }
1868
1869 static inline void spl_filter_it_next(zval *zthis, spl_dual_it_object *intern)
1870 {
1871 spl_dual_it_next(intern, 1);
1872 spl_filter_it_fetch(zthis, intern);
1873 }
1874
1875
1876
1877 SPL_METHOD(FilterIterator, rewind)
1878 {
1879 spl_dual_it_object *intern;
1880
1881 if (zend_parse_parameters_none() == FAILURE) {
1882 return;
1883 }
1884
1885 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
1886 spl_filter_it_rewind(getThis(), intern);
1887 }
1888
1889
1890
1891 SPL_METHOD(FilterIterator, next)
1892 {
1893 spl_dual_it_object *intern;
1894
1895 if (zend_parse_parameters_none() == FAILURE) {
1896 return;
1897 }
1898
1899 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
1900 spl_filter_it_next(getThis(), intern);
1901 }
1902
1903
1904
1905 SPL_METHOD(RecursiveCallbackFilterIterator, __construct)
1906 {
1907 spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveCallbackFilterIterator, spl_ce_RecursiveIterator, DIT_RecursiveCallbackFilterIterator);
1908 }
1909
1910
1911
1912
1913 SPL_METHOD(RecursiveFilterIterator, __construct)
1914 {
1915 spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveFilterIterator, spl_ce_RecursiveIterator, DIT_RecursiveFilterIterator);
1916 }
1917
1918
1919
1920 SPL_METHOD(RecursiveFilterIterator, hasChildren)
1921 {
1922 spl_dual_it_object *intern;
1923 zval retval;
1924
1925 if (zend_parse_parameters_none() == FAILURE) {
1926 return;
1927 }
1928
1929 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
1930
1931 zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "haschildren", &retval);
1932 if (Z_TYPE(retval) != IS_UNDEF) {
1933 RETURN_ZVAL(&retval, 0, 1);
1934 } else {
1935 RETURN_FALSE;
1936 }
1937 }
1938
1939
1940
1941 SPL_METHOD(RecursiveFilterIterator, getChildren)
1942 {
1943 spl_dual_it_object *intern;
1944 zval retval;
1945
1946 if (zend_parse_parameters_none() == FAILURE) {
1947 return;
1948 }
1949
1950 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
1951
1952 zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &retval);
1953 if (!EG(exception) && Z_TYPE(retval) != IS_UNDEF) {
1954 spl_instantiate_arg_ex1(Z_OBJCE_P(getThis()), return_value, &retval);
1955 }
1956 zval_ptr_dtor(&retval);
1957 }
1958
1959
1960
1961 SPL_METHOD(RecursiveCallbackFilterIterator, getChildren)
1962 {
1963 spl_dual_it_object *intern;
1964 zval retval;
1965
1966 if (zend_parse_parameters_none() == FAILURE) {
1967 return;
1968 }
1969
1970 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
1971
1972 zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &retval);
1973 if (!EG(exception) && Z_TYPE(retval) != IS_UNDEF) {
1974 spl_instantiate_arg_ex2(Z_OBJCE_P(getThis()), return_value, &retval, &intern->u.cbfilter->fci.function_name);
1975 }
1976 zval_ptr_dtor(&retval);
1977 }
1978
1979
1980 SPL_METHOD(ParentIterator, __construct)
1981 {
1982 spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_ParentIterator, spl_ce_RecursiveIterator, DIT_ParentIterator);
1983 }
1984
1985 #if HAVE_PCRE || HAVE_BUNDLED_PCRE
1986
1987
1988 SPL_METHOD(RegexIterator, __construct)
1989 {
1990 spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RegexIterator, zend_ce_iterator, DIT_RegexIterator);
1991 }
1992
1993
1994
1995 SPL_METHOD(CallbackFilterIterator, accept)
1996 {
1997 spl_dual_it_object *intern = Z_SPLDUAL_IT_P(getThis());
1998 zend_fcall_info *fci = &intern->u.cbfilter->fci;
1999 zend_fcall_info_cache *fcc = &intern->u.cbfilter->fcc;
2000 zval params[3];
2001 zval result;
2002
2003 if (zend_parse_parameters_none() == FAILURE) {
2004 return;
2005 }
2006
2007 if (Z_TYPE(intern->current.data) == IS_UNDEF || Z_TYPE(intern->current.key) == IS_UNDEF) {
2008 RETURN_FALSE;
2009 }
2010
2011 ZVAL_COPY_VALUE(¶ms[0], &intern->current.data);
2012 ZVAL_COPY_VALUE(¶ms[1], &intern->current.key);
2013 ZVAL_COPY_VALUE(¶ms[2], &intern->inner.zobject);
2014
2015 fci->retval = &result;
2016 fci->param_count = 3;
2017 fci->params = params;
2018 fci->no_separation = 0;
2019
2020 if (zend_call_function(fci, fcc) != SUCCESS || Z_TYPE(result) == IS_UNDEF) {
2021 RETURN_FALSE;
2022 }
2023 if (EG(exception)) {
2024 return;
2025 }
2026
2027 RETURN_ZVAL(&result, 1, 1);
2028 }
2029
2030
2031
2032
2033 SPL_METHOD(RegexIterator, accept)
2034 {
2035 spl_dual_it_object *intern;
2036 zend_string *result, *subject;
2037 int count = 0;
2038 zval zcount, *replacement, tmp_replacement, rv;
2039
2040 if (zend_parse_parameters_none() == FAILURE) {
2041 return;
2042 }
2043
2044 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2045
2046 if (Z_TYPE(intern->current.data) == IS_UNDEF) {
2047 RETURN_FALSE;
2048 } else if (Z_TYPE(intern->current.data) == IS_ARRAY) {
2049 RETURN_FALSE;
2050 }
2051
2052 if (intern->u.regex.flags & REGIT_USE_KEY) {
2053 subject = zval_get_string(&intern->current.key);
2054 } else {
2055 subject = zval_get_string(&intern->current.data);
2056 }
2057
2058 switch (intern->u.regex.mode)
2059 {
2060 case REGIT_MODE_MAX:
2061 case REGIT_MODE_MATCH:
2062 #ifdef PCRE_EXTRA_MARK
2063 if (intern->u.regex.pce->extra) {
2064 intern->u.regex.pce->extra->flags &= ~PCRE_EXTRA_MARK;
2065 }
2066 #endif
2067 count = pcre_exec(intern->u.regex.pce->re, intern->u.regex.pce->extra, ZSTR_VAL(subject), ZSTR_LEN(subject), 0, 0, NULL, 0);
2068 RETVAL_BOOL(count >= 0);
2069 break;
2070
2071 case REGIT_MODE_ALL_MATCHES:
2072 case REGIT_MODE_GET_MATCH:
2073 zval_ptr_dtor(&intern->current.data);
2074 ZVAL_UNDEF(&intern->current.data);
2075 php_pcre_match_impl(intern->u.regex.pce, ZSTR_VAL(subject), ZSTR_LEN(subject), &zcount,
2076 &intern->current.data, intern->u.regex.mode == REGIT_MODE_ALL_MATCHES, intern->u.regex.use_flags, intern->u.regex.preg_flags, 0);
2077 RETVAL_BOOL(Z_LVAL(zcount) > 0);
2078 break;
2079
2080 case REGIT_MODE_SPLIT:
2081 zval_ptr_dtor(&intern->current.data);
2082 ZVAL_UNDEF(&intern->current.data);
2083 php_pcre_split_impl(intern->u.regex.pce, ZSTR_VAL(subject), ZSTR_LEN(subject), &intern->current.data, -1, intern->u.regex.preg_flags);
2084 count = zend_hash_num_elements(Z_ARRVAL(intern->current.data));
2085 RETVAL_BOOL(count > 1);
2086 break;
2087
2088 case REGIT_MODE_REPLACE:
2089 replacement = zend_read_property(intern->std.ce, getThis(), "replacement", sizeof("replacement")-1, 1, &rv);
2090 if (Z_TYPE_P(replacement) != IS_STRING) {
2091 ZVAL_COPY(&tmp_replacement, replacement);
2092 convert_to_string(&tmp_replacement);
2093 replacement = &tmp_replacement;
2094 }
2095 result = php_pcre_replace_impl(intern->u.regex.pce, subject, ZSTR_VAL(subject), ZSTR_LEN(subject), replacement, 0, -1, &count);
2096
2097 if (intern->u.regex.flags & REGIT_USE_KEY) {
2098 zval_ptr_dtor(&intern->current.key);
2099 ZVAL_STR(&intern->current.key, result);
2100 } else {
2101 zval_ptr_dtor(&intern->current.data);
2102 ZVAL_STR(&intern->current.data, result);
2103 }
2104
2105 if (replacement == &tmp_replacement) {
2106 zval_ptr_dtor(replacement);
2107 }
2108 RETVAL_BOOL(count > 0);
2109 }
2110
2111 if (intern->u.regex.flags & REGIT_INVERTED) {
2112 RETVAL_BOOL(Z_TYPE_P(return_value) != IS_TRUE);
2113 }
2114 zend_string_release(subject);
2115 }
2116
2117
2118
2119 SPL_METHOD(RegexIterator, getRegex)
2120 {
2121 spl_dual_it_object *intern = Z_SPLDUAL_IT_P(getThis());
2122
2123 if (zend_parse_parameters_none() == FAILURE) {
2124 return;
2125 }
2126
2127 RETURN_STR_COPY(intern->u.regex.regex);
2128 }
2129
2130
2131
2132 SPL_METHOD(RegexIterator, getMode)
2133 {
2134 spl_dual_it_object *intern;
2135
2136 if (zend_parse_parameters_none() == FAILURE) {
2137 return;
2138 }
2139
2140 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2141
2142 RETURN_LONG(intern->u.regex.mode);
2143 }
2144
2145
2146
2147 SPL_METHOD(RegexIterator, setMode)
2148 {
2149 spl_dual_it_object *intern;
2150 zend_long mode;
2151
2152 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &mode) == FAILURE) {
2153 return;
2154 }
2155
2156 if (mode < 0 || mode >= REGIT_MODE_MAX) {
2157 zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "Illegal mode %pd", mode);
2158 return;
2159 }
2160
2161 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2162
2163 intern->u.regex.mode = mode;
2164 }
2165
2166
2167
2168 SPL_METHOD(RegexIterator, getFlags)
2169 {
2170 spl_dual_it_object *intern;
2171
2172 if (zend_parse_parameters_none() == FAILURE) {
2173 return;
2174 }
2175
2176 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2177
2178 RETURN_LONG(intern->u.regex.flags);
2179 }
2180
2181
2182
2183 SPL_METHOD(RegexIterator, setFlags)
2184 {
2185 spl_dual_it_object *intern;
2186 zend_long flags;
2187
2188 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &flags) == FAILURE) {
2189 return;
2190 }
2191
2192 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2193
2194 intern->u.regex.flags = flags;
2195 }
2196
2197
2198
2199 SPL_METHOD(RegexIterator, getPregFlags)
2200 {
2201 spl_dual_it_object *intern;
2202
2203 if (zend_parse_parameters_none() == FAILURE) {
2204 return;
2205 }
2206
2207 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2208
2209 if (intern->u.regex.use_flags) {
2210 RETURN_LONG(intern->u.regex.preg_flags);
2211 } else {
2212 return;
2213 }
2214 }
2215
2216
2217
2218 SPL_METHOD(RegexIterator, setPregFlags)
2219 {
2220 spl_dual_it_object *intern;
2221 zend_long preg_flags;
2222
2223 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &preg_flags) == FAILURE) {
2224 return;
2225 }
2226
2227 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2228
2229 intern->u.regex.preg_flags = preg_flags;
2230 intern->u.regex.use_flags = 1;
2231 }
2232
2233
2234
2235 SPL_METHOD(RecursiveRegexIterator, __construct)
2236 {
2237 spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveRegexIterator, spl_ce_RecursiveIterator, DIT_RecursiveRegexIterator);
2238 }
2239
2240
2241
2242 SPL_METHOD(RecursiveRegexIterator, getChildren)
2243 {
2244 spl_dual_it_object *intern;
2245 zval retval;
2246
2247 if (zend_parse_parameters_none() == FAILURE) {
2248 return;
2249 }
2250
2251 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2252
2253 zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &retval);
2254 if (!EG(exception)) {
2255 zval args[5];
2256
2257 ZVAL_COPY(&args[0], &retval);
2258 ZVAL_STR_COPY(&args[1], intern->u.regex.regex);
2259 ZVAL_LONG(&args[2], intern->u.regex.mode);
2260 ZVAL_LONG(&args[3], intern->u.regex.flags);
2261 ZVAL_LONG(&args[4], intern->u.regex.preg_flags);
2262
2263 spl_instantiate_arg_n(Z_OBJCE_P(getThis()), return_value, 5, args);
2264
2265 zval_ptr_dtor(&args[0]);
2266 zval_ptr_dtor(&args[1]);
2267 }
2268 zval_ptr_dtor(&retval);
2269 }
2270
2271 SPL_METHOD(RecursiveRegexIterator, accept)
2272 {
2273 spl_dual_it_object *intern;
2274
2275 if (zend_parse_parameters_none() == FAILURE) {
2276 return;
2277 }
2278
2279 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2280
2281 if (Z_TYPE(intern->current.data) == IS_UNDEF) {
2282 RETURN_FALSE;
2283 } else if (Z_TYPE(intern->current.data) == IS_ARRAY) {
2284 RETURN_BOOL(zend_hash_num_elements(Z_ARRVAL(intern->current.data)) > 0);
2285 }
2286
2287 zend_call_method_with_0_params(getThis(), spl_ce_RegexIterator, NULL, "accept", return_value);
2288 }
2289
2290 #endif
2291
2292
2293 static void spl_dual_it_dtor(zend_object *_object)
2294 {
2295 spl_dual_it_object *object = spl_dual_it_from_obj(_object);
2296
2297
2298 zend_objects_destroy_object(_object);
2299
2300 spl_dual_it_free(object);
2301
2302 if (object->inner.iterator) {
2303 zend_iterator_dtor(object->inner.iterator);
2304 }
2305 }
2306
2307
2308
2309 static void spl_dual_it_free_storage(zend_object *_object)
2310 {
2311 spl_dual_it_object *object = spl_dual_it_from_obj(_object);
2312
2313
2314 if (!Z_ISUNDEF(object->inner.zobject)) {
2315 zval_ptr_dtor(&object->inner.zobject);
2316 }
2317
2318 if (object->dit_type == DIT_AppendIterator) {
2319 zend_iterator_dtor(object->u.append.iterator);
2320 if (Z_TYPE(object->u.append.zarrayit) != IS_UNDEF) {
2321 zval_ptr_dtor(&object->u.append.zarrayit);
2322 }
2323 }
2324
2325 if (object->dit_type == DIT_CachingIterator || object->dit_type == DIT_RecursiveCachingIterator) {
2326 zval_ptr_dtor(&object->u.caching.zcache);
2327 }
2328
2329 #if HAVE_PCRE || HAVE_BUNDLED_PCRE
2330 if (object->dit_type == DIT_RegexIterator || object->dit_type == DIT_RecursiveRegexIterator) {
2331 if (object->u.regex.pce) {
2332 object->u.regex.pce->refcount--;
2333 }
2334 if (object->u.regex.regex) {
2335 zend_string_release(object->u.regex.regex);
2336 }
2337 }
2338 #endif
2339
2340 if (object->dit_type == DIT_CallbackFilterIterator || object->dit_type == DIT_RecursiveCallbackFilterIterator) {
2341 if (object->u.cbfilter) {
2342 _spl_cbfilter_it_intern *cbfilter = object->u.cbfilter;
2343 object->u.cbfilter = NULL;
2344 zval_ptr_dtor(&cbfilter->fci.function_name);
2345 if (cbfilter->fci.object) {
2346 OBJ_RELEASE(cbfilter->fci.object);
2347 }
2348 efree(cbfilter);
2349 }
2350 }
2351
2352 zend_object_std_dtor(&object->std);
2353 }
2354
2355
2356
2357 static zend_object *spl_dual_it_new(zend_class_entry *class_type)
2358 {
2359 spl_dual_it_object *intern;
2360
2361 intern = ecalloc(1, sizeof(spl_dual_it_object) + zend_object_properties_size(class_type));
2362 intern->dit_type = DIT_Unknown;
2363
2364 zend_object_std_init(&intern->std, class_type);
2365 object_properties_init(&intern->std, class_type);
2366
2367 intern->std.handlers = &spl_handlers_dual_it;
2368 return &intern->std;
2369 }
2370
2371
2372 ZEND_BEGIN_ARG_INFO(arginfo_filter_it___construct, 0)
2373 ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
2374 ZEND_END_ARG_INFO();
2375
2376 static const zend_function_entry spl_funcs_FilterIterator[] = {
2377 SPL_ME(FilterIterator, __construct, arginfo_filter_it___construct, ZEND_ACC_PUBLIC)
2378 SPL_ME(FilterIterator, rewind, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2379 SPL_ME(dual_it, valid, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2380 SPL_ME(dual_it, key, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2381 SPL_ME(dual_it, current, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2382 SPL_ME(FilterIterator, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2383 SPL_ME(dual_it, getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2384 SPL_ABSTRACT_ME(FilterIterator, accept, arginfo_recursive_it_void)
2385 PHP_FE_END
2386 };
2387
2388 ZEND_BEGIN_ARG_INFO(arginfo_callback_filter_it___construct, 0)
2389 ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
2390 ZEND_ARG_INFO(0, callback)
2391 ZEND_END_ARG_INFO();
2392
2393 static const zend_function_entry spl_funcs_CallbackFilterIterator[] = {
2394 SPL_ME(CallbackFilterIterator, __construct, arginfo_callback_filter_it___construct, ZEND_ACC_PUBLIC)
2395 SPL_ME(CallbackFilterIterator, accept, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2396 PHP_FE_END
2397 };
2398
2399 ZEND_BEGIN_ARG_INFO(arginfo_recursive_callback_filter_it___construct, 0)
2400 ZEND_ARG_OBJ_INFO(0, iterator, RecursiveIterator, 0)
2401 ZEND_ARG_INFO(0, callback)
2402 ZEND_END_ARG_INFO();
2403
2404 static const zend_function_entry spl_funcs_RecursiveCallbackFilterIterator[] = {
2405 SPL_ME(RecursiveCallbackFilterIterator, __construct, arginfo_recursive_callback_filter_it___construct, ZEND_ACC_PUBLIC)
2406 SPL_ME(RecursiveFilterIterator, hasChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2407 SPL_ME(RecursiveCallbackFilterIterator, getChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2408 PHP_FE_END
2409 };
2410
2411 ZEND_BEGIN_ARG_INFO(arginfo_parent_it___construct, 0)
2412 ZEND_ARG_OBJ_INFO(0, iterator, RecursiveIterator, 0)
2413 ZEND_END_ARG_INFO();
2414
2415 static const zend_function_entry spl_funcs_RecursiveFilterIterator[] = {
2416 SPL_ME(RecursiveFilterIterator, __construct, arginfo_parent_it___construct, ZEND_ACC_PUBLIC)
2417 SPL_ME(RecursiveFilterIterator, hasChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2418 SPL_ME(RecursiveFilterIterator, getChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2419 PHP_FE_END
2420 };
2421
2422 static const zend_function_entry spl_funcs_ParentIterator[] = {
2423 SPL_ME(ParentIterator, __construct, arginfo_parent_it___construct, ZEND_ACC_PUBLIC)
2424 SPL_MA(ParentIterator, accept, RecursiveFilterIterator, hasChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2425 PHP_FE_END
2426 };
2427
2428 #if HAVE_PCRE || HAVE_BUNDLED_PCRE
2429 ZEND_BEGIN_ARG_INFO_EX(arginfo_regex_it___construct, 0, 0, 2)
2430 ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
2431 ZEND_ARG_INFO(0, regex)
2432 ZEND_ARG_INFO(0, mode)
2433 ZEND_ARG_INFO(0, flags)
2434 ZEND_ARG_INFO(0, preg_flags)
2435 ZEND_END_ARG_INFO();
2436
2437 ZEND_BEGIN_ARG_INFO_EX(arginfo_regex_it_set_mode, 0, 0, 1)
2438 ZEND_ARG_INFO(0, mode)
2439 ZEND_END_ARG_INFO();
2440
2441 ZEND_BEGIN_ARG_INFO_EX(arginfo_regex_it_set_flags, 0, 0, 1)
2442 ZEND_ARG_INFO(0, flags)
2443 ZEND_END_ARG_INFO();
2444
2445 ZEND_BEGIN_ARG_INFO_EX(arginfo_regex_it_set_preg_flags, 0, 0, 1)
2446 ZEND_ARG_INFO(0, preg_flags)
2447 ZEND_END_ARG_INFO();
2448
2449 static const zend_function_entry spl_funcs_RegexIterator[] = {
2450 SPL_ME(RegexIterator, __construct, arginfo_regex_it___construct, ZEND_ACC_PUBLIC)
2451 SPL_ME(RegexIterator, accept, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2452 SPL_ME(RegexIterator, getMode, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2453 SPL_ME(RegexIterator, setMode, arginfo_regex_it_set_mode, ZEND_ACC_PUBLIC)
2454 SPL_ME(RegexIterator, getFlags, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2455 SPL_ME(RegexIterator, setFlags, arginfo_regex_it_set_flags, ZEND_ACC_PUBLIC)
2456 SPL_ME(RegexIterator, getPregFlags, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2457 SPL_ME(RegexIterator, setPregFlags, arginfo_regex_it_set_preg_flags, ZEND_ACC_PUBLIC)
2458 SPL_ME(RegexIterator, getRegex, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2459 PHP_FE_END
2460 };
2461
2462 ZEND_BEGIN_ARG_INFO_EX(arginfo_rec_regex_it___construct, 0, 0, 2)
2463 ZEND_ARG_OBJ_INFO(0, iterator, RecursiveIterator, 0)
2464 ZEND_ARG_INFO(0, regex)
2465 ZEND_ARG_INFO(0, mode)
2466 ZEND_ARG_INFO(0, flags)
2467 ZEND_ARG_INFO(0, preg_flags)
2468 ZEND_END_ARG_INFO();
2469
2470 static const zend_function_entry spl_funcs_RecursiveRegexIterator[] = {
2471 SPL_ME(RecursiveRegexIterator, __construct, arginfo_rec_regex_it___construct, ZEND_ACC_PUBLIC)
2472 SPL_ME(RecursiveRegexIterator, accept, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2473 SPL_ME(RecursiveFilterIterator, hasChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2474 SPL_ME(RecursiveRegexIterator, getChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2475 PHP_FE_END
2476 };
2477 #endif
2478
2479 static inline int spl_limit_it_valid(spl_dual_it_object *intern)
2480 {
2481
2482 if (intern->u.limit.count != -1 && intern->current.pos >= intern->u.limit.offset + intern->u.limit.count) {
2483 return FAILURE;
2484 } else {
2485 return spl_dual_it_valid(intern);
2486 }
2487 }
2488
2489 static inline void spl_limit_it_seek(spl_dual_it_object *intern, zend_long pos)
2490 {
2491 zval zpos;
2492
2493 spl_dual_it_free(intern);
2494 if (pos < intern->u.limit.offset) {
2495 zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0, "Cannot seek to %pd which is below the offset %pd", pos, intern->u.limit.offset);
2496 return;
2497 }
2498 if (pos >= intern->u.limit.offset + intern->u.limit.count && intern->u.limit.count != -1) {
2499 zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0, "Cannot seek to %pd which is behind offset %pd plus count %pd", pos, intern->u.limit.offset, intern->u.limit.count);
2500 return;
2501 }
2502 if (pos != intern->current.pos && instanceof_function(intern->inner.ce, spl_ce_SeekableIterator)) {
2503 ZVAL_LONG(&zpos, pos);
2504 spl_dual_it_free(intern);
2505 zend_call_method_with_1_params(&intern->inner.zobject, intern->inner.ce, NULL, "seek", NULL, &zpos);
2506 zval_ptr_dtor(&zpos);
2507 if (!EG(exception)) {
2508 intern->current.pos = pos;
2509 if (spl_limit_it_valid(intern) == SUCCESS) {
2510 spl_dual_it_fetch(intern, 0);
2511 }
2512 }
2513 } else {
2514
2515
2516 if (pos < intern->current.pos) {
2517 spl_dual_it_rewind(intern);
2518 }
2519 while (pos > intern->current.pos && spl_dual_it_valid(intern) == SUCCESS) {
2520 spl_dual_it_next(intern, 1);
2521 }
2522 if (spl_dual_it_valid(intern) == SUCCESS) {
2523 spl_dual_it_fetch(intern, 1);
2524 }
2525 }
2526 }
2527
2528
2529
2530 SPL_METHOD(LimitIterator, __construct)
2531 {
2532 spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_LimitIterator, zend_ce_iterator, DIT_LimitIterator);
2533 }
2534
2535
2536
2537 SPL_METHOD(LimitIterator, rewind)
2538 {
2539 spl_dual_it_object *intern;
2540
2541 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2542 spl_dual_it_rewind(intern);
2543 spl_limit_it_seek(intern, intern->u.limit.offset);
2544 }
2545
2546
2547
2548 SPL_METHOD(LimitIterator, valid)
2549 {
2550 spl_dual_it_object *intern;
2551
2552 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2553
2554
2555 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);
2556 }
2557
2558
2559
2560 SPL_METHOD(LimitIterator, next)
2561 {
2562 spl_dual_it_object *intern;
2563
2564 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2565
2566 spl_dual_it_next(intern, 1);
2567 if (intern->u.limit.count == -1 || intern->current.pos < intern->u.limit.offset + intern->u.limit.count) {
2568 spl_dual_it_fetch(intern, 1);
2569 }
2570 }
2571
2572
2573
2574 SPL_METHOD(LimitIterator, seek)
2575 {
2576 spl_dual_it_object *intern;
2577 zend_long pos;
2578
2579 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &pos) == FAILURE) {
2580 return;
2581 }
2582
2583 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2584 spl_limit_it_seek(intern, pos);
2585 RETURN_LONG(intern->current.pos);
2586 }
2587
2588
2589
2590 SPL_METHOD(LimitIterator, getPosition)
2591 {
2592 spl_dual_it_object *intern;
2593 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2594 RETURN_LONG(intern->current.pos);
2595 }
2596
2597 ZEND_BEGIN_ARG_INFO(arginfo_seekable_it_seek, 0)
2598 ZEND_ARG_INFO(0, position)
2599 ZEND_END_ARG_INFO();
2600
2601 static const zend_function_entry spl_funcs_SeekableIterator[] = {
2602 SPL_ABSTRACT_ME(SeekableIterator, seek, arginfo_seekable_it_seek)
2603 PHP_FE_END
2604 };
2605
2606 ZEND_BEGIN_ARG_INFO_EX(arginfo_limit_it___construct, 0, 0, 1)
2607 ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
2608 ZEND_ARG_INFO(0, offset)
2609 ZEND_ARG_INFO(0, count)
2610 ZEND_END_ARG_INFO();
2611
2612 ZEND_BEGIN_ARG_INFO(arginfo_limit_it_seek, 0)
2613 ZEND_ARG_INFO(0, position)
2614 ZEND_END_ARG_INFO();
2615
2616 static const zend_function_entry spl_funcs_LimitIterator[] = {
2617 SPL_ME(LimitIterator, __construct, arginfo_limit_it___construct, ZEND_ACC_PUBLIC)
2618 SPL_ME(LimitIterator, rewind, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2619 SPL_ME(LimitIterator, valid, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2620 SPL_ME(dual_it, key, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2621 SPL_ME(dual_it, current, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2622 SPL_ME(LimitIterator, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2623 SPL_ME(LimitIterator, seek, arginfo_limit_it_seek, ZEND_ACC_PUBLIC)
2624 SPL_ME(LimitIterator, getPosition, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2625 SPL_ME(dual_it, getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2626 PHP_FE_END
2627 };
2628
2629 static inline int spl_caching_it_valid(spl_dual_it_object *intern)
2630 {
2631 return intern->u.caching.flags & CIT_VALID ? SUCCESS : FAILURE;
2632 }
2633
2634 static inline int spl_caching_it_has_next(spl_dual_it_object *intern)
2635 {
2636 return spl_dual_it_valid(intern);
2637 }
2638
2639 static inline void spl_caching_it_next(spl_dual_it_object *intern)
2640 {
2641 if (spl_dual_it_fetch(intern, 1) == SUCCESS) {
2642 intern->u.caching.flags |= CIT_VALID;
2643
2644 if (intern->u.caching.flags & CIT_FULL_CACHE) {
2645 zval *key = &intern->current.key;
2646 zval *data = &intern->current.data;
2647
2648 ZVAL_DEREF(data);
2649 Z_TRY_ADDREF_P(data);
2650 array_set_zval_key(Z_ARRVAL(intern->u.caching.zcache), key, data);
2651 zval_ptr_dtor(data);
2652 }
2653
2654 if (intern->dit_type == DIT_RecursiveCachingIterator) {
2655 zval retval, zchildren, zflags;
2656 zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "haschildren", &retval);
2657 if (EG(exception)) {
2658 zval_ptr_dtor(&retval);
2659 if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) {
2660 zend_clear_exception();
2661 } else {
2662 return;
2663 }
2664 } else {
2665 if (zend_is_true(&retval)) {
2666 zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &zchildren);
2667 if (EG(exception)) {
2668 zval_ptr_dtor(&zchildren);
2669 if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) {
2670 zend_clear_exception();
2671 } else {
2672 zval_ptr_dtor(&retval);
2673 return;
2674 }
2675 } else {
2676 ZVAL_LONG(&zflags, intern->u.caching.flags & CIT_PUBLIC);
2677 spl_instantiate_arg_ex2(spl_ce_RecursiveCachingIterator, &intern->u.caching.zchildren, &zchildren, &zflags);
2678 zval_ptr_dtor(&zchildren);
2679 }
2680 }
2681 zval_ptr_dtor(&retval);
2682 if (EG(exception)) {
2683 if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) {
2684 zend_clear_exception();
2685 } else {
2686 return;
2687 }
2688 }
2689 }
2690 }
2691 if (intern->u.caching.flags & (CIT_TOSTRING_USE_INNER|CIT_CALL_TOSTRING)) {
2692 int use_copy;
2693 zval expr_copy;
2694 if (intern->u.caching.flags & CIT_TOSTRING_USE_INNER) {
2695 ZVAL_COPY_VALUE(&intern->u.caching.zstr, &intern->inner.zobject);
2696 } else {
2697 ZVAL_COPY_VALUE(&intern->u.caching.zstr, &intern->current.data);
2698 }
2699 use_copy = zend_make_printable_zval(&intern->u.caching.zstr, &expr_copy);
2700 if (use_copy) {
2701 ZVAL_COPY_VALUE(&intern->u.caching.zstr, &expr_copy);
2702 } else if (Z_REFCOUNTED(intern->u.caching.zstr)) {
2703 Z_ADDREF(intern->u.caching.zstr);
2704 }
2705 }
2706 spl_dual_it_next(intern, 0);
2707 } else {
2708 intern->u.caching.flags &= ~CIT_VALID;
2709 }
2710 }
2711
2712 static inline void spl_caching_it_rewind(spl_dual_it_object *intern)
2713 {
2714 spl_dual_it_rewind(intern);
2715 zend_hash_clean(Z_ARRVAL(intern->u.caching.zcache));
2716 spl_caching_it_next(intern);
2717 }
2718
2719
2720
2721 SPL_METHOD(CachingIterator, __construct)
2722 {
2723 spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_CachingIterator, zend_ce_iterator, DIT_CachingIterator);
2724 }
2725
2726
2727
2728 SPL_METHOD(CachingIterator, rewind)
2729 {
2730 spl_dual_it_object *intern;
2731
2732 if (zend_parse_parameters_none() == FAILURE) {
2733 return;
2734 }
2735
2736 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2737
2738 spl_caching_it_rewind(intern);
2739 }
2740
2741
2742
2743 SPL_METHOD(CachingIterator, valid)
2744 {
2745 spl_dual_it_object *intern;
2746
2747 if (zend_parse_parameters_none() == FAILURE) {
2748 return;
2749 }
2750
2751 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2752
2753 RETURN_BOOL(spl_caching_it_valid(intern) == SUCCESS);
2754 }
2755
2756
2757
2758 SPL_METHOD(CachingIterator, next)
2759 {
2760 spl_dual_it_object *intern;
2761
2762 if (zend_parse_parameters_none() == FAILURE) {
2763 return;
2764 }
2765
2766 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2767
2768 spl_caching_it_next(intern);
2769 }
2770
2771
2772
2773 SPL_METHOD(CachingIterator, hasNext)
2774 {
2775 spl_dual_it_object *intern;
2776
2777 if (zend_parse_parameters_none() == FAILURE) {
2778 return;
2779 }
2780
2781 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2782
2783 RETURN_BOOL(spl_caching_it_has_next(intern) == SUCCESS);
2784 }
2785
2786
2787
2788 SPL_METHOD(CachingIterator, __toString)
2789 {
2790 spl_dual_it_object *intern;
2791
2792 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2793
2794 if (!(intern->u.caching.flags & (CIT_CALL_TOSTRING|CIT_TOSTRING_USE_KEY|CIT_TOSTRING_USE_CURRENT|CIT_TOSTRING_USE_INNER))) {
2795 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s does not fetch string value (see CachingIterator::__construct)", ZSTR_VAL(Z_OBJCE_P(getThis())->name));
2796 return;
2797 }
2798 if (intern->u.caching.flags & CIT_TOSTRING_USE_KEY) {
2799 ZVAL_COPY(return_value, &intern->current.key);
2800 convert_to_string(return_value);
2801 return;
2802 } else if (intern->u.caching.flags & CIT_TOSTRING_USE_CURRENT) {
2803 ZVAL_COPY(return_value, &intern->current.data);
2804 convert_to_string(return_value);
2805 return;
2806 }
2807 if (Z_TYPE(intern->u.caching.zstr) == IS_STRING) {
2808 RETURN_STR_COPY(Z_STR_P(&intern->u.caching.zstr));
2809 } else {
2810 RETURN_NULL();
2811 }
2812 }
2813
2814
2815
2816 SPL_METHOD(CachingIterator, offsetSet)
2817 {
2818 spl_dual_it_object *intern;
2819 zend_string *key;
2820 zval *value;
2821
2822 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2823
2824 if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
2825 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s does not use a full cache (see CachingIterator::__construct)", ZSTR_VAL(Z_OBJCE_P(getThis())->name));
2826 return;
2827 }
2828
2829 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sz", &key, &value) == FAILURE) {
2830 return;
2831 }
2832
2833 if (Z_REFCOUNTED_P(value)) {
2834 Z_ADDREF_P(value);
2835 }
2836 zend_symtable_update(Z_ARRVAL(intern->u.caching.zcache), key, value);
2837 }
2838
2839
2840
2841
2842 SPL_METHOD(CachingIterator, offsetGet)
2843 {
2844 spl_dual_it_object *intern;
2845 zend_string *key;
2846 zval *value;
2847
2848 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2849
2850 if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
2851 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s does not use a full cache (see CachingIterator::__construct)", ZSTR_VAL(Z_OBJCE_P(getThis())->name));
2852 return;
2853 }
2854
2855 if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &key) == FAILURE) {
2856 return;
2857 }
2858
2859 if ((value = zend_symtable_find(Z_ARRVAL(intern->u.caching.zcache), key)) == NULL) {
2860 zend_error(E_NOTICE, "Undefined index: %s", ZSTR_VAL(key));
2861 return;
2862 }
2863
2864 ZVAL_DEREF(value);
2865 ZVAL_COPY(return_value, value);
2866 }
2867
2868
2869
2870
2871 SPL_METHOD(CachingIterator, offsetUnset)
2872 {
2873 spl_dual_it_object *intern;
2874 zend_string *key;
2875
2876 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2877
2878 if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
2879 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s does not use a full cache (see CachingIterator::__construct)", ZSTR_VAL(Z_OBJCE_P(getThis())->name));
2880 return;
2881 }
2882
2883 if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &key) == FAILURE) {
2884 return;
2885 }
2886
2887 zend_symtable_del(Z_ARRVAL(intern->u.caching.zcache), key);
2888 }
2889
2890
2891
2892
2893 SPL_METHOD(CachingIterator, offsetExists)
2894 {
2895 spl_dual_it_object *intern;
2896 zend_string *key;
2897
2898 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2899
2900 if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
2901 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s does not use a full cache (see CachingIterator::__construct)", ZSTR_VAL(Z_OBJCE_P(getThis())->name));
2902 return;
2903 }
2904
2905 if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &key) == FAILURE) {
2906 return;
2907 }
2908
2909 RETURN_BOOL(zend_symtable_exists(Z_ARRVAL(intern->u.caching.zcache), key));
2910 }
2911
2912
2913
2914
2915 SPL_METHOD(CachingIterator, getCache)
2916 {
2917 spl_dual_it_object *intern;
2918
2919 if (zend_parse_parameters_none() == FAILURE) {
2920 return;
2921 }
2922
2923 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2924
2925 if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
2926 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%v does not use a full cache (see CachingIterator::__construct)", ZSTR_VAL(Z_OBJCE_P(getThis())->name));
2927 return;
2928 }
2929
2930 ZVAL_COPY(return_value, &intern->u.caching.zcache);
2931 }
2932
2933
2934
2935
2936 SPL_METHOD(CachingIterator, getFlags)
2937 {
2938 spl_dual_it_object *intern;
2939
2940 if (zend_parse_parameters_none() == FAILURE) {
2941 return;
2942 }
2943
2944 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2945
2946 RETURN_LONG(intern->u.caching.flags);
2947 }
2948
2949
2950
2951
2952 SPL_METHOD(CachingIterator, setFlags)
2953 {
2954 spl_dual_it_object *intern;
2955 zend_long flags;
2956
2957 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2958
2959 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &flags) == FAILURE) {
2960 return;
2961 }
2962
2963 if (spl_cit_check_flags(flags) != SUCCESS) {
2964 zend_throw_exception(spl_ce_InvalidArgumentException , "Flags must contain only one of CALL_TOSTRING, TOSTRING_USE_KEY, TOSTRING_USE_CURRENT, TOSTRING_USE_INNER", 0);
2965 return;
2966 }
2967 if ((intern->u.caching.flags & CIT_CALL_TOSTRING) != 0 && (flags & CIT_CALL_TOSTRING) == 0) {
2968 zend_throw_exception(spl_ce_InvalidArgumentException, "Unsetting flag CALL_TO_STRING is not possible", 0);
2969 return;
2970 }
2971 if ((intern->u.caching.flags & CIT_TOSTRING_USE_INNER) != 0 && (flags & CIT_TOSTRING_USE_INNER) == 0) {
2972 zend_throw_exception(spl_ce_InvalidArgumentException, "Unsetting flag TOSTRING_USE_INNER is not possible", 0);
2973 return;
2974 }
2975 if ((flags & CIT_FULL_CACHE) != 0 && (intern->u.caching.flags & CIT_FULL_CACHE) == 0) {
2976
2977 zend_hash_clean(Z_ARRVAL(intern->u.caching.zcache));
2978 }
2979 intern->u.caching.flags = (intern->u.caching.flags & ~CIT_PUBLIC) | (flags & CIT_PUBLIC);
2980 }
2981
2982
2983
2984
2985 SPL_METHOD(CachingIterator, count)
2986 {
2987 spl_dual_it_object *intern;
2988
2989 if (zend_parse_parameters_none() == FAILURE) {
2990 return;
2991 }
2992
2993 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2994
2995 if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
2996 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%v does not use a full cache (see CachingIterator::__construct)", ZSTR_VAL(Z_OBJCE_P(getThis())->name));
2997 return;
2998 }
2999
3000 RETURN_LONG(zend_hash_num_elements(Z_ARRVAL(intern->u.caching.zcache)));
3001 }
3002
3003
3004 ZEND_BEGIN_ARG_INFO_EX(arginfo_caching_it___construct, 0, 0, 1)
3005 ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
3006 ZEND_ARG_INFO(0, flags)
3007 ZEND_END_ARG_INFO();
3008
3009 ZEND_BEGIN_ARG_INFO(arginfo_caching_it_setFlags, 0)
3010 ZEND_ARG_INFO(0, flags)
3011 ZEND_END_ARG_INFO();
3012
3013 ZEND_BEGIN_ARG_INFO(arginfo_caching_it_offsetGet, 0)
3014 ZEND_ARG_INFO(0, index)
3015 ZEND_END_ARG_INFO();
3016
3017 ZEND_BEGIN_ARG_INFO(arginfo_caching_it_offsetSet, 0)
3018 ZEND_ARG_INFO(0, index)
3019 ZEND_ARG_INFO(0, newval)
3020 ZEND_END_ARG_INFO();
3021
3022 static const zend_function_entry spl_funcs_CachingIterator[] = {
3023 SPL_ME(CachingIterator, __construct, arginfo_caching_it___construct, ZEND_ACC_PUBLIC)
3024 SPL_ME(CachingIterator, rewind, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3025 SPL_ME(CachingIterator, valid, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3026 SPL_ME(dual_it, key, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3027 SPL_ME(dual_it, current, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3028 SPL_ME(CachingIterator, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3029 SPL_ME(CachingIterator, hasNext, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3030 SPL_ME(CachingIterator, __toString, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3031 SPL_ME(dual_it, getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3032 SPL_ME(CachingIterator, getFlags, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3033 SPL_ME(CachingIterator, setFlags, arginfo_caching_it_setFlags, ZEND_ACC_PUBLIC)
3034 SPL_ME(CachingIterator, offsetGet, arginfo_caching_it_offsetGet, ZEND_ACC_PUBLIC)
3035 SPL_ME(CachingIterator, offsetSet, arginfo_caching_it_offsetSet, ZEND_ACC_PUBLIC)
3036 SPL_ME(CachingIterator, offsetUnset, arginfo_caching_it_offsetGet, ZEND_ACC_PUBLIC)
3037 SPL_ME(CachingIterator, offsetExists, arginfo_caching_it_offsetGet, ZEND_ACC_PUBLIC)
3038 SPL_ME(CachingIterator, getCache, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3039 SPL_ME(CachingIterator, count, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3040 PHP_FE_END
3041 };
3042
3043
3044
3045 SPL_METHOD(RecursiveCachingIterator, __construct)
3046 {
3047 spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveCachingIterator, spl_ce_RecursiveIterator, DIT_RecursiveCachingIterator);
3048 }
3049
3050
3051
3052 SPL_METHOD(RecursiveCachingIterator, hasChildren)
3053 {
3054 spl_dual_it_object *intern;
3055
3056 if (zend_parse_parameters_none() == FAILURE) {
3057 return;
3058 }
3059
3060 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
3061
3062 RETURN_BOOL(Z_TYPE(intern->u.caching.zchildren) != IS_UNDEF);
3063 }
3064
3065
3066
3067 SPL_METHOD(RecursiveCachingIterator, getChildren)
3068 {
3069 spl_dual_it_object *intern;
3070
3071 if (zend_parse_parameters_none() == FAILURE) {
3072 return;
3073 }
3074
3075 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
3076
3077 if (Z_TYPE(intern->u.caching.zchildren) != IS_UNDEF) {
3078 zval *value = &intern->u.caching.zchildren;
3079
3080 ZVAL_DEREF(value);
3081 ZVAL_COPY(return_value, value);
3082 } else {
3083 RETURN_NULL();
3084 }
3085 }
3086
3087 ZEND_BEGIN_ARG_INFO_EX(arginfo_caching_rec_it___construct, 0, ZEND_RETURN_VALUE, 1)
3088 ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
3089 ZEND_ARG_INFO(0, flags)
3090 ZEND_END_ARG_INFO();
3091
3092 static const zend_function_entry spl_funcs_RecursiveCachingIterator[] = {
3093 SPL_ME(RecursiveCachingIterator, __construct, arginfo_caching_rec_it___construct, ZEND_ACC_PUBLIC)
3094 SPL_ME(RecursiveCachingIterator, hasChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3095 SPL_ME(RecursiveCachingIterator, getChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3096 PHP_FE_END
3097 };
3098
3099
3100
3101 SPL_METHOD(IteratorIterator, __construct)
3102 {
3103 spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_IteratorIterator, zend_ce_traversable, DIT_IteratorIterator);
3104 }
3105
3106 ZEND_BEGIN_ARG_INFO(arginfo_iterator_it___construct, 0)
3107 ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0)
3108 ZEND_END_ARG_INFO();
3109
3110 static const zend_function_entry spl_funcs_IteratorIterator[] = {
3111 SPL_ME(IteratorIterator, __construct, arginfo_iterator_it___construct, ZEND_ACC_PUBLIC)
3112 SPL_ME(dual_it, rewind, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3113 SPL_ME(dual_it, valid, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3114 SPL_ME(dual_it, key, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3115 SPL_ME(dual_it, current, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3116 SPL_ME(dual_it, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3117 SPL_ME(dual_it, getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3118 PHP_FE_END
3119 };
3120
3121
3122
3123 SPL_METHOD(NoRewindIterator, __construct)
3124 {
3125 spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_NoRewindIterator, zend_ce_iterator, DIT_NoRewindIterator);
3126 }
3127
3128
3129
3130 SPL_METHOD(NoRewindIterator, rewind)
3131 {
3132 if (zend_parse_parameters_none() == FAILURE) {
3133 return;
3134 }
3135
3136 }
3137
3138
3139
3140 SPL_METHOD(NoRewindIterator, valid)
3141 {
3142 spl_dual_it_object *intern;
3143
3144 if (zend_parse_parameters_none() == FAILURE) {
3145 return;
3146 }
3147
3148 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
3149 RETURN_BOOL(intern->inner.iterator->funcs->valid(intern->inner.iterator) == SUCCESS);
3150 }
3151
3152
3153
3154 SPL_METHOD(NoRewindIterator, key)
3155 {
3156 spl_dual_it_object *intern;
3157
3158 if (zend_parse_parameters_none() == FAILURE) {
3159 return;
3160 }
3161
3162 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
3163
3164 if (intern->inner.iterator->funcs->get_current_key) {
3165 intern->inner.iterator->funcs->get_current_key(intern->inner.iterator, return_value);
3166 } else {
3167 RETURN_NULL();
3168 }
3169 }
3170
3171
3172
3173 SPL_METHOD(NoRewindIterator, current)
3174 {
3175 spl_dual_it_object *intern;
3176 zval *data;
3177
3178 if (zend_parse_parameters_none() == FAILURE) {
3179 return;
3180 }
3181
3182 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
3183 data = intern->inner.iterator->funcs->get_current_data(intern->inner.iterator);
3184 if (data) {
3185 ZVAL_DEREF(data);
3186 ZVAL_COPY(return_value, data);
3187 }
3188 }
3189
3190
3191
3192 SPL_METHOD(NoRewindIterator, next)
3193 {
3194 spl_dual_it_object *intern;
3195
3196 if (zend_parse_parameters_none() == FAILURE) {
3197 return;
3198 }
3199
3200 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
3201 intern->inner.iterator->funcs->move_forward(intern->inner.iterator);
3202 }
3203
3204 ZEND_BEGIN_ARG_INFO(arginfo_norewind_it___construct, 0)
3205 ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
3206 ZEND_END_ARG_INFO();
3207
3208 static const zend_function_entry spl_funcs_NoRewindIterator[] = {
3209 SPL_ME(NoRewindIterator, __construct, arginfo_norewind_it___construct, ZEND_ACC_PUBLIC)
3210 SPL_ME(NoRewindIterator, rewind, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3211 SPL_ME(NoRewindIterator, valid, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3212 SPL_ME(NoRewindIterator, key, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3213 SPL_ME(NoRewindIterator, current, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3214 SPL_ME(NoRewindIterator, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3215 SPL_ME(dual_it, getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3216 PHP_FE_END
3217 };
3218
3219
3220
3221 SPL_METHOD(InfiniteIterator, __construct)
3222 {
3223 spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_InfiniteIterator, zend_ce_iterator, DIT_InfiniteIterator);
3224 }
3225
3226
3227
3228 SPL_METHOD(InfiniteIterator, next)
3229 {
3230 spl_dual_it_object *intern;
3231
3232 if (zend_parse_parameters_none() == FAILURE) {
3233 return;
3234 }
3235
3236 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
3237
3238 spl_dual_it_next(intern, 1);
3239 if (spl_dual_it_valid(intern) == SUCCESS) {
3240 spl_dual_it_fetch(intern, 0);
3241 } else {
3242 spl_dual_it_rewind(intern);
3243 if (spl_dual_it_valid(intern) == SUCCESS) {
3244 spl_dual_it_fetch(intern, 0);
3245 }
3246 }
3247 }
3248
3249 static const zend_function_entry spl_funcs_InfiniteIterator[] = {
3250 SPL_ME(InfiniteIterator, __construct, arginfo_norewind_it___construct, ZEND_ACC_PUBLIC)
3251 SPL_ME(InfiniteIterator, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3252 PHP_FE_END
3253 };
3254
3255
3256
3257 SPL_METHOD(EmptyIterator, rewind)
3258 {
3259 if (zend_parse_parameters_none() == FAILURE) {
3260 return;
3261 }
3262 }
3263
3264
3265
3266 SPL_METHOD(EmptyIterator, valid)
3267 {
3268 if (zend_parse_parameters_none() == FAILURE) {
3269 return;
3270 }
3271 RETURN_FALSE;
3272 }
3273
3274
3275
3276 SPL_METHOD(EmptyIterator, key)
3277 {
3278 if (zend_parse_parameters_none() == FAILURE) {
3279 return;
3280 }
3281 zend_throw_exception(spl_ce_BadMethodCallException, "Accessing the key of an EmptyIterator", 0);
3282 }
3283
3284
3285
3286 SPL_METHOD(EmptyIterator, current)
3287 {
3288 if (zend_parse_parameters_none() == FAILURE) {
3289 return;
3290 }
3291 zend_throw_exception(spl_ce_BadMethodCallException, "Accessing the value of an EmptyIterator", 0);
3292 }
3293
3294
3295
3296 SPL_METHOD(EmptyIterator, next)
3297 {
3298 if (zend_parse_parameters_none() == FAILURE) {
3299 return;
3300 }
3301 }
3302
3303 static const zend_function_entry spl_funcs_EmptyIterator[] = {
3304 SPL_ME(EmptyIterator, rewind, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3305 SPL_ME(EmptyIterator, valid, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3306 SPL_ME(EmptyIterator, key, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3307 SPL_ME(EmptyIterator, current, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3308 SPL_ME(EmptyIterator, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3309 PHP_FE_END
3310 };
3311
3312 int spl_append_it_next_iterator(spl_dual_it_object *intern)
3313 {
3314 spl_dual_it_free(intern);
3315
3316 if (!Z_ISUNDEF(intern->inner.zobject)) {
3317 zval_ptr_dtor(&intern->inner.zobject);
3318 ZVAL_UNDEF(&intern->inner.zobject);
3319 intern->inner.ce = NULL;
3320 if (intern->inner.iterator) {
3321 zend_iterator_dtor(intern->inner.iterator);
3322 intern->inner.iterator = NULL;
3323 }
3324 }
3325 if (intern->u.append.iterator->funcs->valid(intern->u.append.iterator) == SUCCESS) {
3326 zval *it;
3327
3328 it = intern->u.append.iterator->funcs->get_current_data(intern->u.append.iterator);
3329 ZVAL_COPY(&intern->inner.zobject, it);
3330 intern->inner.ce = Z_OBJCE_P(it);
3331 intern->inner.iterator = intern->inner.ce->get_iterator(intern->inner.ce, it, 0);
3332 spl_dual_it_rewind(intern);
3333 return SUCCESS;
3334 } else {
3335 return FAILURE;
3336 }
3337 }
3338
3339 void spl_append_it_fetch(spl_dual_it_object *intern)
3340 {
3341 while (spl_dual_it_valid(intern) != SUCCESS) {
3342 intern->u.append.iterator->funcs->move_forward(intern->u.append.iterator);
3343 if (spl_append_it_next_iterator(intern) != SUCCESS) {
3344 return;
3345 }
3346 }
3347 spl_dual_it_fetch(intern, 0);
3348 }
3349
3350 void spl_append_it_next(spl_dual_it_object *intern)
3351 {
3352 if (spl_dual_it_valid(intern) == SUCCESS) {
3353 spl_dual_it_next(intern, 1);
3354 }
3355 spl_append_it_fetch(intern);
3356 }
3357
3358
3359
3360 SPL_METHOD(AppendIterator, __construct)
3361 {
3362 spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_AppendIterator, zend_ce_iterator, DIT_AppendIterator);
3363 }
3364
3365
3366
3367 SPL_METHOD(AppendIterator, append)
3368 {
3369 spl_dual_it_object *intern;
3370 zval *it;
3371
3372 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
3373
3374 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "O", &it, zend_ce_iterator) == FAILURE) {
3375 return;
3376 }
3377 spl_array_iterator_append(&intern->u.append.zarrayit, it);
3378
3379 if (!intern->inner.iterator || spl_dual_it_valid(intern) != SUCCESS) {
3380 if (intern->u.append.iterator->funcs->valid(intern->u.append.iterator) != SUCCESS) {
3381 intern->u.append.iterator->funcs->rewind(intern->u.append.iterator);
3382 }
3383 do {
3384 spl_append_it_next_iterator(intern);
3385 } while (Z_OBJ(intern->inner.zobject) != Z_OBJ_P(it));
3386 spl_append_it_fetch(intern);
3387 }
3388 }
3389
3390
3391
3392 SPL_METHOD(AppendIterator, rewind)
3393 {
3394 spl_dual_it_object *intern;
3395
3396 if (zend_parse_parameters_none() == FAILURE) {
3397 return;
3398 }
3399
3400 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
3401
3402 intern->u.append.iterator->funcs->rewind(intern->u.append.iterator);
3403 if (spl_append_it_next_iterator(intern) == SUCCESS) {
3404 spl_append_it_fetch(intern);
3405 }
3406 }
3407
3408
3409
3410 SPL_METHOD(AppendIterator, valid)
3411 {
3412 spl_dual_it_object *intern;
3413
3414 if (zend_parse_parameters_none() == FAILURE) {
3415 return;
3416 }
3417
3418 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
3419
3420 RETURN_BOOL(Z_TYPE(intern->current.data) != IS_UNDEF);
3421 }
3422
3423
3424
3425 SPL_METHOD(AppendIterator, next)
3426 {
3427 spl_dual_it_object *intern;
3428
3429 if (zend_parse_parameters_none() == FAILURE) {
3430 return;
3431 }
3432
3433 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
3434
3435 spl_append_it_next(intern);
3436 }
3437
3438
3439
3440 SPL_METHOD(AppendIterator, getIteratorIndex)
3441 {
3442 spl_dual_it_object *intern;
3443
3444 if (zend_parse_parameters_none() == FAILURE) {
3445 return;
3446 }
3447
3448 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
3449
3450 APPENDIT_CHECK_CTOR(intern);
3451 spl_array_iterator_key(&intern->u.append.zarrayit, return_value);
3452 }
3453
3454
3455
3456 SPL_METHOD(AppendIterator, getArrayIterator)
3457 {
3458 spl_dual_it_object *intern;
3459 zval *value;
3460
3461 if (zend_parse_parameters_none() == FAILURE) {
3462 return;
3463 }
3464
3465 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
3466
3467 value = &intern->u.append.zarrayit;
3468 ZVAL_DEREF(value);
3469 ZVAL_COPY(return_value, value);
3470 }
3471
3472 ZEND_BEGIN_ARG_INFO(arginfo_append_it_append, 0)
3473 ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
3474 ZEND_END_ARG_INFO();
3475
3476 static const zend_function_entry spl_funcs_AppendIterator[] = {
3477 SPL_ME(AppendIterator, __construct, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3478 SPL_ME(AppendIterator, append, arginfo_append_it_append, ZEND_ACC_PUBLIC)
3479 SPL_ME(AppendIterator, rewind, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3480 SPL_ME(AppendIterator, valid, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3481 SPL_ME(dual_it, key, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3482 SPL_ME(dual_it, current, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3483 SPL_ME(AppendIterator, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3484 SPL_ME(dual_it, getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3485 SPL_ME(AppendIterator, getIteratorIndex, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3486 SPL_ME(AppendIterator, getArrayIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3487 PHP_FE_END
3488 };
3489
3490 PHPAPI int spl_iterator_apply(zval *obj, spl_iterator_apply_func_t apply_func, void *puser)
3491 {
3492 zend_object_iterator *iter;
3493 zend_class_entry *ce = Z_OBJCE_P(obj);
3494
3495 iter = ce->get_iterator(ce, obj, 0);
3496
3497 if (EG(exception)) {
3498 goto done;
3499 }
3500
3501 iter->index = 0;
3502 if (iter->funcs->rewind) {
3503 iter->funcs->rewind(iter);
3504 if (EG(exception)) {
3505 goto done;
3506 }
3507 }
3508
3509 while (iter->funcs->valid(iter) == SUCCESS) {
3510 if (EG(exception)) {
3511 goto done;
3512 }
3513 if (apply_func(iter, puser) == ZEND_HASH_APPLY_STOP || EG(exception)) {
3514 goto done;
3515 }
3516 iter->index++;
3517 iter->funcs->move_forward(iter);
3518 if (EG(exception)) {
3519 goto done;
3520 }
3521 }
3522
3523 done:
3524 if (iter) {
3525 zend_iterator_dtor(iter);
3526 }
3527 return EG(exception) ? FAILURE : SUCCESS;
3528 }
3529
3530
3531 static int spl_iterator_to_array_apply(zend_object_iterator *iter, void *puser)
3532 {
3533 zval *data, *return_value = (zval*)puser;
3534
3535 data = iter->funcs->get_current_data(iter);
3536 if (EG(exception)) {
3537 return ZEND_HASH_APPLY_STOP;
3538 }
3539 if (data == NULL) {
3540 return ZEND_HASH_APPLY_STOP;
3541 }
3542 if (iter->funcs->get_current_key) {
3543 zval key;
3544 iter->funcs->get_current_key(iter, &key);
3545 if (EG(exception)) {
3546 return ZEND_HASH_APPLY_STOP;
3547 }
3548 array_set_zval_key(Z_ARRVAL_P(return_value), &key, data);
3549 zval_ptr_dtor(&key);
3550 } else {
3551 Z_TRY_ADDREF_P(data);
3552 add_next_index_zval(return_value, data);
3553 }
3554 return ZEND_HASH_APPLY_KEEP;
3555 }
3556
3557
3558 static int spl_iterator_to_values_apply(zend_object_iterator *iter, void *puser)
3559 {
3560 zval *data, *return_value = (zval*)puser;
3561
3562 data = iter->funcs->get_current_data(iter);
3563 if (EG(exception)) {
3564 return ZEND_HASH_APPLY_STOP;
3565 }
3566 if (data == NULL) {
3567 return ZEND_HASH_APPLY_STOP;
3568 }
3569 if (Z_REFCOUNTED_P(data)) {
3570 Z_ADDREF_P(data);
3571 }
3572 add_next_index_zval(return_value, data);
3573 return ZEND_HASH_APPLY_KEEP;
3574 }
3575
3576
3577
3578
3579 PHP_FUNCTION(iterator_to_array)
3580 {
3581 zval *obj;
3582 zend_bool use_keys = 1;
3583
3584 if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|b", &obj, zend_ce_traversable, &use_keys) == FAILURE) {
3585 RETURN_FALSE;
3586 }
3587
3588 array_init(return_value);
3589
3590 if (spl_iterator_apply(obj, use_keys ? spl_iterator_to_array_apply : spl_iterator_to_values_apply, (void*)return_value) != SUCCESS) {
3591 zval_ptr_dtor(return_value);
3592 RETURN_NULL();
3593 }
3594 }
3595
3596 static int spl_iterator_count_apply(zend_object_iterator *iter, void *puser)
3597 {
3598 (*(zend_long*)puser)++;
3599 return ZEND_HASH_APPLY_KEEP;
3600 }
3601
3602
3603
3604
3605 PHP_FUNCTION(iterator_count)
3606 {
3607 zval *obj;
3608 zend_long count = 0;
3609
3610 if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &obj, zend_ce_traversable) == FAILURE) {
3611 RETURN_FALSE;
3612 }
3613
3614 if (spl_iterator_apply(obj, spl_iterator_count_apply, (void*)&count) == SUCCESS) {
3615 RETURN_LONG(count);
3616 }
3617 }
3618
3619
3620 typedef struct {
3621 zval *obj;
3622 zval *args;
3623 zend_long count;
3624 zend_fcall_info fci;
3625 zend_fcall_info_cache fcc;
3626 } spl_iterator_apply_info;
3627
3628 static int spl_iterator_func_apply(zend_object_iterator *iter, void *puser)
3629 {
3630 zval retval;
3631 spl_iterator_apply_info *apply_info = (spl_iterator_apply_info*)puser;
3632 int result;
3633
3634 apply_info->count++;
3635 zend_fcall_info_call(&apply_info->fci, &apply_info->fcc, &retval, NULL);
3636 if (Z_TYPE(retval) != IS_UNDEF) {
3637 result = zend_is_true(&retval) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_STOP;
3638 zval_ptr_dtor(&retval);
3639 } else {
3640 result = ZEND_HASH_APPLY_STOP;
3641 }
3642 return result;
3643 }
3644
3645
3646
3647
3648 PHP_FUNCTION(iterator_apply)
3649 {
3650 spl_iterator_apply_info apply_info;
3651
3652 apply_info.args = NULL;
3653 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Of|a!", &apply_info.obj, zend_ce_traversable, &apply_info.fci, &apply_info.fcc, &apply_info.args) == FAILURE) {
3654 return;
3655 }
3656
3657 apply_info.count = 0;
3658 zend_fcall_info_args(&apply_info.fci, apply_info.args);
3659 if (spl_iterator_apply(apply_info.obj, spl_iterator_func_apply, (void*)&apply_info) == SUCCESS) {
3660 RETVAL_LONG(apply_info.count);
3661 } else {
3662 RETVAL_FALSE;
3663 }
3664 zend_fcall_info_args(&apply_info.fci, NULL);
3665 }
3666
3667
3668 static const zend_function_entry spl_funcs_OuterIterator[] = {
3669 SPL_ABSTRACT_ME(OuterIterator, getInnerIterator, arginfo_recursive_it_void)
3670 PHP_FE_END
3671 };
3672
3673 static const zend_function_entry spl_funcs_Countable[] = {
3674 SPL_ABSTRACT_ME(Countable, count, arginfo_recursive_it_void)
3675 PHP_FE_END
3676 };
3677
3678
3679
3680 PHP_MINIT_FUNCTION(spl_iterators)
3681 {
3682 REGISTER_SPL_INTERFACE(RecursiveIterator);
3683 REGISTER_SPL_ITERATOR(RecursiveIterator);
3684
3685 REGISTER_SPL_STD_CLASS_EX(RecursiveIteratorIterator, spl_RecursiveIteratorIterator_new, spl_funcs_RecursiveIteratorIterator);
3686 REGISTER_SPL_ITERATOR(RecursiveIteratorIterator);
3687
3688 memcpy(&spl_handlers_rec_it_it, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
3689 spl_handlers_rec_it_it.offset = XtOffsetOf(spl_recursive_it_object, std);
3690 spl_handlers_rec_it_it.get_method = spl_recursive_it_get_method;
3691 spl_handlers_rec_it_it.clone_obj = NULL;
3692 spl_handlers_rec_it_it.dtor_obj = spl_RecursiveIteratorIterator_dtor;
3693 spl_handlers_rec_it_it.free_obj = spl_RecursiveIteratorIterator_free_storage;
3694
3695 memcpy(&spl_handlers_dual_it, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
3696 spl_handlers_dual_it.offset = XtOffsetOf(spl_dual_it_object, std);
3697 spl_handlers_dual_it.get_method = spl_dual_it_get_method;
3698
3699 spl_handlers_dual_it.clone_obj = NULL;
3700 spl_handlers_dual_it.dtor_obj = spl_dual_it_dtor;
3701 spl_handlers_dual_it.free_obj = spl_dual_it_free_storage;
3702
3703 spl_ce_RecursiveIteratorIterator->get_iterator = spl_recursive_it_get_iterator;
3704 spl_ce_RecursiveIteratorIterator->iterator_funcs.funcs = &spl_recursive_it_iterator_funcs;
3705
3706 REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "LEAVES_ONLY", RIT_LEAVES_ONLY);
3707 REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "SELF_FIRST", RIT_SELF_FIRST);
3708 REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "CHILD_FIRST", RIT_CHILD_FIRST);
3709 REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "CATCH_GET_CHILD", RIT_CATCH_GET_CHILD);
3710
3711 REGISTER_SPL_INTERFACE(OuterIterator);
3712 REGISTER_SPL_ITERATOR(OuterIterator);
3713
3714 REGISTER_SPL_STD_CLASS_EX(IteratorIterator, spl_dual_it_new, spl_funcs_IteratorIterator);
3715 REGISTER_SPL_ITERATOR(IteratorIterator);
3716 REGISTER_SPL_IMPLEMENTS(IteratorIterator, OuterIterator);
3717
3718 REGISTER_SPL_SUB_CLASS_EX(FilterIterator, IteratorIterator, spl_dual_it_new, spl_funcs_FilterIterator);
3719 spl_ce_FilterIterator->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
3720
3721 REGISTER_SPL_SUB_CLASS_EX(RecursiveFilterIterator, FilterIterator, spl_dual_it_new, spl_funcs_RecursiveFilterIterator);
3722 REGISTER_SPL_IMPLEMENTS(RecursiveFilterIterator, RecursiveIterator);
3723
3724 REGISTER_SPL_SUB_CLASS_EX(CallbackFilterIterator, FilterIterator, spl_dual_it_new, spl_funcs_CallbackFilterIterator);
3725
3726 REGISTER_SPL_SUB_CLASS_EX(RecursiveCallbackFilterIterator, CallbackFilterIterator, spl_dual_it_new, spl_funcs_RecursiveCallbackFilterIterator);
3727 REGISTER_SPL_IMPLEMENTS(RecursiveCallbackFilterIterator, RecursiveIterator);
3728
3729
3730 REGISTER_SPL_SUB_CLASS_EX(ParentIterator, RecursiveFilterIterator, spl_dual_it_new, spl_funcs_ParentIterator);
3731
3732 REGISTER_SPL_INTERFACE(Countable);
3733 REGISTER_SPL_INTERFACE(SeekableIterator);
3734 REGISTER_SPL_ITERATOR(SeekableIterator);
3735
3736 REGISTER_SPL_SUB_CLASS_EX(LimitIterator, IteratorIterator, spl_dual_it_new, spl_funcs_LimitIterator);
3737
3738 REGISTER_SPL_SUB_CLASS_EX(CachingIterator, IteratorIterator, spl_dual_it_new, spl_funcs_CachingIterator);
3739 REGISTER_SPL_IMPLEMENTS(CachingIterator, ArrayAccess);
3740 REGISTER_SPL_IMPLEMENTS(CachingIterator, Countable);
3741
3742 REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "CALL_TOSTRING", CIT_CALL_TOSTRING);
3743 REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "CATCH_GET_CHILD", CIT_CATCH_GET_CHILD);
3744 REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "TOSTRING_USE_KEY", CIT_TOSTRING_USE_KEY);
3745 REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "TOSTRING_USE_CURRENT", CIT_TOSTRING_USE_CURRENT);
3746 REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "TOSTRING_USE_INNER", CIT_TOSTRING_USE_INNER);
3747 REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "FULL_CACHE", CIT_FULL_CACHE);
3748
3749 REGISTER_SPL_SUB_CLASS_EX(RecursiveCachingIterator, CachingIterator, spl_dual_it_new, spl_funcs_RecursiveCachingIterator);
3750 REGISTER_SPL_IMPLEMENTS(RecursiveCachingIterator, RecursiveIterator);
3751
3752 REGISTER_SPL_SUB_CLASS_EX(NoRewindIterator, IteratorIterator, spl_dual_it_new, spl_funcs_NoRewindIterator);
3753
3754 REGISTER_SPL_SUB_CLASS_EX(AppendIterator, IteratorIterator, spl_dual_it_new, spl_funcs_AppendIterator);
3755
3756 REGISTER_SPL_IMPLEMENTS(RecursiveIteratorIterator, OuterIterator);
3757
3758 REGISTER_SPL_SUB_CLASS_EX(InfiniteIterator, IteratorIterator, spl_dual_it_new, spl_funcs_InfiniteIterator);
3759 #if HAVE_PCRE || HAVE_BUNDLED_PCRE
3760 REGISTER_SPL_SUB_CLASS_EX(RegexIterator, FilterIterator, spl_dual_it_new, spl_funcs_RegexIterator);
3761 REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "USE_KEY", REGIT_USE_KEY);
3762 REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "INVERT_MATCH",REGIT_INVERTED);
3763 REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "MATCH", REGIT_MODE_MATCH);
3764 REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "GET_MATCH", REGIT_MODE_GET_MATCH);
3765 REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "ALL_MATCHES", REGIT_MODE_ALL_MATCHES);
3766 REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "SPLIT", REGIT_MODE_SPLIT);
3767 REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "REPLACE", REGIT_MODE_REPLACE);
3768 REGISTER_SPL_PROPERTY(RegexIterator, "replacement", 0);
3769 REGISTER_SPL_SUB_CLASS_EX(RecursiveRegexIterator, RegexIterator, spl_dual_it_new, spl_funcs_RecursiveRegexIterator);
3770 REGISTER_SPL_IMPLEMENTS(RecursiveRegexIterator, RecursiveIterator);
3771 #else
3772 spl_ce_RegexIterator = NULL;
3773 spl_ce_RecursiveRegexIterator = NULL;
3774 #endif
3775
3776 REGISTER_SPL_STD_CLASS_EX(EmptyIterator, NULL, spl_funcs_EmptyIterator);
3777 REGISTER_SPL_ITERATOR(EmptyIterator);
3778
3779 REGISTER_SPL_SUB_CLASS_EX(RecursiveTreeIterator, RecursiveIteratorIterator, spl_RecursiveTreeIterator_new, spl_funcs_RecursiveTreeIterator);
3780 REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "BYPASS_CURRENT", RTIT_BYPASS_CURRENT);
3781 REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "BYPASS_KEY", RTIT_BYPASS_KEY);
3782 REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_LEFT", 0);
3783 REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_MID_HAS_NEXT", 1);
3784 REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_MID_LAST", 2);
3785 REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_END_HAS_NEXT", 3);
3786 REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_END_LAST", 4);
3787 REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_RIGHT", 5);
3788
3789 return SUCCESS;
3790 }
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800