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