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