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