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