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