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