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