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