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