1/*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2015 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 | Author: Antony Dovgal <tony@daylessday.org> |
16 | Etienne Kneuss <colder@php.net> |
17 +----------------------------------------------------------------------+
18*/
19
20/* $Id$ */
21
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
25
26#include "php.h"
27#include "php_ini.h"
28#include "ext/standard/info.h"
29#include "zend_exceptions.h"
30
31#include "php_spl.h"
32#include "spl_functions.h"
33#include "spl_engine.h"
34#include "spl_fixedarray.h"
35#include "spl_exceptions.h"
36#include "spl_iterators.h"
37
38zend_object_handlers spl_handler_SplFixedArray;
39PHPAPI zend_class_entry *spl_ce_SplFixedArray;
40
41#ifdef COMPILE_DL_SPL_FIXEDARRAY
42ZEND_GET_MODULE(spl_fixedarray)
43#endif
44
45typedef struct _spl_fixedarray { /* {{{ */
46 long size;
47 zval **elements;
48} spl_fixedarray;
49/* }}} */
50
51typedef struct _spl_fixedarray_object { /* {{{ */
52 zend_object std;
53 spl_fixedarray *array;
54 zval *retval;
55 zend_function *fptr_offset_get;
56 zend_function *fptr_offset_set;
57 zend_function *fptr_offset_has;
58 zend_function *fptr_offset_del;
59 zend_function *fptr_count;
60 int current;
61 int flags;
62 zend_class_entry *ce_get_iterator;
63} spl_fixedarray_object;
64/* }}} */
65
66typedef struct _spl_fixedarray_it { /* {{{ */
67 zend_user_iterator intern;
68 spl_fixedarray_object *object;
69} spl_fixedarray_it;
70/* }}} */
71
72#define SPL_FIXEDARRAY_OVERLOADED_REWIND 0x0001
73#define SPL_FIXEDARRAY_OVERLOADED_VALID 0x0002
74#define SPL_FIXEDARRAY_OVERLOADED_KEY 0x0004
75#define SPL_FIXEDARRAY_OVERLOADED_CURRENT 0x0008
76#define SPL_FIXEDARRAY_OVERLOADED_NEXT 0x0010
77
78static void spl_fixedarray_init(spl_fixedarray *array, long size TSRMLS_DC) /* {{{ */
79{
80 if (size > 0) {
81 array->size = 0; /* reset size in case ecalloc() fails */
82 array->elements = ecalloc(size, sizeof(zval *));
83 array->size = size;
84 } else {
85 array->elements = NULL;
86 array->size = 0;
87 }
88}
89/* }}} */
90
91static void spl_fixedarray_resize(spl_fixedarray *array, long size TSRMLS_DC) /* {{{ */
92{
93 if (size == array->size) {
94 /* nothing to do */
95 return;
96 }
97
98 /* first initialization */
99 if (array->size == 0) {
100 spl_fixedarray_init(array, size TSRMLS_CC);
101 return;
102 }
103
104 /* clearing the array */
105 if (size == 0) {
106 long i;
107
108 for (i = 0; i < array->size; i++) {
109 if (array->elements[i]) {
110 zval_ptr_dtor(&(array->elements[i]));
111 }
112 }
113
114 if (array->elements) {
115 efree(array->elements);
116 array->elements = NULL;
117 }
118 } else if (size > array->size) {
119 array->elements = safe_erealloc(array->elements, size, sizeof(zval *), 0);
120 memset(array->elements + array->size, '\0', sizeof(zval *) * (size - array->size));
121 } else { /* size < array->size */
122 long i;
123
124 for (i = size; i < array->size; i++) {
125 if (array->elements[i]) {
126 zval_ptr_dtor(&(array->elements[i]));
127 }
128 }
129 array->elements = erealloc(array->elements, sizeof(zval *) * size);
130 }
131
132 array->size = size;
133}
134/* }}} */
135
136static void spl_fixedarray_copy(spl_fixedarray *to, spl_fixedarray *from TSRMLS_DC) /* {{{ */
137{
138 int i;
139 for (i = 0; i < from->size; i++) {
140 if (from->elements[i]) {
141 Z_ADDREF_P(from->elements[i]);
142 to->elements[i] = from->elements[i];
143 } else {
144 to->elements[i] = NULL;
145 }
146 }
147}
148/* }}} */
149
150static HashTable* spl_fixedarray_object_get_gc(zval *obj, zval ***table, int *n TSRMLS_DC) /* {{{{ */
151{
152 spl_fixedarray_object *intern = (spl_fixedarray_object*)zend_object_store_get_object(obj TSRMLS_CC);
153 HashTable *ht = zend_std_get_properties(obj TSRMLS_CC);
154
155 if (intern->array) {
156 *table = intern->array->elements;
157 *n = intern->array->size;
158 } else {
159 *table = NULL;
160 *n = 0;
161 }
162
163 return ht;
164}
165/* }}}} */
166
167static HashTable* spl_fixedarray_object_get_properties(zval *obj TSRMLS_DC) /* {{{{ */
168{
169 spl_fixedarray_object *intern = (spl_fixedarray_object*)zend_object_store_get_object(obj TSRMLS_CC);
170 HashTable *ht = zend_std_get_properties(obj TSRMLS_CC);
171 int i = 0;
172
173 if (intern->array) {
174 int j = zend_hash_num_elements(ht);
175
176 for (i = 0; i < intern->array->size; i++) {
177 if (intern->array->elements[i]) {
178 zend_hash_index_update(ht, i, (void *)&intern->array->elements[i], sizeof(zval *), NULL);
179 Z_ADDREF_P(intern->array->elements[i]);
180 } else {
181 zend_hash_index_update(ht, i, (void *)&EG(uninitialized_zval_ptr), sizeof(zval *), NULL);
182 Z_ADDREF_P(EG(uninitialized_zval_ptr));
183 }
184 }
185 if (j > intern->array->size) {
186 for (i = intern->array->size; i < j; ++i) {
187 zend_hash_index_del(ht, i);
188 }
189 }
190 }
191
192 return ht;
193}
194/* }}}} */
195
196static void spl_fixedarray_object_free_storage(void *object TSRMLS_DC) /* {{{ */
197{
198 spl_fixedarray_object *intern = (spl_fixedarray_object *)object;
199 long i;
200
201 if (intern->array) {
202 for (i = 0; i < intern->array->size; i++) {
203 if (intern->array->elements[i]) {
204 zval_ptr_dtor(&(intern->array->elements[i]));
205 }
206 }
207
208 if (intern->array->size > 0 && intern->array->elements) {
209 efree(intern->array->elements);
210 }
211 efree(intern->array);
212 }
213
214 zend_object_std_dtor(&intern->std TSRMLS_CC);
215 zval_ptr_dtor(&intern->retval);
216
217 efree(object);
218}
219/* }}} */
220
221zend_object_iterator *spl_fixedarray_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC);
222
223static zend_object_value spl_fixedarray_object_new_ex(zend_class_entry *class_type, spl_fixedarray_object **obj, zval *orig, int clone_orig TSRMLS_DC) /* {{{ */
224{
225 zend_object_value retval;
226 spl_fixedarray_object *intern;
227 zend_class_entry *parent = class_type;
228 int inherited = 0;
229
230 intern = ecalloc(1, sizeof(spl_fixedarray_object));
231 *obj = intern;
232 ALLOC_INIT_ZVAL(intern->retval);
233
234 zend_object_std_init(&intern->std, class_type TSRMLS_CC);
235 object_properties_init(&intern->std, class_type);
236
237 intern->current = 0;
238 intern->flags = 0;
239
240 if (orig && clone_orig) {
241 spl_fixedarray_object *other = (spl_fixedarray_object*)zend_object_store_get_object(orig TSRMLS_CC);
242 intern->ce_get_iterator = other->ce_get_iterator;
243 if (!other->array) {
244 /* leave a empty object, will be dtor later by CLONE handler */
245 zend_throw_exception(spl_ce_RuntimeException, "The instance wasn't initialized properly", 0 TSRMLS_CC);
246 } else {
247 intern->array = emalloc(sizeof(spl_fixedarray));
248 spl_fixedarray_init(intern->array, other->array->size TSRMLS_CC);
249 spl_fixedarray_copy(intern->array, other->array TSRMLS_CC);
250 }
251 }
252
253 while (parent) {
254 if (parent == spl_ce_SplFixedArray) {
255 retval.handlers = &spl_handler_SplFixedArray;
256 class_type->get_iterator = spl_fixedarray_get_iterator;
257 break;
258 }
259
260 parent = parent->parent;
261 inherited = 1;
262 }
263
264 retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, spl_fixedarray_object_free_storage, NULL TSRMLS_CC);
265
266 if (!parent) { /* this must never happen */
267 php_error_docref(NULL TSRMLS_CC, E_COMPILE_ERROR, "Internal compiler error, Class is not child of SplFixedArray");
268 }
269 if (!class_type->iterator_funcs.zf_current) {
270 zend_hash_find(&class_type->function_table, "rewind", sizeof("rewind"), (void **) &class_type->iterator_funcs.zf_rewind);
271 zend_hash_find(&class_type->function_table, "valid", sizeof("valid"), (void **) &class_type->iterator_funcs.zf_valid);
272 zend_hash_find(&class_type->function_table, "key", sizeof("key"), (void **) &class_type->iterator_funcs.zf_key);
273 zend_hash_find(&class_type->function_table, "current", sizeof("current"), (void **) &class_type->iterator_funcs.zf_current);
274 zend_hash_find(&class_type->function_table, "next", sizeof("next"), (void **) &class_type->iterator_funcs.zf_next);
275 }
276 if (inherited) {
277 if (class_type->iterator_funcs.zf_rewind->common.scope != parent) {
278 intern->flags |= SPL_FIXEDARRAY_OVERLOADED_REWIND;
279 }
280 if (class_type->iterator_funcs.zf_valid->common.scope != parent) {
281 intern->flags |= SPL_FIXEDARRAY_OVERLOADED_VALID;
282 }
283 if (class_type->iterator_funcs.zf_key->common.scope != parent) {
284 intern->flags |= SPL_FIXEDARRAY_OVERLOADED_KEY;
285 }
286 if (class_type->iterator_funcs.zf_current->common.scope != parent) {
287 intern->flags |= SPL_FIXEDARRAY_OVERLOADED_CURRENT;
288 }
289 if (class_type->iterator_funcs.zf_next->common.scope != parent) {
290 intern->flags |= SPL_FIXEDARRAY_OVERLOADED_NEXT;
291 }
292
293 zend_hash_find(&class_type->function_table, "offsetget", sizeof("offsetget"), (void **) &intern->fptr_offset_get);
294 if (intern->fptr_offset_get->common.scope == parent) {
295 intern->fptr_offset_get = NULL;
296 }
297 zend_hash_find(&class_type->function_table, "offsetset", sizeof("offsetset"), (void **) &intern->fptr_offset_set);
298 if (intern->fptr_offset_set->common.scope == parent) {
299 intern->fptr_offset_set = NULL;
300 }
301 zend_hash_find(&class_type->function_table, "offsetexists", sizeof("offsetexists"), (void **) &intern->fptr_offset_has);
302 if (intern->fptr_offset_has->common.scope == parent) {
303 intern->fptr_offset_has = NULL;
304 }
305 zend_hash_find(&class_type->function_table, "offsetunset", sizeof("offsetunset"), (void **) &intern->fptr_offset_del);
306 if (intern->fptr_offset_del->common.scope == parent) {
307 intern->fptr_offset_del = NULL;
308 }
309 zend_hash_find(&class_type->function_table, "count", sizeof("count"), (void **) &intern->fptr_count);
310 if (intern->fptr_count->common.scope == parent) {
311 intern->fptr_count = NULL;
312 }
313 }
314
315 return retval;
316}
317/* }}} */
318
319static zend_object_value spl_fixedarray_new(zend_class_entry *class_type TSRMLS_DC) /* {{{ */
320{
321 spl_fixedarray_object *tmp;
322 return spl_fixedarray_object_new_ex(class_type, &tmp, NULL, 0 TSRMLS_CC);
323}
324/* }}} */
325
326static zend_object_value spl_fixedarray_object_clone(zval *zobject TSRMLS_DC) /* {{{ */
327{
328 zend_object_value new_obj_val;
329 zend_object *old_object;
330 zend_object *new_object;
331 zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
332 spl_fixedarray_object *intern;
333
334 old_object = zend_objects_get_address(zobject TSRMLS_CC);
335 new_obj_val = spl_fixedarray_object_new_ex(old_object->ce, &intern, zobject, 1 TSRMLS_CC);
336 new_object = &intern->std;
337
338 zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC);
339
340 return new_obj_val;
341}
342/* }}} */
343
344static inline zval **spl_fixedarray_object_read_dimension_helper(spl_fixedarray_object *intern, zval *offset TSRMLS_DC) /* {{{ */
345{
346 long index;
347
348 /* we have to return NULL on error here to avoid memleak because of
349 * ZE duplicating uninitialized_zval_ptr */
350 if (!offset) {
351 zend_throw_exception(spl_ce_RuntimeException, "Index invalid or out of range", 0 TSRMLS_CC);
352 return NULL;
353 }
354
355 if (Z_TYPE_P(offset) != IS_LONG) {
356 index = spl_offset_convert_to_long(offset TSRMLS_CC);
357 } else {
358 index = Z_LVAL_P(offset);
359 }
360
361 if (index < 0 || intern->array == NULL || index >= intern->array->size) {
362 zend_throw_exception(spl_ce_RuntimeException, "Index invalid or out of range", 0 TSRMLS_CC);
363 return NULL;
364 } else if(!intern->array->elements[index]) {
365 return NULL;
366 } else {
367 return &intern->array->elements[index];
368 }
369}
370/* }}} */
371
372static zval *spl_fixedarray_object_read_dimension(zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
373{
374 spl_fixedarray_object *intern;
375 zval **retval;
376
377 intern = (spl_fixedarray_object *)zend_object_store_get_object(object TSRMLS_CC);
378
379 if (intern->fptr_offset_get) {
380 zval *rv;
381 if (!offset) {
382 ALLOC_INIT_ZVAL(offset);
383 } else {
384 SEPARATE_ARG_IF_REF(offset);
385 }
386 zend_call_method_with_1_params(&object, intern->std.ce, &intern->fptr_offset_get, "offsetGet", &rv, offset);
387 zval_ptr_dtor(&offset);
388 if (rv) {
389 zval_ptr_dtor(&intern->retval);
390 MAKE_STD_ZVAL(intern->retval);
391 ZVAL_ZVAL(intern->retval, rv, 1, 1);
392 return intern->retval;
393 }
394 return EG(uninitialized_zval_ptr);
395 }
396
397 retval = spl_fixedarray_object_read_dimension_helper(intern, offset TSRMLS_CC);
398 if (retval) {
399 return *retval;
400 }
401 return NULL;
402}
403/* }}} */
404
405static inline void spl_fixedarray_object_write_dimension_helper(spl_fixedarray_object *intern, zval *offset, zval *value TSRMLS_DC) /* {{{ */
406{
407 long index;
408
409 if (!offset) {
410 /* '$array[] = value' syntax is not supported */
411 zend_throw_exception(spl_ce_RuntimeException, "Index invalid or out of range", 0 TSRMLS_CC);
412 return;
413 }
414
415 if (Z_TYPE_P(offset) != IS_LONG) {
416 index = spl_offset_convert_to_long(offset TSRMLS_CC);
417 } else {
418 index = Z_LVAL_P(offset);
419 }
420
421 if (index < 0 || intern->array == NULL || index >= intern->array->size) {
422 zend_throw_exception(spl_ce_RuntimeException, "Index invalid or out of range", 0 TSRMLS_CC);
423 return;
424 } else {
425 if (intern->array->elements[index]) {
426 zval_ptr_dtor(&(intern->array->elements[index]));
427 }
428 SEPARATE_ARG_IF_REF(value);
429 intern->array->elements[index] = value;
430 }
431}
432/* }}} */
433
434static void spl_fixedarray_object_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC) /* {{{ */
435{
436 spl_fixedarray_object *intern;
437
438 intern = (spl_fixedarray_object *)zend_object_store_get_object(object TSRMLS_CC);
439
440 if (intern->fptr_offset_set) {
441 if (!offset) {
442 ALLOC_INIT_ZVAL(offset);
443 } else {
444 SEPARATE_ARG_IF_REF(offset);
445 }
446 SEPARATE_ARG_IF_REF(value);
447 zend_call_method_with_2_params(&object, intern->std.ce, &intern->fptr_offset_set, "offsetSet", NULL, offset, value);
448 zval_ptr_dtor(&value);
449 zval_ptr_dtor(&offset);
450 return;
451 }
452
453 spl_fixedarray_object_write_dimension_helper(intern, offset, value TSRMLS_CC);
454}
455/* }}} */
456
457static inline void spl_fixedarray_object_unset_dimension_helper(spl_fixedarray_object *intern, zval *offset TSRMLS_DC) /* {{{ */
458{
459 long index;
460
461 if (Z_TYPE_P(offset) != IS_LONG) {
462 index = spl_offset_convert_to_long(offset TSRMLS_CC);
463 } else {
464 index = Z_LVAL_P(offset);
465 }
466
467 if (index < 0 || intern->array == NULL || index >= intern->array->size) {
468 zend_throw_exception(spl_ce_RuntimeException, "Index invalid or out of range", 0 TSRMLS_CC);
469 return;
470 } else {
471 if (intern->array->elements[index]) {
472 zval_ptr_dtor(&(intern->array->elements[index]));
473 }
474 intern->array->elements[index] = NULL;
475 }
476}
477/* }}} */
478
479static void spl_fixedarray_object_unset_dimension(zval *object, zval *offset TSRMLS_DC) /* {{{ */
480{
481 spl_fixedarray_object *intern;
482
483 intern = (spl_fixedarray_object *)zend_object_store_get_object(object TSRMLS_CC);
484
485 if (intern->fptr_offset_del) {
486 SEPARATE_ARG_IF_REF(offset);
487 zend_call_method_with_1_params(&object, intern->std.ce, &intern->fptr_offset_del, "offsetUnset", NULL, offset);
488 zval_ptr_dtor(&offset);
489 return;
490 }
491
492 spl_fixedarray_object_unset_dimension_helper(intern, offset TSRMLS_CC);
493
494}
495/* }}} */
496
497static inline int spl_fixedarray_object_has_dimension_helper(spl_fixedarray_object *intern, zval *offset, int check_empty TSRMLS_DC) /* {{{ */
498{
499 long index;
500 int retval;
501
502 if (Z_TYPE_P(offset) != IS_LONG) {
503 index = spl_offset_convert_to_long(offset TSRMLS_CC);
504 } else {
505 index = Z_LVAL_P(offset);
506 }
507
508 if (index < 0 || intern->array == NULL || index >= intern->array->size) {
509 retval = 0;
510 } else {
511 if (!intern->array->elements[index]) {
512 retval = 0;
513 } else if (check_empty) {
514 if (zend_is_true(intern->array->elements[index])) {
515 retval = 1;
516 } else {
517 retval = 0;
518 }
519 } else { /* != NULL and !check_empty */
520 retval = 1;
521 }
522 }
523
524 return retval;
525}
526/* }}} */
527
528static int spl_fixedarray_object_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC) /* {{{ */
529{
530 spl_fixedarray_object *intern;
531
532 intern = (spl_fixedarray_object *)zend_object_store_get_object(object TSRMLS_CC);
533
534 if (intern->fptr_offset_get) {
535 zval *rv;
536 SEPARATE_ARG_IF_REF(offset);
537 zend_call_method_with_1_params(&object, intern->std.ce, &intern->fptr_offset_has, "offsetExists", &rv, offset);
538 zval_ptr_dtor(&offset);
539 if (rv) {
540 zval_ptr_dtor(&intern->retval);
541 MAKE_STD_ZVAL(intern->retval);
542 ZVAL_ZVAL(intern->retval, rv, 1, 1);
543 return zend_is_true(intern->retval);
544 }
545 return 0;
546 }
547
548 return spl_fixedarray_object_has_dimension_helper(intern, offset, check_empty TSRMLS_CC);
549}
550/* }}} */
551
552static int spl_fixedarray_object_count_elements(zval *object, long *count TSRMLS_DC) /* {{{ */
553{
554 spl_fixedarray_object *intern;
555
556 intern = (spl_fixedarray_object *)zend_object_store_get_object(object TSRMLS_CC);
557 if (intern->fptr_count) {
558 zval *rv;
559 zend_call_method_with_0_params(&object, intern->std.ce, &intern->fptr_count, "count", &rv);
560 if (rv) {
561 zval_ptr_dtor(&intern->retval);
562 MAKE_STD_ZVAL(intern->retval);
563 ZVAL_ZVAL(intern->retval, rv, 1, 1);
564 convert_to_long(intern->retval);
565 *count = (long) Z_LVAL_P(intern->retval);
566 return SUCCESS;
567 }
568 } else if (intern->array) {
569 *count = intern->array->size;
570 return SUCCESS;
571 }
572
573 *count = 0;
574 return SUCCESS;
575}
576/* }}} */
577
578/* {{{ proto void SplFixedArray::__construct([int size])
579*/
580SPL_METHOD(SplFixedArray, __construct)
581{
582 zval *object = getThis();
583 spl_fixedarray_object *intern;
584 long size = 0;
585
586 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &size) == FAILURE) {
587 return;
588 }
589
590 if (size < 0) {
591 zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "array size cannot be less than zero");
592 return;
593 }
594
595 intern = (spl_fixedarray_object *)zend_object_store_get_object(object TSRMLS_CC);
596
597 if (intern->array) {
598 /* called __construct() twice, bail out */
599 return;
600 }
601
602 intern->array = emalloc(sizeof(spl_fixedarray));
603 spl_fixedarray_init(intern->array, size TSRMLS_CC);
604}
605/* }}} */
606
607/* {{{ proto void SplFixedArray::__wakeup()
608*/
609SPL_METHOD(SplFixedArray, __wakeup)
610{
611 spl_fixedarray_object *intern = (spl_fixedarray_object *) zend_object_store_get_object(getThis() TSRMLS_CC);
612 HashPosition ptr;
613 HashTable *intern_ht = zend_std_get_properties(getThis() TSRMLS_CC);
614 zval **data;
615
616 if (zend_parse_parameters_none() == FAILURE) {
617 return;
618 }
619
620 if (!intern->array) {
621 int index = 0;
622 int size = zend_hash_num_elements(intern_ht);
623
624 intern->array = emalloc(sizeof(spl_fixedarray));
625 spl_fixedarray_init(intern->array, size TSRMLS_CC);
626
627 for (zend_hash_internal_pointer_reset_ex(intern_ht, &ptr); zend_hash_get_current_data_ex(intern_ht, (void **) &data, &ptr) == SUCCESS; zend_hash_move_forward_ex(intern_ht, &ptr)) {
628 Z_ADDREF_PP(data);
629 intern->array->elements[index++] = *data;
630 }
631
632 /* Remove the unserialised properties, since we now have the elements
633 * within the spl_fixedarray_object structure. */
634 zend_hash_clean(intern_ht);
635 }
636}
637/* }}} */
638
639/* {{{ proto int SplFixedArray::count(void)
640*/
641SPL_METHOD(SplFixedArray, count)
642{
643 zval *object = getThis();
644 spl_fixedarray_object *intern;
645
646 if (zend_parse_parameters_none() == FAILURE) {
647 return;
648 }
649
650 intern = (spl_fixedarray_object *)zend_object_store_get_object(object TSRMLS_CC);
651 if (intern->array) {
652 RETURN_LONG(intern->array->size);
653 }
654 RETURN_LONG(0);
655}
656/* }}} */
657
658/* {{{ proto object SplFixedArray::toArray()
659*/
660SPL_METHOD(SplFixedArray, toArray)
661{
662 spl_fixedarray_object *intern;
663
664 if (zend_parse_parameters_none() == FAILURE) {
665 return;
666 }
667
668 intern = (spl_fixedarray_object *)zend_object_store_get_object(getThis() TSRMLS_CC);
669
670 array_init(return_value);
671 if (intern->array) {
672 int i = 0;
673 for (; i < intern->array->size; i++) {
674 if (intern->array->elements[i]) {
675 zend_hash_index_update(Z_ARRVAL_P(return_value), i, (void *)&intern->array->elements[i], sizeof(zval *), NULL);
676 Z_ADDREF_P(intern->array->elements[i]);
677 } else {
678 zend_hash_index_update(Z_ARRVAL_P(return_value), i, (void *)&EG(uninitialized_zval_ptr), sizeof(zval *), NULL);
679 Z_ADDREF_P(EG(uninitialized_zval_ptr));
680 }
681 }
682 }
683}
684/* }}} */
685
686/* {{{ proto object SplFixedArray::fromArray(array data[, bool save_indexes])
687*/
688SPL_METHOD(SplFixedArray, fromArray)
689{
690 zval *data;
691 spl_fixedarray *array;
692 spl_fixedarray_object *intern;
693 int num;
694 zend_bool save_indexes = 1;
695
696 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|b", &data, &save_indexes) == FAILURE) {
697 return;
698 }
699
700 array = ecalloc(1, sizeof(*array));
701 num = zend_hash_num_elements(Z_ARRVAL_P(data));
702
703 if (num > 0 && save_indexes) {
704 zval **element, *value;
705 char *str_index;
706 ulong num_index, max_index = 0;
707 long tmp;
708
709 for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(data));
710 zend_hash_get_current_data(Z_ARRVAL_P(data), (void **) &element) == SUCCESS;
711 zend_hash_move_forward(Z_ARRVAL_P(data))
712 ) {
713 if (zend_hash_get_current_key(Z_ARRVAL_P(data), &str_index, &num_index, 0) != HASH_KEY_IS_LONG || (long)num_index < 0) {
714 efree(array);
715 zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "array must contain only positive integer keys");
716 return;
717 }
718
719 if (num_index > max_index) {
720 max_index = num_index;
721 }
722 }
723
724 tmp = max_index + 1;
725 if (tmp <= 0) {
726 efree(array);
727 zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "integer overflow detected");
728 return;
729 }
730 spl_fixedarray_init(array, tmp TSRMLS_CC);
731
732 for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(data));
733 zend_hash_get_current_data(Z_ARRVAL_P(data), (void **) &element) == SUCCESS;
734 zend_hash_move_forward(Z_ARRVAL_P(data))
735 ) {
736
737 zend_hash_get_current_key(Z_ARRVAL_P(data), &str_index, &num_index, 0);
738 value = *element;
739
740 SEPARATE_ARG_IF_REF(value);
741 array->elements[num_index] = value;
742 }
743
744 } else if (num > 0 && !save_indexes) {
745 zval **element, *value;
746 long i = 0;
747
748 spl_fixedarray_init(array, num TSRMLS_CC);
749
750 for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(data));
751 zend_hash_get_current_data(Z_ARRVAL_P(data), (void **) &element) == SUCCESS;
752 zend_hash_move_forward(Z_ARRVAL_P(data))
753 ) {
754
755 value = *element;
756
757 SEPARATE_ARG_IF_REF(value);
758 array->elements[i] = value;
759 i++;
760 }
761 } else {
762 spl_fixedarray_init(array, 0 TSRMLS_CC);
763 }
764
765 object_init_ex(return_value, spl_ce_SplFixedArray);
766 Z_TYPE_P(return_value) = IS_OBJECT;
767
768 intern = (spl_fixedarray_object *)zend_object_store_get_object(return_value TSRMLS_CC);
769 intern->array = array;
770}
771/* }}} */
772
773/* {{{ proto int SplFixedArray::getSize(void)
774*/
775SPL_METHOD(SplFixedArray, getSize)
776{
777 zval *object = getThis();
778 spl_fixedarray_object *intern;
779
780 if (zend_parse_parameters_none() == FAILURE) {
781 return;
782 }
783
784 intern = (spl_fixedarray_object *)zend_object_store_get_object(object TSRMLS_CC);
785 if (intern->array) {
786 RETURN_LONG(intern->array->size);
787 }
788 RETURN_LONG(0);
789}
790/* }}} */
791
792/* {{{ proto bool SplFixedArray::setSize(int size)
793*/
794SPL_METHOD(SplFixedArray, setSize)
795{
796 zval *object = getThis();
797 spl_fixedarray_object *intern;
798 long size;
799
800 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &size) == FAILURE) {
801 return;
802 }
803
804 if (size < 0) {
805 zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "array size cannot be less than zero");
806 return;
807 }
808
809 intern = (spl_fixedarray_object *)zend_object_store_get_object(object TSRMLS_CC);
810 if (!intern->array) {
811 intern->array = ecalloc(1, sizeof(spl_fixedarray));
812 }
813
814 spl_fixedarray_resize(intern->array, size TSRMLS_CC);
815 RETURN_TRUE;
816}
817/* }}} */
818
819/* {{{ proto bool SplFixedArray::offsetExists(mixed $index) U
820 Returns whether the requested $index exists. */
821SPL_METHOD(SplFixedArray, offsetExists)
822{
823 zval *zindex;
824 spl_fixedarray_object *intern;
825
826 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zindex) == FAILURE) {
827 return;
828 }
829
830 intern = (spl_fixedarray_object *)zend_object_store_get_object(getThis() TSRMLS_CC);
831
832 RETURN_BOOL(spl_fixedarray_object_has_dimension_helper(intern, zindex, 0 TSRMLS_CC));
833} /* }}} */
834
835/* {{{ proto mixed SplFixedArray::offsetGet(mixed $index) U
836 Returns the value at the specified $index. */
837SPL_METHOD(SplFixedArray, offsetGet)
838{
839 zval *zindex, **value_pp;
840 spl_fixedarray_object *intern;
841
842 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zindex) == FAILURE) {
843 return;
844 }
845
846 intern = (spl_fixedarray_object *)zend_object_store_get_object(getThis() TSRMLS_CC);
847 value_pp = spl_fixedarray_object_read_dimension_helper(intern, zindex TSRMLS_CC);
848
849 if (value_pp) {
850 RETURN_ZVAL(*value_pp, 1, 0);
851 }
852 RETURN_NULL();
853} /* }}} */
854
855/* {{{ proto void SplFixedArray::offsetSet(mixed $index, mixed $newval) U
856 Sets the value at the specified $index to $newval. */
857SPL_METHOD(SplFixedArray, offsetSet)
858{
859 zval *zindex, *value;
860 spl_fixedarray_object *intern;
861
862 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &zindex, &value) == FAILURE) {
863 return;
864 }
865
866 intern = (spl_fixedarray_object *)zend_object_store_get_object(getThis() TSRMLS_CC);
867 spl_fixedarray_object_write_dimension_helper(intern, zindex, value TSRMLS_CC);
868
869} /* }}} */
870
871/* {{{ proto void SplFixedArray::offsetUnset(mixed $index) U
872 Unsets the value at the specified $index. */
873SPL_METHOD(SplFixedArray, offsetUnset)
874{
875 zval *zindex;
876 spl_fixedarray_object *intern;
877
878 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zindex) == FAILURE) {
879 return;
880 }
881
882 intern = (spl_fixedarray_object *)zend_object_store_get_object(getThis() TSRMLS_CC);
883 spl_fixedarray_object_unset_dimension_helper(intern, zindex TSRMLS_CC);
884
885} /* }}} */
886
887static void spl_fixedarray_it_dtor(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
888{
889 spl_fixedarray_it *iterator = (spl_fixedarray_it *)iter;
890
891 zend_user_it_invalidate_current(iter TSRMLS_CC);
892 zval_ptr_dtor((zval**)&iterator->intern.it.data);
893
894 efree(iterator);
895}
896/* }}} */
897
898static void spl_fixedarray_it_rewind(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
899{
900 spl_fixedarray_it *iterator = (spl_fixedarray_it *)iter;
901 spl_fixedarray_object *intern = iterator->object;
902
903 if (intern->flags & SPL_FIXEDARRAY_OVERLOADED_REWIND) {
904 zend_user_it_rewind(iter TSRMLS_CC);
905 } else {
906 iterator->object->current = 0;
907 }
908}
909/* }}} */
910
911static int spl_fixedarray_it_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
912{
913 spl_fixedarray_it *iterator = (spl_fixedarray_it *)iter;
914 spl_fixedarray_object *intern = iterator->object;
915
916 if (intern->flags & SPL_FIXEDARRAY_OVERLOADED_VALID) {
917 return zend_user_it_valid(iter TSRMLS_CC);
918 }
919
920 if (iterator->object->current >= 0 && iterator->object->array && iterator->object->current < iterator->object->array->size) {
921 return SUCCESS;
922 }
923
924 return FAILURE;
925}
926/* }}} */
927
928static void spl_fixedarray_it_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) /* {{{ */
929{
930 zval *zindex;
931 spl_fixedarray_it *iterator = (spl_fixedarray_it *)iter;
932 spl_fixedarray_object *intern = iterator->object;
933
934 if (intern->flags & SPL_FIXEDARRAY_OVERLOADED_CURRENT) {
935 zend_user_it_get_current_data(iter, data TSRMLS_CC);
936 } else {
937 ALLOC_INIT_ZVAL(zindex);
938 ZVAL_LONG(zindex, iterator->object->current);
939
940 *data = spl_fixedarray_object_read_dimension_helper(intern, zindex TSRMLS_CC);
941
942 if (*data == NULL) {
943 *data = &EG(uninitialized_zval_ptr);
944 }
945
946 zval_ptr_dtor(&zindex);
947 }
948}
949/* }}} */
950
951static void spl_fixedarray_it_get_current_key(zend_object_iterator *iter, zval *key TSRMLS_DC) /* {{{ */
952{
953 spl_fixedarray_it *iterator = (spl_fixedarray_it *)iter;
954 spl_fixedarray_object *intern = iterator->object;
955
956 if (intern->flags & SPL_FIXEDARRAY_OVERLOADED_KEY) {
957 zend_user_it_get_current_key(iter, key TSRMLS_CC);
958 } else {
959 ZVAL_LONG(key, iterator->object->current);
960 }
961}
962/* }}} */
963
964static void spl_fixedarray_it_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
965{
966 spl_fixedarray_it *iterator = (spl_fixedarray_it *)iter;
967 spl_fixedarray_object *intern = iterator->object;
968
969 if (intern->flags & SPL_FIXEDARRAY_OVERLOADED_NEXT) {
970 zend_user_it_move_forward(iter TSRMLS_CC);
971 } else {
972 zend_user_it_invalidate_current(iter TSRMLS_CC);
973 iterator->object->current++;
974 }
975}
976/* }}} */
977
978/* {{{ proto int SplFixedArray::key() U
979 Return current array key */
980SPL_METHOD(SplFixedArray, key)
981{
982 spl_fixedarray_object *intern = (spl_fixedarray_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
983
984 if (zend_parse_parameters_none() == FAILURE) {
985 return;
986 }
987
988 RETURN_LONG(intern->current);
989}
990/* }}} */
991
992/* {{{ proto void SplFixedArray::next() U
993 Move to next entry */
994SPL_METHOD(SplFixedArray, next)
995{
996 spl_fixedarray_object *intern = (spl_fixedarray_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
997
998 if (zend_parse_parameters_none() == FAILURE) {
999 return;
1000 }
1001
1002 intern->current++;
1003}
1004/* }}} */
1005
1006/* {{{ proto bool SplFixedArray::valid() U
1007 Check whether the datastructure contains more entries */
1008SPL_METHOD(SplFixedArray, valid)
1009{
1010 spl_fixedarray_object *intern = (spl_fixedarray_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1011
1012 if (zend_parse_parameters_none() == FAILURE) {
1013 return;
1014 }
1015
1016 RETURN_BOOL(intern->current >= 0 && intern->array && intern->current < intern->array->size);
1017}
1018/* }}} */
1019
1020/* {{{ proto void SplFixedArray::rewind() U
1021 Rewind the datastructure back to the start */
1022SPL_METHOD(SplFixedArray, rewind)
1023{
1024 spl_fixedarray_object *intern = (spl_fixedarray_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1025
1026 if (zend_parse_parameters_none() == FAILURE) {
1027 return;
1028 }
1029
1030 intern->current = 0;
1031}
1032/* }}} */
1033
1034/* {{{ proto mixed|NULL SplFixedArray::current() U
1035 Return current datastructure entry */
1036SPL_METHOD(SplFixedArray, current)
1037{
1038 zval *zindex, **value_pp;
1039 spl_fixedarray_object *intern = (spl_fixedarray_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1040
1041 if (zend_parse_parameters_none() == FAILURE) {
1042 return;
1043 }
1044
1045 ALLOC_INIT_ZVAL(zindex);
1046 ZVAL_LONG(zindex, intern->current);
1047
1048 value_pp = spl_fixedarray_object_read_dimension_helper(intern, zindex TSRMLS_CC);
1049
1050 zval_ptr_dtor(&zindex);
1051
1052 if (value_pp) {
1053 RETURN_ZVAL(*value_pp, 1, 0);
1054 }
1055 RETURN_NULL();
1056}
1057/* }}} */
1058
1059/* iterator handler table */
1060zend_object_iterator_funcs spl_fixedarray_it_funcs = {
1061 spl_fixedarray_it_dtor,
1062 spl_fixedarray_it_valid,
1063 spl_fixedarray_it_get_current_data,
1064 spl_fixedarray_it_get_current_key,
1065 spl_fixedarray_it_move_forward,
1066 spl_fixedarray_it_rewind
1067};
1068
1069zend_object_iterator *spl_fixedarray_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */
1070{
1071 spl_fixedarray_it *iterator;
1072 spl_fixedarray_object *fixedarray_object = (spl_fixedarray_object*)zend_object_store_get_object(object TSRMLS_CC);
1073
1074 if (by_ref) {
1075 zend_throw_exception(spl_ce_RuntimeException, "An iterator cannot be used with foreach by reference", 0 TSRMLS_CC);
1076 return NULL;
1077 }
1078
1079 Z_ADDREF_P(object);
1080
1081 iterator = emalloc(sizeof(spl_fixedarray_it));
1082 iterator->intern.it.data = (void*)object;
1083 iterator->intern.it.funcs = &spl_fixedarray_it_funcs;
1084 iterator->intern.ce = ce;
1085 iterator->intern.value = NULL;
1086 iterator->object = fixedarray_object;
1087
1088 return (zend_object_iterator*)iterator;
1089}
1090/* }}} */
1091
1092ZEND_BEGIN_ARG_INFO_EX(arginfo_splfixedarray_construct, 0, 0, 0)
1093 ZEND_ARG_INFO(0, size)
1094ZEND_END_ARG_INFO()
1095
1096ZEND_BEGIN_ARG_INFO_EX(arginfo_fixedarray_offsetGet, 0, 0, 1)
1097 ZEND_ARG_INFO(0, index)
1098ZEND_END_ARG_INFO()
1099
1100ZEND_BEGIN_ARG_INFO_EX(arginfo_fixedarray_offsetSet, 0, 0, 2)
1101 ZEND_ARG_INFO(0, index)
1102 ZEND_ARG_INFO(0, newval)
1103ZEND_END_ARG_INFO()
1104
1105ZEND_BEGIN_ARG_INFO(arginfo_fixedarray_setSize, 0)
1106 ZEND_ARG_INFO(0, value)
1107ZEND_END_ARG_INFO()
1108
1109ZEND_BEGIN_ARG_INFO_EX(arginfo_fixedarray_fromArray, 0, 0, 1)
1110 ZEND_ARG_INFO(0, data)
1111 ZEND_ARG_INFO(0, save_indexes)
1112ZEND_END_ARG_INFO()
1113
1114ZEND_BEGIN_ARG_INFO(arginfo_splfixedarray_void, 0)
1115ZEND_END_ARG_INFO()
1116
1117static zend_function_entry spl_funcs_SplFixedArray[] = { /* {{{ */
1118 SPL_ME(SplFixedArray, __construct, arginfo_splfixedarray_construct,ZEND_ACC_PUBLIC)
1119 SPL_ME(SplFixedArray, __wakeup, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC)
1120 SPL_ME(SplFixedArray, count, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC)
1121 SPL_ME(SplFixedArray, toArray, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC)
1122 SPL_ME(SplFixedArray, fromArray, arginfo_fixedarray_fromArray, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
1123 SPL_ME(SplFixedArray, getSize, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC)
1124 SPL_ME(SplFixedArray, setSize, arginfo_fixedarray_setSize, ZEND_ACC_PUBLIC)
1125 SPL_ME(SplFixedArray, offsetExists, arginfo_fixedarray_offsetGet, ZEND_ACC_PUBLIC)
1126 SPL_ME(SplFixedArray, offsetGet, arginfo_fixedarray_offsetGet, ZEND_ACC_PUBLIC)
1127 SPL_ME(SplFixedArray, offsetSet, arginfo_fixedarray_offsetSet, ZEND_ACC_PUBLIC)
1128 SPL_ME(SplFixedArray, offsetUnset, arginfo_fixedarray_offsetGet, ZEND_ACC_PUBLIC)
1129 SPL_ME(SplFixedArray, rewind, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC)
1130 SPL_ME(SplFixedArray, current, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC)
1131 SPL_ME(SplFixedArray, key, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC)
1132 SPL_ME(SplFixedArray, next, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC)
1133 SPL_ME(SplFixedArray, valid, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC)
1134 PHP_FE_END
1135};
1136/* }}} */
1137
1138/* {{{ PHP_MINIT_FUNCTION */
1139PHP_MINIT_FUNCTION(spl_fixedarray)
1140{
1141 REGISTER_SPL_STD_CLASS_EX(SplFixedArray, spl_fixedarray_new, spl_funcs_SplFixedArray);
1142 memcpy(&spl_handler_SplFixedArray, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1143
1144 spl_handler_SplFixedArray.clone_obj = spl_fixedarray_object_clone;
1145 spl_handler_SplFixedArray.read_dimension = spl_fixedarray_object_read_dimension;
1146 spl_handler_SplFixedArray.write_dimension = spl_fixedarray_object_write_dimension;
1147 spl_handler_SplFixedArray.unset_dimension = spl_fixedarray_object_unset_dimension;
1148 spl_handler_SplFixedArray.has_dimension = spl_fixedarray_object_has_dimension;
1149 spl_handler_SplFixedArray.count_elements = spl_fixedarray_object_count_elements;
1150 spl_handler_SplFixedArray.get_properties = spl_fixedarray_object_get_properties;
1151 spl_handler_SplFixedArray.get_gc = spl_fixedarray_object_get_gc;
1152
1153 REGISTER_SPL_IMPLEMENTS(SplFixedArray, Iterator);
1154 REGISTER_SPL_IMPLEMENTS(SplFixedArray, ArrayAccess);
1155 REGISTER_SPL_IMPLEMENTS(SplFixedArray, Countable);
1156
1157 spl_ce_SplFixedArray->get_iterator = spl_fixedarray_get_iterator;
1158
1159 return SUCCESS;
1160}
1161/* }}} */
1162
1163
1164/*
1165 * Local variables:
1166 * tab-width: 4
1167 * c-basic-offset: 4
1168 * End:
1169 * vim600: noet sw=4 ts=4 fdm=marker
1170 * vim<600: noet sw=4 ts=4
1171 */
1172