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