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