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