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