LTP GCOV extension - code coverage report
Current view: directory - ext/spl - spl_array.c
Test: PHP Code Coverage
Date: 2007-04-10 Instrumented lines: 691
Code covered: 4.8 % Executed lines: 33
Legend: not executed executed

       1                 : /*
       2                 :    +----------------------------------------------------------------------+
       3                 :    | PHP Version 5                                                        |
       4                 :    +----------------------------------------------------------------------+
       5                 :    | Copyright (c) 1997-2007 The PHP Group                                |
       6                 :    +----------------------------------------------------------------------+
       7                 :    | This source file is subject to version 3.01 of the PHP license,      |
       8                 :    | that is bundled with this package in the file LICENSE, and is        |
       9                 :    | available through the world-wide-web at the following url:           |
      10                 :    | http://www.php.net/license/3_01.txt                                  |
      11                 :    | If you did not receive a copy of the PHP license and are unable to   |
      12                 :    | obtain it through the world-wide-web, please send a note to          |
      13                 :    | license@php.net so we can mail you a copy immediately.               |
      14                 :    +----------------------------------------------------------------------+
      15                 :    | Authors: Marcus Boerger <helly@php.net>                              |
      16                 :    +----------------------------------------------------------------------+
      17                 :  */
      18                 : 
      19                 : /* $Id: spl_array.c,v 1.71.2.17.2.11 2007/04/06 17:57:10 helly Exp $ */
      20                 : 
      21                 : #ifdef HAVE_CONFIG_H
      22                 : # include "config.h"
      23                 : #endif
      24                 : 
      25                 : #include "php.h"
      26                 : #include "php_ini.h"
      27                 : #include "ext/standard/info.h"
      28                 : #include "zend_interfaces.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_iterators.h"
      35                 : #include "spl_array.h"
      36                 : #include "spl_exceptions.h"
      37                 : 
      38                 : zend_object_handlers spl_handler_ArrayObject;
      39                 : PHPAPI zend_class_entry  *spl_ce_ArrayObject;
      40                 : 
      41                 : zend_object_handlers spl_handler_ArrayIterator;
      42                 : PHPAPI zend_class_entry  *spl_ce_ArrayIterator;
      43                 : PHPAPI zend_class_entry  *spl_ce_RecursiveArrayIterator;
      44                 : 
      45                 : #define SPL_ARRAY_STD_PROP_LIST      0x00000001
      46                 : #define SPL_ARRAY_ARRAY_AS_PROPS     0x00000002
      47                 : #define SPL_ARRAY_OVERLOADED_REWIND  0x00010000
      48                 : #define SPL_ARRAY_OVERLOADED_VALID   0x00020000
      49                 : #define SPL_ARRAY_OVERLOADED_KEY     0x00040000
      50                 : #define SPL_ARRAY_OVERLOADED_CURRENT 0x00080000
      51                 : #define SPL_ARRAY_OVERLOADED_NEXT    0x00100000
      52                 : #define SPL_ARRAY_IS_REF             0x01000000
      53                 : #define SPL_ARRAY_IS_SELF            0x02000000
      54                 : #define SPL_ARRAY_USE_OTHER          0x04000000
      55                 : #define SPL_ARRAY_INT_MASK           0xFFFF0000
      56                 : #define SPL_ARRAY_CLONE_MASK         0x03000007
      57                 : 
      58                 : typedef struct _spl_array_object {
      59                 :         zend_object       std;
      60                 :         zval              *array;
      61                 :         zval              *retval;
      62                 :         HashPosition      pos;
      63                 :         int               ar_flags;
      64                 :         int               is_self;
      65                 :         zend_function *   fptr_offset_get;
      66                 :         zend_function *   fptr_offset_set;
      67                 :         zend_function *   fptr_offset_has;
      68                 :         zend_function *   fptr_offset_del;
      69                 :         zend_class_entry* ce_get_iterator;
      70                 : } spl_array_object;
      71                 : 
      72               0 : static inline HashTable *spl_array_get_hash_table(spl_array_object* intern, int check_std_props TSRMLS_DC) {
      73               0 :         if ((intern->ar_flags & SPL_ARRAY_IS_SELF) != 0) {
      74               0 :                 return intern->std.properties;
      75               0 :         } else if ((intern->ar_flags & SPL_ARRAY_USE_OTHER) && (check_std_props == 0 || (intern->ar_flags & SPL_ARRAY_STD_PROP_LIST) == 0)) {
      76               0 :                 spl_array_object *other  = (spl_array_object*)zend_object_store_get_object(intern->array TSRMLS_CC);
      77               0 :                 return spl_array_get_hash_table(other, check_std_props TSRMLS_CC);
      78               0 :         } else if ((intern->ar_flags & ((check_std_props ? SPL_ARRAY_STD_PROP_LIST : 0) | SPL_ARRAY_IS_SELF)) != 0) {
      79               0 :                 return intern->std.properties;
      80                 :         } else {
      81               0 :                 return HASH_OF(intern->array);
      82                 :         }
      83                 : }
      84                 : 
      85                 : SPL_API int spl_hash_verify_pos(spl_array_object * intern TSRMLS_DC) /* {{{ */
      86               0 : {
      87               0 :         HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
      88                 :         Bucket *p;
      89                 : 
      90                 : /*      IS_CONSISTENT(ht);*/
      91                 : 
      92                 : /*      HASH_PROTECT_RECURSION(ht);*/
      93               0 :         p = ht->pListHead;
      94               0 :         while (p != NULL) {
      95               0 :                 if (p == intern->pos) {
      96               0 :                         return SUCCESS;
      97                 :                 }
      98               0 :                 p = p->pListNext;
      99                 :         }
     100                 : /*      HASH_UNPROTECT_RECURSION(ht); */
     101               0 :         zend_hash_internal_pointer_reset_ex(spl_array_get_hash_table(intern, 0 TSRMLS_CC), &intern->pos);
     102               0 :         return FAILURE;
     103                 : }
     104                 : /* }}} */
     105                 : 
     106                 : /* {{{ spl_array_object_free_storage */
     107                 : static void spl_array_object_free_storage(void *object TSRMLS_DC)
     108               0 : {
     109               0 :         spl_array_object *intern = (spl_array_object *)object;
     110                 : 
     111               0 :         zend_object_std_dtor(&intern->std TSRMLS_CC);
     112                 : 
     113               0 :         zval_ptr_dtor(&intern->array);
     114               0 :         zval_ptr_dtor(&intern->retval);
     115                 : 
     116               0 :         efree(object);
     117               0 : }
     118                 : /* }}} */
     119                 : 
     120                 : zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC);
     121                 : 
     122                 : /* {{{ spl_array_object_new */
     123                 : static zend_object_value spl_array_object_new_ex(zend_class_entry *class_type, spl_array_object **obj, zval *orig, int clone_orig TSRMLS_DC)
     124               0 : {
     125                 :         zend_object_value retval;
     126                 :         spl_array_object *intern;
     127                 :         zval *tmp;
     128               0 :         zend_class_entry * parent = class_type;
     129               0 :         int inherited = 0;
     130                 : 
     131               0 :         intern = emalloc(sizeof(spl_array_object));
     132               0 :         memset(intern, 0, sizeof(spl_array_object));
     133               0 :         *obj = intern;
     134               0 :         ALLOC_INIT_ZVAL(intern->retval);
     135                 : 
     136               0 :         zend_object_std_init(&intern->std, class_type TSRMLS_CC);
     137               0 :         zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
     138                 : 
     139               0 :         intern->ar_flags = 0;
     140               0 :         intern->ce_get_iterator = spl_ce_ArrayIterator;
     141               0 :         if (orig) {
     142               0 :                 spl_array_object *other = (spl_array_object*)zend_object_store_get_object(orig TSRMLS_CC);
     143                 : 
     144               0 :                 intern->ar_flags &= ~ SPL_ARRAY_CLONE_MASK;
     145               0 :                 intern->ar_flags |= (other->ar_flags & SPL_ARRAY_CLONE_MASK);
     146               0 :                 intern->ce_get_iterator = other->ce_get_iterator;
     147               0 :                 if (clone_orig) {
     148               0 :                         intern->array = other->array;
     149               0 :                         if (Z_OBJ_HT_P(orig) == &spl_handler_ArrayObject) {
     150               0 :                                 MAKE_STD_ZVAL(intern->array);
     151               0 :                                 array_init(intern->array);
     152               0 :                                 zend_hash_copy(HASH_OF(intern->array), HASH_OF(other->array), (copy_ctor_func_t) zval_add_ref, &tmp, sizeof(zval*));
     153                 :                         }
     154               0 :                         if (Z_OBJ_HT_P(orig) == &spl_handler_ArrayIterator) {
     155               0 :                                 ZVAL_ADDREF(other->array);
     156                 :                         }
     157                 :                 } else {
     158               0 :                         intern->array = orig;
     159               0 :                         ZVAL_ADDREF(intern->array);
     160               0 :                         intern->ar_flags |= SPL_ARRAY_IS_REF | SPL_ARRAY_USE_OTHER;
     161                 :                 }
     162                 :         } else {
     163               0 :                 MAKE_STD_ZVAL(intern->array);
     164               0 :                 array_init(intern->array);
     165               0 :                 intern->ar_flags &= ~SPL_ARRAY_IS_REF;
     166                 :         }
     167                 : 
     168               0 :         retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) spl_array_object_free_storage, NULL TSRMLS_CC);
     169               0 :         while (parent) {
     170               0 :                 if (parent == spl_ce_ArrayIterator || parent == spl_ce_RecursiveArrayIterator) {
     171               0 :                         retval.handlers = &spl_handler_ArrayIterator;
     172               0 :                         class_type->get_iterator = spl_array_get_iterator;
     173               0 :                         break;
     174               0 :                 } else if (parent == spl_ce_ArrayObject) {
     175               0 :                         retval.handlers = &spl_handler_ArrayObject;
     176               0 :                         break;
     177                 :                 }
     178               0 :                 parent = parent->parent;
     179               0 :                 inherited = 1;
     180                 :         }
     181               0 :         if (!parent) { /* this must never happen */
     182               0 :                 php_error_docref(NULL TSRMLS_CC, E_COMPILE_ERROR, "Internal compiler error, Class is not child of ArrayObject or ArrayIterator");
     183                 :         }
     184               0 :         if (inherited) {
     185               0 :                 zend_hash_find(&class_type->function_table, "offsetget",    sizeof("offsetget"),    (void **) &intern->fptr_offset_get);
     186               0 :                 if (intern->fptr_offset_get->common.scope == parent) {
     187               0 :                         intern->fptr_offset_get = NULL;
     188                 :                 }
     189               0 :                 zend_hash_find(&class_type->function_table, "offsetset",    sizeof("offsetset"),    (void **) &intern->fptr_offset_set);
     190               0 :                 if (intern->fptr_offset_set->common.scope == parent) {
     191               0 :                         intern->fptr_offset_set = NULL;
     192                 :                 }
     193               0 :                 zend_hash_find(&class_type->function_table, "offsetexists", sizeof("offsetexists"), (void **) &intern->fptr_offset_has);
     194               0 :                 if (intern->fptr_offset_has->common.scope == parent) {
     195               0 :                         intern->fptr_offset_has = NULL;
     196                 :                 }
     197               0 :                 zend_hash_find(&class_type->function_table, "offsetunset",  sizeof("offsetunset"),  (void **) &intern->fptr_offset_del);
     198               0 :                 if (intern->fptr_offset_del->common.scope == parent) {
     199               0 :                         intern->fptr_offset_del = NULL;
     200                 :                 }
     201                 :         }
     202                 :         /* Cache iterator functions if ArrayIterator or derived. Check current's */
     203                 :         /* cache since only current is always required */
     204               0 :         if (retval.handlers == &spl_handler_ArrayIterator) {
     205               0 :                 if (!class_type->iterator_funcs.zf_current) {
     206               0 :                         zend_hash_find(&class_type->function_table, "rewind",  sizeof("rewind"),  (void **) &class_type->iterator_funcs.zf_rewind);
     207               0 :                         zend_hash_find(&class_type->function_table, "valid",   sizeof("valid"),   (void **) &class_type->iterator_funcs.zf_valid);
     208               0 :                         zend_hash_find(&class_type->function_table, "key",     sizeof("key"),     (void **) &class_type->iterator_funcs.zf_key);
     209               0 :                         zend_hash_find(&class_type->function_table, "current", sizeof("current"), (void **) &class_type->iterator_funcs.zf_current);
     210               0 :                         zend_hash_find(&class_type->function_table, "next",    sizeof("next"),    (void **) &class_type->iterator_funcs.zf_next);
     211                 :                 }
     212               0 :                 if (inherited) {
     213               0 :                         if (class_type->iterator_funcs.zf_rewind->common.scope  != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_REWIND;
     214               0 :                         if (class_type->iterator_funcs.zf_valid->common.scope   != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_VALID;
     215               0 :                         if (class_type->iterator_funcs.zf_key->common.scope     != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_KEY;
     216               0 :                         if (class_type->iterator_funcs.zf_current->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_CURRENT;
     217               0 :                         if (class_type->iterator_funcs.zf_next->common.scope    != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_NEXT;
     218                 :                 }
     219                 :         }
     220                 : 
     221               0 :         zend_hash_internal_pointer_reset_ex(spl_array_get_hash_table(intern, 0 TSRMLS_CC), &intern->pos);
     222               0 :         return retval;
     223                 : }
     224                 : /* }}} */
     225                 : 
     226                 : /* {{{ spl_array_object_new */
     227                 : static zend_object_value spl_array_object_new(zend_class_entry *class_type TSRMLS_DC)
     228               0 : {
     229                 :         spl_array_object *tmp;
     230               0 :         return spl_array_object_new_ex(class_type, &tmp, NULL, 0 TSRMLS_CC);
     231                 : }
     232                 : /* }}} */
     233                 : 
     234                 : /* {{{ spl_array_object_clone */
     235                 : static zend_object_value spl_array_object_clone(zval *zobject TSRMLS_DC)
     236               0 : {
     237                 :         zend_object_value new_obj_val;
     238                 :         zend_object *old_object;
     239                 :         zend_object *new_object;
     240               0 :         zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
     241                 :         spl_array_object *intern;
     242                 : 
     243               0 :         old_object = zend_objects_get_address(zobject TSRMLS_CC);
     244               0 :         new_obj_val = spl_array_object_new_ex(old_object->ce, &intern, zobject, 1 TSRMLS_CC);
     245               0 :         new_object = &intern->std;
     246                 : 
     247               0 :         zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC);
     248                 : 
     249               0 :         return new_obj_val;
     250                 : }
     251                 : /* }}} */
     252                 : 
     253                 : static zval **spl_array_get_dimension_ptr_ptr(int check_inherited, zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
     254               0 : {
     255               0 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     256                 :         zval **retval;
     257                 :         long index;
     258                 : 
     259                 : /*  We cannot get the pointer pointer so we don't allow it here for now
     260                 :         if (check_inherited && intern->fptr_offset_get) {
     261                 :                 return zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_get, "offsetGet", NULL, offset);
     262                 :         }*/
     263                 : 
     264               0 :         if (!offset) {
     265               0 :                 return &EG(uninitialized_zval_ptr);
     266                 :         }
     267                 :         
     268               0 :         switch(Z_TYPE_P(offset)) {
     269                 :         case IS_STRING:
     270               0 :                 if (zend_symtable_find(spl_array_get_hash_table(intern, 0 TSRMLS_CC), Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void **) &retval) == FAILURE) {
     271               0 :                         zend_error(E_NOTICE, "Undefined index:  %s", Z_STRVAL_P(offset));
     272               0 :                         return &EG(uninitialized_zval_ptr);
     273                 :                 } else {
     274               0 :                         return retval;
     275                 :                 }
     276                 :         case IS_DOUBLE:
     277                 :         case IS_RESOURCE:
     278                 :         case IS_BOOL: 
     279                 :         case IS_LONG: 
     280               0 :                 if (offset->type == IS_DOUBLE) {
     281               0 :                         index = (long)Z_DVAL_P(offset);
     282                 :                 } else {
     283               0 :                         index = Z_LVAL_P(offset);
     284                 :                 }
     285               0 :                 if (zend_hash_index_find(spl_array_get_hash_table(intern, 0 TSRMLS_CC), index, (void **) &retval) == FAILURE) {
     286               0 :                         zend_error(E_NOTICE, "Undefined offset:  %ld", Z_LVAL_P(offset));
     287               0 :                         return &EG(uninitialized_zval_ptr);
     288                 :                 } else {
     289               0 :                         return retval;
     290                 :                 }
     291                 :                 break;
     292                 :         default:
     293               0 :                 zend_error(E_WARNING, "Illegal offset type");
     294               0 :                 return &EG(uninitialized_zval_ptr);
     295                 :         }
     296                 : } /* }}} */
     297                 : 
     298                 : static zval *spl_array_read_dimension_ex(int check_inherited, zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
     299               0 : {
     300                 :         zval **ret;
     301                 : 
     302               0 :         if (check_inherited) {
     303               0 :                 spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     304               0 :                 if (intern->fptr_offset_get) {
     305                 :                         zval *rv;
     306               0 :                         SEPARATE_ARG_IF_REF(offset);
     307               0 :                         zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_get, "offsetGet", &rv, offset);        
     308               0 :                         zval_ptr_dtor(&offset);
     309               0 :                         if (rv) {
     310               0 :                                 zval_ptr_dtor(&intern->retval);
     311               0 :                                 MAKE_STD_ZVAL(intern->retval);
     312               0 :                                 ZVAL_ZVAL(intern->retval, rv, 1, 1);
     313               0 :                                 return intern->retval;
     314                 :                         }
     315               0 :                         return EG(uninitialized_zval_ptr);
     316                 :                 }
     317                 :         }
     318               0 :         ret = spl_array_get_dimension_ptr_ptr(check_inherited, object, offset, type TSRMLS_CC);
     319                 : 
     320                 :         /* When in a write context,
     321                 :          * ZE has to be fooled into thinking this is in a reference set
     322                 :          * by separating (if necessary) and returning as an is_ref=1 zval (even if refcount == 1) */
     323               0 :         if ((type == BP_VAR_W || type == BP_VAR_RW) && !(*ret)->is_ref) {
     324               0 :                 if ((*ret)->refcount > 1) {
     325                 :                         zval *newval;
     326                 : 
     327                 :                         /* Separate */
     328               0 :                         MAKE_STD_ZVAL(newval);
     329               0 :                         *newval = **ret;
     330               0 :                         zval_copy_ctor(newval);
     331               0 :                         newval->refcount = 1;
     332                 : 
     333                 :                         /* Replace */
     334               0 :                         (*ret)->refcount--;
     335               0 :                         *ret = newval;
     336                 :                 }
     337                 : 
     338               0 :                 (*ret)->is_ref = 1;
     339                 :         }
     340                 : 
     341               0 :         return *ret;
     342                 : } /* }}} */
     343                 : 
     344                 : static zval *spl_array_read_dimension(zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
     345               0 : {
     346               0 :         return spl_array_read_dimension_ex(1, object, offset, type TSRMLS_CC);
     347                 : } /* }}} */
     348                 : 
     349                 : static void spl_array_write_dimension_ex(int check_inherited, zval *object, zval *offset, zval *value TSRMLS_DC) /* {{{ */
     350               0 : {
     351               0 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     352                 :         long index;
     353                 : 
     354               0 :         if (check_inherited && intern->fptr_offset_set) {
     355               0 :                 if (!offset) {
     356               0 :                         ALLOC_INIT_ZVAL(offset);
     357                 :                 } else {
     358               0 :                         SEPARATE_ARG_IF_REF(offset);
     359                 :                 }
     360               0 :                 zend_call_method_with_2_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_set, "offsetSet", NULL, offset, value);
     361               0 :                 zval_ptr_dtor(&offset);
     362               0 :                 return;
     363                 :         }
     364                 :         
     365               0 :         if (!offset) {
     366               0 :                 value->refcount++;
     367               0 :                 zend_hash_next_index_insert(spl_array_get_hash_table(intern, 0 TSRMLS_CC), (void**)&value, sizeof(void*), NULL);
     368               0 :                 return;
     369                 :         }
     370               0 :         switch(Z_TYPE_P(offset)) {
     371                 :         case IS_STRING:
     372               0 :                 if (*Z_STRVAL_P(offset) == '\0') {
     373               0 :                         zend_throw_exception(spl_ce_InvalidArgumentException, "An offset must not begin with \\0 or be empty", 0 TSRMLS_CC);
     374               0 :                         return;
     375                 :                 }
     376               0 :                 value->refcount++;
     377               0 :                 zend_symtable_update(spl_array_get_hash_table(intern, 0 TSRMLS_CC), Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void**)&value, sizeof(void*), NULL);
     378               0 :                 return;
     379                 :         case IS_DOUBLE:
     380                 :         case IS_RESOURCE:
     381                 :         case IS_BOOL: 
     382                 :         case IS_LONG: 
     383               0 :                 if (offset->type == IS_DOUBLE) {
     384               0 :                         index = (long)Z_DVAL_P(offset);
     385                 :                 } else {
     386               0 :                         index = Z_LVAL_P(offset);
     387                 :                 }
     388               0 :                 value->refcount++;
     389               0 :                 zend_hash_index_update(spl_array_get_hash_table(intern, 0 TSRMLS_CC), index, (void**)&value, sizeof(void*), NULL);
     390               0 :                 return;
     391                 :         case IS_NULL:
     392               0 :                 value->refcount++;
     393               0 :                 zend_hash_next_index_insert(spl_array_get_hash_table(intern, 0 TSRMLS_CC), (void**)&value, sizeof(void*), NULL);
     394               0 :                 return;
     395                 :         default:
     396               0 :                 zend_error(E_WARNING, "Illegal offset type");
     397               0 :                 return;
     398                 :         }
     399                 : } /* }}} */
     400                 : 
     401                 : static void spl_array_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC) /* {{{ */
     402               0 : {
     403               0 :         spl_array_write_dimension_ex(1, object, offset, value TSRMLS_CC);
     404               0 : } /* }}} */
     405                 : 
     406                 : static void spl_array_unset_dimension_ex(int check_inherited, zval *object, zval *offset TSRMLS_DC) /* {{{ */
     407               0 : {
     408               0 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     409                 :         long index;
     410                 : 
     411               0 :         if (check_inherited && intern->fptr_offset_del) {
     412               0 :                 SEPARATE_ARG_IF_REF(offset);
     413               0 :                 zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_del, "offsetUnset", NULL, offset);
     414               0 :                 zval_ptr_dtor(&offset);
     415               0 :                 return;
     416                 :         }
     417                 : 
     418               0 :         switch(Z_TYPE_P(offset)) {
     419                 :         case IS_STRING:
     420               0 :                 if (spl_array_get_hash_table(intern, 0 TSRMLS_CC) == &EG(symbol_table)) {
     421               0 :                         if (zend_delete_global_variable(Z_STRVAL_P(offset), Z_STRLEN_P(offset) TSRMLS_CC)) {
     422               0 :                                 zend_error(E_NOTICE,"Undefined index:  %s", Z_STRVAL_P(offset));
     423                 :                         }
     424                 :                 } else {
     425               0 :                         if (zend_symtable_del(spl_array_get_hash_table(intern, 0 TSRMLS_CC), Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1) == FAILURE) {
     426               0 :                                 zend_error(E_NOTICE,"Undefined index:  %s", Z_STRVAL_P(offset));
     427                 :                         }
     428                 :                 }
     429               0 :                 break;
     430                 :         case IS_DOUBLE:
     431                 :         case IS_RESOURCE:
     432                 :         case IS_BOOL: 
     433                 :         case IS_LONG: 
     434               0 :                 if (offset->type == IS_DOUBLE) {
     435               0 :                         index = (long)Z_DVAL_P(offset);
     436                 :                 } else {
     437               0 :                         index = Z_LVAL_P(offset);
     438                 :                 }
     439               0 :                 if (zend_hash_index_del(spl_array_get_hash_table(intern, 0 TSRMLS_CC), index) == FAILURE) {
     440               0 :                         zend_error(E_NOTICE,"Undefined offset:  %ld", Z_LVAL_P(offset));
     441                 :                 }
     442               0 :                 break;
     443                 :         default:
     444               0 :                 zend_error(E_WARNING, "Illegal offset type");
     445               0 :                 return;
     446                 :         }
     447               0 :         spl_hash_verify_pos(intern TSRMLS_CC); /* call rewind on FAILURE */
     448                 : } /* }}} */
     449                 : 
     450                 : static void spl_array_unset_dimension(zval *object, zval *offset TSRMLS_DC) /* {{{ */
     451               0 : {
     452               0 :         spl_array_unset_dimension_ex(1, object, offset TSRMLS_CC);
     453               0 : } /* }}} */
     454                 : 
     455                 : static int spl_array_has_dimension_ex(int check_inherited, zval *object, zval *offset, int check_empty TSRMLS_DC) /* {{{ */
     456               0 : {
     457               0 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     458                 :         long index;
     459                 :         zval *rv, **tmp;
     460                 : 
     461               0 :         if (check_inherited && intern->fptr_offset_has) {
     462               0 :                 SEPARATE_ARG_IF_REF(offset);
     463               0 :                 zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_has, "offsetExists", &rv, offset);
     464               0 :                 zval_ptr_dtor(&offset);
     465               0 :                 if (rv && zend_is_true(rv)) {
     466               0 :                         zval_ptr_dtor(&rv);
     467               0 :                         return 1;
     468                 :                 }
     469               0 :                 if (rv) {
     470               0 :                         zval_ptr_dtor(&rv);
     471                 :                 }
     472               0 :                 return 0;
     473                 :         }
     474                 :         
     475               0 :         switch(Z_TYPE_P(offset)) {
     476                 :         case IS_STRING:
     477               0 :                 if (check_empty) {
     478               0 :                         if (zend_symtable_find(spl_array_get_hash_table(intern, 0 TSRMLS_CC), Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void **) &tmp) != FAILURE && zend_is_true(*tmp)) {
     479               0 :                                 return 1;
     480                 :                         }
     481               0 :                         return 0;
     482                 :                 } else {
     483               0 :                         return zend_symtable_exists(spl_array_get_hash_table(intern, 0 TSRMLS_CC), Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1);
     484                 :                 }
     485                 :         case IS_DOUBLE:
     486                 :         case IS_RESOURCE:
     487                 :         case IS_BOOL: 
     488                 :         case IS_LONG: 
     489               0 :                 if (offset->type == IS_DOUBLE) {
     490               0 :                         index = (long)Z_DVAL_P(offset);
     491                 :                 } else {
     492               0 :                         index = Z_LVAL_P(offset);
     493                 :                 }
     494               0 :                 if (check_empty) {
     495               0 :                         HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
     496               0 :                         if (zend_hash_index_find(ht, index, (void **)&tmp) != FAILURE && zend_is_true(*tmp)) {
     497               0 :                                 return 1;
     498                 :                         }
     499               0 :                         return 0;
     500                 :                 } else {
     501               0 :                         return zend_hash_index_exists(spl_array_get_hash_table(intern, 0 TSRMLS_CC), index);
     502                 :                 }
     503                 :         default:
     504               0 :                 zend_error(E_WARNING, "Illegal offset type");
     505                 :         }
     506               0 :         return 0;
     507                 : } /* }}} */
     508                 : 
     509                 : static int spl_array_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC) /* {{{ */
     510               0 : {
     511               0 :         return spl_array_has_dimension_ex(1, object, offset, check_empty TSRMLS_CC);
     512                 : } /* }}} */
     513                 : 
     514                 : /* {{{ proto bool ArrayObject::offsetExists(mixed $index)
     515                 :        proto bool ArrayIterator::offsetExists(mixed $index)
     516                 :  Returns whether the requested $index exists. */
     517                 : SPL_METHOD(Array, offsetExists)
     518               0 : {
     519                 :         zval *index;
     520               0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) {
     521               0 :                 return;
     522                 :         }
     523               0 :         RETURN_BOOL(spl_array_has_dimension_ex(0, getThis(), index, 0 TSRMLS_CC));
     524                 : } /* }}} */
     525                 : 
     526                 : /* {{{ proto mixed ArrayObject::offsetGet(mixed $index)
     527                 :        proto mixed ArrayIterator::offsetGet(mixed $index)
     528                 :  Returns the value at the specified $index. */
     529                 : SPL_METHOD(Array, offsetGet)
     530               0 : {
     531                 :         zval *index, *value;
     532               0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) {
     533               0 :                 return;
     534                 :         }
     535               0 :         value = spl_array_read_dimension_ex(0, getThis(), index, BP_VAR_R TSRMLS_CC);
     536               0 :         RETURN_ZVAL(value, 1, 0);
     537                 : } /* }}} */
     538                 : 
     539                 : /* {{{ proto void ArrayObject::offsetSet(mixed $index, mixed $newval)
     540                 :        proto void ArrayIterator::offsetSet(mixed $index, mixed $newval)
     541                 :  Sets the value at the specified $index to $newval. */
     542                 : SPL_METHOD(Array, offsetSet)
     543               0 : {
     544                 :         zval *index, *value;
     545               0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &index, &value) == FAILURE) {
     546               0 :                 return;
     547                 :         }
     548               0 :         spl_array_write_dimension_ex(0, getThis(), index, value TSRMLS_CC);
     549                 : } /* }}} */
     550                 : 
     551                 : 
     552                 : void spl_array_iterator_append(zval *object, zval *append_value TSRMLS_DC) /* {{{ */
     553               0 : {
     554               0 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     555               0 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
     556                 : 
     557               0 :         if (!aht) {
     558               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
     559               0 :                 return;
     560                 :         }
     561                 :         
     562               0 :         if (Z_TYPE_P(intern->array) == IS_OBJECT) {
     563               0 :                 php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Cannot append properties to objects, use %s::offsetSet() instead", Z_OBJCE_P(object)->name);
     564               0 :                 return;
     565                 :         }
     566                 : 
     567               0 :         spl_array_write_dimension(object, NULL, append_value TSRMLS_CC);
     568               0 :         if (!intern->pos) {
     569               0 :                 intern->pos = aht->pListTail;
     570                 :         }
     571                 : } /* }}} */
     572                 : 
     573                 : /* {{{ proto void ArrayObject::append(mixed $newval)
     574                 :        proto void ArrayIterator::append(mixed $newval)
     575                 :  Appends the value (cannot be called for objects). */
     576                 : SPL_METHOD(Array, append)
     577               0 : {
     578                 :         zval *value;
     579                 : 
     580               0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
     581               0 :                 return;
     582                 :         }
     583               0 :         spl_array_iterator_append(getThis(), value TSRMLS_CC);
     584                 : } /* }}} */
     585                 : 
     586                 : /* {{{ proto void ArrayObject::offsetUnset(mixed $index)
     587                 :        proto void ArrayIterator::offsetUnset(mixed $index)
     588                 :  Unsets the value at the specified $index. */
     589                 : SPL_METHOD(Array, offsetUnset)
     590               0 : {
     591                 :         zval *index;
     592               0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) {
     593               0 :                 return;
     594                 :         }
     595               0 :         spl_array_unset_dimension_ex(0, getThis(), index TSRMLS_CC);
     596                 : } /* }}} */
     597                 : 
     598                 : /* {{ proto array ArrayObject::getArrayCopy()
     599                 :       proto array ArrayIterator::getArrayCopy()
     600                 :  Return a copy of the contained array */
     601                 : SPL_METHOD(Array, getArrayCopy)
     602               0 : {
     603               0 :         zval *object = getThis(), *tmp;
     604               0 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     605                 :     
     606               0 :     array_init(return_value);
     607               0 :         zend_hash_copy(HASH_OF(return_value), spl_array_get_hash_table(intern, 0 TSRMLS_CC), (copy_ctor_func_t) zval_add_ref, &tmp, sizeof(zval*));
     608               0 : } /* }}} */
     609                 : 
     610                 : static HashTable *spl_array_get_properties(zval *object TSRMLS_DC) /* {{{ */
     611               0 : {
     612               0 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     613                 : 
     614               0 :         return spl_array_get_hash_table(intern, 1 TSRMLS_CC);
     615                 : } /* }}} */
     616                 : 
     617                 : static zval *spl_array_read_property(zval *object, zval *member, int type TSRMLS_DC) /* {{{ */
     618               0 : {
     619               0 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     620                 : 
     621               0 :         if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
     622                 :         && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) {
     623               0 :                 return spl_array_read_dimension(object, member, type TSRMLS_CC);
     624                 :         }
     625               0 :         return std_object_handlers.read_property(object, member, type TSRMLS_CC);
     626                 : } /* }}} */
     627                 : 
     628                 : static void spl_array_write_property(zval *object, zval *member, zval *value TSRMLS_DC) /* {{{ */
     629               0 : {
     630               0 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     631                 : 
     632               0 :         if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
     633                 :         && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) {
     634               0 :                 spl_array_write_dimension(object, member, value TSRMLS_CC);
     635               0 :                 return;
     636                 :         }
     637               0 :         std_object_handlers.write_property(object, member, value TSRMLS_CC);
     638                 : } /* }}} */
     639                 : 
     640                 : static zval **spl_array_get_property_ptr_ptr(zval *object, zval *member TSRMLS_DC) /* {{{ */
     641               0 : {
     642               0 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     643                 : 
     644               0 :         if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
     645                 :         && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) {
     646               0 :                 return spl_array_get_dimension_ptr_ptr(1, object, member, 0 TSRMLS_CC);         
     647                 :         }
     648               0 :         return std_object_handlers.get_property_ptr_ptr(object, member TSRMLS_CC);
     649                 : } /* }}} */
     650                 : 
     651                 : static int spl_array_has_property(zval *object, zval *member, int has_set_exists TSRMLS_DC) /* {{{ */
     652               0 : {
     653               0 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     654                 : 
     655               0 :         if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0) {
     656               0 :                 if (!std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) {
     657               0 :                         return spl_array_has_dimension(object, member, has_set_exists TSRMLS_CC);
     658                 :                 }
     659               0 :                 return 0; /* if prop doesn't exist at all mode 0/1 cannot return 1 */
     660                 :         }
     661               0 :         return std_object_handlers.has_property(object, member, has_set_exists TSRMLS_CC);
     662                 : } /* }}} */
     663                 : 
     664                 : static void spl_array_rewind(spl_array_object *intern TSRMLS_DC);
     665                 : 
     666                 : static void spl_array_unset_property(zval *object, zval *member TSRMLS_DC) /* {{{ */
     667               0 : {
     668               0 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     669                 : 
     670               0 :         if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
     671                 :         && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) {
     672               0 :                 spl_array_unset_dimension(object, member TSRMLS_CC);
     673               0 :                 spl_array_rewind(intern TSRMLS_CC); /* because deletion might invalidate position */
     674               0 :                 return;
     675                 :         }
     676               0 :         std_object_handlers.unset_property(object, member TSRMLS_CC);
     677                 : } /* }}} */
     678                 : 
     679                 : static int spl_array_skip_protected(spl_array_object *intern TSRMLS_DC) /* {{{ */
     680               0 : {
     681                 :         char *string_key;
     682                 :         uint string_length;
     683                 :         ulong num_key;
     684               0 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
     685                 : 
     686               0 :         if (Z_TYPE_P(intern->array) == IS_OBJECT) {
     687                 :                 do {
     688               0 :                         if (zend_hash_get_current_key_ex(aht, &string_key, &string_length, &num_key, 0, &intern->pos) == HASH_KEY_IS_STRING) {
     689               0 :                                 if (!string_length || string_key[0]) {
     690               0 :                                         return SUCCESS;
     691                 :                                 }
     692                 :                         } else {
     693               0 :                                 return SUCCESS;
     694                 :                         }
     695               0 :                         if (zend_hash_has_more_elements_ex(aht, &intern->pos) != SUCCESS) {
     696               0 :                                 return FAILURE;
     697                 :                         }
     698               0 :                         zend_hash_move_forward_ex(aht, &intern->pos);
     699               0 :                 } while (1);
     700                 :         }
     701               0 :         return FAILURE;
     702                 : }
     703                 : /* }}} */
     704                 : 
     705                 : static int spl_array_next(spl_array_object *intern TSRMLS_DC) /* {{{ */
     706               0 : {
     707               0 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
     708                 : 
     709               0 :         if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(intern TSRMLS_CC) == FAILURE) {
     710               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
     711               0 :                 return FAILURE;
     712                 :         } else {
     713               0 :                 zend_hash_move_forward_ex(aht, &intern->pos);
     714               0 :                 if (Z_TYPE_P(intern->array) == IS_OBJECT) {
     715               0 :                         return spl_array_skip_protected(intern TSRMLS_CC);
     716                 :                 } else {
     717               0 :                         return zend_hash_has_more_elements_ex(aht, &intern->pos);
     718                 :                 }
     719                 :         }
     720                 : } /* }}} */
     721                 : 
     722                 : /* define an overloaded iterator structure */
     723                 : typedef struct {
     724                 :         zend_user_iterator    intern;
     725                 :         spl_array_object      *object;
     726                 : } spl_array_it;
     727                 : 
     728                 : static void spl_array_it_dtor(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
     729               0 : {
     730               0 :         spl_array_it *iterator = (spl_array_it *)iter;
     731                 : 
     732               0 :         zend_user_it_invalidate_current(iter TSRMLS_CC);
     733               0 :         zval_ptr_dtor((zval**)&iterator->intern.it.data);
     734                 : 
     735               0 :         efree(iterator);
     736               0 : }
     737                 : /* }}} */
     738                 :         
     739                 : static int spl_array_it_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
     740               0 : {
     741               0 :         spl_array_it       *iterator = (spl_array_it *)iter;
     742               0 :         spl_array_object   *object   = iterator->object;
     743               0 :         HashTable          *aht      = spl_array_get_hash_table(object, 0 TSRMLS_CC);
     744                 : 
     745               0 :         if (object->ar_flags & SPL_ARRAY_OVERLOADED_VALID) {
     746               0 :                 return zend_user_it_valid(iter TSRMLS_CC);
     747                 :         } else {
     748               0 :                 if (!aht) {
     749               0 :                         php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::valid(): Array was modified outside object and is no longer an array");
     750               0 :                         return FAILURE;
     751                 :                 }
     752                 :         
     753               0 :                 if (object->pos && (object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(object TSRMLS_CC) == FAILURE) {
     754               0 :                         php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::valid(): Array was modified outside object and internal position is no longer valid");
     755               0 :                         return FAILURE;
     756                 :                 } else {
     757               0 :                         return zend_hash_has_more_elements_ex(aht, &object->pos);
     758                 :                 }
     759                 :         }
     760                 : }
     761                 : /* }}} */
     762                 : 
     763                 : static void spl_array_it_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) /* {{{ */
     764               0 : {
     765               0 :         spl_array_it       *iterator = (spl_array_it *)iter;
     766               0 :         spl_array_object   *object   = iterator->object;
     767               0 :         HashTable          *aht      = spl_array_get_hash_table(object, 0 TSRMLS_CC);
     768                 : 
     769               0 :         if (object->ar_flags & SPL_ARRAY_OVERLOADED_CURRENT) {
     770               0 :                 zend_user_it_get_current_data(iter, data TSRMLS_CC);
     771                 :         } else {
     772               0 :                 if (zend_hash_get_current_data_ex(aht, (void**)data, &object->pos) == FAILURE) {
     773               0 :                         *data = NULL;
     774                 :                 }
     775                 :         }
     776               0 : }
     777                 : /* }}} */
     778                 : 
     779                 : static int spl_array_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */
     780               0 : {
     781               0 :         spl_array_it       *iterator = (spl_array_it *)iter;
     782               0 :         spl_array_object   *object   = iterator->object;
     783               0 :         HashTable          *aht      = spl_array_get_hash_table(object, 0 TSRMLS_CC);
     784                 : 
     785               0 :         if (object->ar_flags & SPL_ARRAY_OVERLOADED_KEY) {
     786               0 :                 return zend_user_it_get_current_key(iter, str_key, str_key_len, int_key TSRMLS_CC);
     787                 :         } else {
     788               0 :                 if (!aht) {
     789               0 :                         php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::current(): Array was modified outside object and is no longer an array");
     790               0 :                         return HASH_KEY_NON_EXISTANT;
     791                 :                 }
     792                 :         
     793               0 :                 if ((object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(object TSRMLS_CC) == FAILURE) {
     794               0 :                         php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::current(): Array was modified outside object and internal position is no longer valid");
     795               0 :                         return HASH_KEY_NON_EXISTANT;
     796                 :                 }
     797                 :         
     798               0 :                 return zend_hash_get_current_key_ex(aht, str_key, str_key_len, int_key, 1, &object->pos);
     799                 :         }
     800                 : }
     801                 : /* }}} */
     802                 : 
     803                 : static void spl_array_it_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
     804               0 : {
     805               0 :         spl_array_it       *iterator = (spl_array_it *)iter;
     806               0 :         spl_array_object   *object   = iterator->object;
     807               0 :         HashTable          *aht      = spl_array_get_hash_table(object, 0 TSRMLS_CC);
     808                 : 
     809               0 :         if (object->ar_flags & SPL_ARRAY_OVERLOADED_NEXT) {
     810               0 :                 zend_user_it_move_forward(iter TSRMLS_CC);
     811                 :         } else {
     812               0 :                 zend_user_it_invalidate_current(iter TSRMLS_CC);
     813               0 :                 if (!aht) {
     814               0 :                         php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::current(): Array was modified outside object and is no longer an array");
     815               0 :                         return;
     816                 :                 }
     817                 :         
     818               0 :                 if ((object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(object TSRMLS_CC) == FAILURE) {
     819               0 :                         php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::next(): Array was modified outside object and internal position is no longer valid");
     820                 :                 } else {
     821               0 :                         spl_array_next(object TSRMLS_CC);
     822                 :                 }
     823                 :         }
     824                 : }
     825                 : /* }}} */
     826                 : 
     827                 : static void spl_array_rewind(spl_array_object *intern TSRMLS_DC) /* {{{ */
     828               0 : {
     829               0 :         HashTable          *aht      = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
     830                 : 
     831               0 :         if (!aht) {
     832               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::rewind(): Array was modified outside object and is no longer an array");
     833               0 :                 return;
     834                 :         }
     835                 : 
     836               0 :         zend_hash_internal_pointer_reset_ex(aht, &intern->pos);
     837               0 :         spl_array_skip_protected(intern TSRMLS_CC);
     838                 : }
     839                 : /* }}} */
     840                 : 
     841                 : static void spl_array_it_rewind(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
     842               0 : {
     843               0 :         spl_array_it       *iterator = (spl_array_it *)iter;
     844               0 :         spl_array_object   *object   = iterator->object;
     845                 : 
     846               0 :         if (object->ar_flags & SPL_ARRAY_OVERLOADED_REWIND) {
     847               0 :                 zend_user_it_rewind(iter TSRMLS_CC);
     848                 :         } else {
     849               0 :                 zend_user_it_invalidate_current(iter TSRMLS_CC);
     850               0 :                 spl_array_rewind(object TSRMLS_CC);
     851                 :         }
     852               0 : }
     853                 : /* }}} */
     854                 : 
     855                 : /* iterator handler table */
     856                 : zend_object_iterator_funcs spl_array_it_funcs = {
     857                 :         spl_array_it_dtor,
     858                 :         spl_array_it_valid,
     859                 :         spl_array_it_get_current_data,
     860                 :         spl_array_it_get_current_key,
     861                 :         spl_array_it_move_forward,
     862                 :         spl_array_it_rewind
     863                 : };
     864                 : 
     865                 : zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */
     866               0 : {
     867                 :         spl_array_it       *iterator;
     868               0 :         spl_array_object   *array_object = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     869                 : 
     870               0 :         if (by_ref && (array_object->ar_flags & SPL_ARRAY_OVERLOADED_CURRENT)) {
     871               0 :                 zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
     872                 :         }
     873                 : 
     874               0 :         iterator     = emalloc(sizeof(spl_array_it));
     875                 : 
     876               0 :         object->refcount++;
     877               0 :         iterator->intern.it.data = (void*)object;
     878               0 :         iterator->intern.it.funcs = &spl_array_it_funcs;
     879               0 :         iterator->intern.ce = ce;
     880               0 :         iterator->intern.value = NULL;
     881               0 :         iterator->object = array_object;
     882                 :         
     883               0 :         return (zend_object_iterator*)iterator;
     884                 : }
     885                 : /* }}} */
     886                 : 
     887                 : /* {{{ proto void ArrayObject::__construct(array|object ar = array() [, int flags = 0 [, string iterator_class = "ArrayIterator"]])
     888                 :        proto void ArrayIterator::__construct(array|object ar = array() [, int flags = 0])
     889                 :  Cronstructs a new array iterator from a path. */
     890                 : SPL_METHOD(Array, __construct)
     891               0 : {
     892               0 :         zval *object = getThis();
     893                 :         spl_array_object *intern;
     894                 :         zval *array;
     895               0 :         long ar_flags = 0;
     896                 :         char *class_name;
     897                 :         int class_name_len;
     898                 :         zend_class_entry ** pce_get_iterator;
     899                 : 
     900               0 :         if (ZEND_NUM_ARGS() == 0) {
     901               0 :                 return; /* nothing to do */
     902                 :         }
     903               0 :         php_set_error_handling(EH_THROW, spl_ce_InvalidArgumentException TSRMLS_CC);
     904                 : 
     905               0 :         intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     906                 : 
     907               0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|ls", &array, &ar_flags, &class_name, &class_name_len) == FAILURE) {
     908               0 :                 php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
     909               0 :                 return;
     910                 :         }
     911                 : 
     912               0 :         if (ZEND_NUM_ARGS() > 2) {
     913               0 :                 if (zend_lookup_class(class_name, class_name_len, &pce_get_iterator TSRMLS_CC) == FAILURE) {
     914               0 :                         zend_throw_exception(spl_ce_InvalidArgumentException, "A class that implements Iterator must be specified", 0 TSRMLS_CC);
     915               0 :                         php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
     916               0 :                         return;
     917                 :                 }
     918               0 :                 intern->ce_get_iterator = *pce_get_iterator;
     919                 :         }
     920                 : 
     921               0 :         ar_flags &= ~SPL_ARRAY_INT_MASK;
     922                 : 
     923               0 :         if (Z_TYPE_P(array) == IS_OBJECT && (Z_OBJ_HT_P(array) == &spl_handler_ArrayObject || Z_OBJ_HT_P(array) == &spl_handler_ArrayIterator)) {
     924               0 :                 zval_ptr_dtor(&intern->array);
     925               0 :                 if (ZEND_NUM_ARGS() == 1)
     926                 :                 {
     927               0 :                         spl_array_object *other = (spl_array_object*)zend_object_store_get_object(array TSRMLS_CC);
     928               0 :                         ar_flags = other->ar_flags & ~SPL_ARRAY_INT_MASK;
     929                 :                 }               
     930               0 :                 ar_flags |= SPL_ARRAY_USE_OTHER;
     931               0 :                 intern->array = array;
     932                 :         } else {
     933               0 :                 if (Z_TYPE_P(array) != IS_OBJECT && Z_TYPE_P(array) != IS_ARRAY) {
     934               0 :                         php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
     935               0 :                         zend_throw_exception(spl_ce_InvalidArgumentException, "Passed variable is not an array or object, using empty array instead", 0 TSRMLS_CC);
     936               0 :                         return;
     937                 :                 }
     938               0 :                 zval_ptr_dtor(&intern->array);
     939               0 :                 intern->array = array;
     940                 :         }
     941               0 :         if (object == array) {
     942               0 :                 intern->ar_flags |= SPL_ARRAY_IS_SELF;
     943               0 :                 intern->ar_flags &= ~SPL_ARRAY_USE_OTHER;
     944                 :         } else {
     945               0 :                 intern->ar_flags &= ~SPL_ARRAY_IS_SELF;
     946                 :         }
     947               0 :         intern->ar_flags |= ar_flags;
     948               0 :         ZVAL_ADDREF(intern->array);
     949               0 :         if (Z_TYPE_P(array) == IS_OBJECT) {
     950               0 :                 zend_object_get_properties_t handler = Z_OBJ_HANDLER_P(array, get_properties);
     951               0 :                 if ((handler != std_object_handlers.get_properties && handler != spl_array_get_properties)
     952                 :                 || !spl_array_get_hash_table(intern, 0 TSRMLS_CC)) {
     953               0 :                         php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
     954               0 :                         zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Overloaded object of type %s is not compatible with %s", Z_OBJCE_P(array)->name, intern->std.ce->name);
     955               0 :                         return;
     956                 :                 }
     957                 :         }
     958                 : 
     959               0 :         spl_array_rewind(intern TSRMLS_CC);
     960                 : 
     961               0 :         php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
     962                 : }
     963                 : /* }}} */
     964                 : 
     965                 : /* {{{ proto void ArrayObject::setIteratorClass(string iterator_class)
     966                 :    Set the class used in getIterator. */
     967                 : SPL_METHOD(Array, setIteratorClass)
     968               0 : {
     969               0 :         zval *object = getThis();
     970               0 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     971                 :         char *class_name;
     972                 :         int class_name_len;
     973                 :         zend_class_entry ** pce_get_iterator;
     974                 : 
     975               0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &class_name, &class_name_len) == FAILURE) {
     976               0 :                 php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
     977               0 :                 return;
     978                 :         }
     979                 : 
     980               0 :         if (zend_lookup_class(class_name, class_name_len, &pce_get_iterator TSRMLS_CC) == FAILURE) {
     981               0 :                 zend_throw_exception(spl_ce_InvalidArgumentException, "A class that implements Iterator must be specified", 0 TSRMLS_CC);
     982               0 :                 php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
     983               0 :                 return;
     984                 :         }
     985               0 :         intern->ce_get_iterator = *pce_get_iterator;
     986                 : }
     987                 : /* }}} */
     988                 : 
     989                 : /* {{{ proto string ArrayObject::getIteratorClass()
     990                 :    Get the class used in getIterator. */
     991                 : SPL_METHOD(Array, getIteratorClass)
     992               0 : {
     993               0 :         zval *object = getThis();
     994               0 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     995                 : 
     996               0 :         RETURN_STRING(intern->ce_get_iterator->name, 1);
     997                 : }
     998                 : /* }}} */
     999                 : 
    1000                 : /* {{{ proto int ArrayObject::getFlags()
    1001                 :    Get flags */
    1002                 : SPL_METHOD(Array, getFlags)
    1003               0 : {
    1004               0 :         zval *object = getThis();
    1005               0 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1006                 :         
    1007               0 :         RETURN_LONG(intern->ar_flags & ~SPL_ARRAY_INT_MASK);
    1008                 : }
    1009                 : /* }}} */
    1010                 : 
    1011                 : /* {{{ proto void ArrayObject::setFlags(int flags)
    1012                 :    Set flags */
    1013                 : SPL_METHOD(Array, setFlags)
    1014               0 : {
    1015               0 :         zval *object = getThis();
    1016               0 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1017               0 :         long ar_flags = 0;
    1018                 : 
    1019               0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &ar_flags) == FAILURE) {
    1020               0 :                 return;
    1021                 :         }
    1022                 :         
    1023               0 :         intern->ar_flags = (intern->ar_flags & SPL_ARRAY_INT_MASK) | (ar_flags & ~SPL_ARRAY_INT_MASK);
    1024                 : }
    1025                 : /* }}} */
    1026                 : 
    1027                 : /* {{{ proto Array|Object ArrayObject::exchangeArray(Array|Object ar = array())
    1028                 :    Replace the referenced array or object with a new one and return the old one (right now copy - to be changed) */
    1029                 : SPL_METHOD(Array, exchangeArray)
    1030               0 : {
    1031               0 :         zval *object = getThis(), *tmp, **array;
    1032               0 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1033                 : 
    1034               0 :         array_init(return_value);
    1035               0 :         zend_hash_copy(HASH_OF(return_value), spl_array_get_hash_table(intern, 0 TSRMLS_CC), (copy_ctor_func_t) zval_add_ref, &tmp, sizeof(zval*));
    1036                 :         
    1037               0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &array) == FAILURE) {
    1038               0 :                 return;
    1039                 :         }
    1040               0 :         if (Z_TYPE_PP(array) == IS_OBJECT && intern == (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC)) {
    1041               0 :                 zval_ptr_dtor(&intern->array);
    1042               0 :                 array = &object;
    1043               0 :                 intern->array = object;
    1044               0 :         } else if (Z_TYPE_PP(array) == IS_OBJECT && (Z_OBJ_HT_PP(array) == &spl_handler_ArrayObject || Z_OBJ_HT_PP(array) == &spl_handler_ArrayIterator)) {
    1045               0 :                 spl_array_object *other  = (spl_array_object*)zend_object_store_get_object(*array TSRMLS_CC);
    1046               0 :                 zval_ptr_dtor(&intern->array);
    1047               0 :                 intern->array = other->array;
    1048                 :         } else {
    1049               0 :                 if (Z_TYPE_PP(array) != IS_OBJECT && !HASH_OF(*array)) {
    1050               0 :                         zend_throw_exception(spl_ce_InvalidArgumentException, "Passed variable is not an array or object, using empty array instead", 0 TSRMLS_CC);
    1051               0 :                         return;
    1052                 :                 }
    1053               0 :                 zval_ptr_dtor(&intern->array);
    1054               0 :                 intern->array = *array;
    1055                 :         }
    1056               0 :         if (object == *array) {
    1057               0 :                 intern->ar_flags |= SPL_ARRAY_IS_SELF;
    1058                 :         } else {
    1059               0 :                 intern->ar_flags &= ~SPL_ARRAY_IS_SELF;
    1060                 :         }
    1061               0 :         ZVAL_ADDREF(intern->array);
    1062                 : 
    1063               0 :         spl_array_rewind(intern TSRMLS_CC);
    1064                 : }
    1065                 : /* }}} */
    1066                 : 
    1067                 : /* {{{ proto ArrayIterator ArrayObject::getIterator()
    1068                 :    Create a new iterator from a ArrayObject instance */
    1069                 : SPL_METHOD(Array, getIterator)
    1070               0 : {
    1071               0 :         zval *object = getThis();
    1072               0 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1073                 :         spl_array_object *iterator;
    1074               0 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
    1075                 : 
    1076               0 :         if (!aht) {
    1077               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
    1078               0 :                 return;
    1079                 :         }
    1080                 : 
    1081               0 :         return_value->type = IS_OBJECT;
    1082               0 :         return_value->value.obj = spl_array_object_new_ex(intern->ce_get_iterator, &iterator, object, 0 TSRMLS_CC);
    1083               0 :         return_value->refcount = 1;
    1084               0 :         return_value->is_ref = 1;
    1085                 : }
    1086                 : /* }}} */
    1087                 : 
    1088                 : /* {{{ proto void ArrayIterator::rewind()
    1089                 :    Rewind array back to the start */
    1090                 : SPL_METHOD(Array, rewind)
    1091               0 : {
    1092               0 :         zval *object = getThis();
    1093               0 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1094                 : 
    1095               0 :         spl_array_rewind(intern TSRMLS_CC);
    1096               0 : }
    1097                 : /* }}} */
    1098                 : 
    1099                 : /* {{{ proto void ArrayIterator::seek(int $position)
    1100                 :  Seek to position. */
    1101                 : SPL_METHOD(Array, seek)
    1102               0 : {
    1103                 :         long opos, position;
    1104               0 :         zval *object = getThis();
    1105               0 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1106               0 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
    1107                 :         int result;
    1108                 : 
    1109               0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &position) == FAILURE) {
    1110               0 :                 return;
    1111                 :         }
    1112                 : 
    1113               0 :         if (!aht) {
    1114               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
    1115               0 :                 return;
    1116                 :         }
    1117                 : 
    1118               0 :         opos = position;
    1119                 : 
    1120               0 :         if (position >= 0) { /* negative values are not supported */
    1121               0 :                 zend_hash_internal_pointer_reset_ex(aht, &intern->pos);
    1122               0 :                 result = SUCCESS;
    1123                 :                 
    1124               0 :                 while (position-- > 0 && (result = spl_array_next(intern TSRMLS_CC)) == SUCCESS);
    1125                 :         
    1126               0 :                 if (result == SUCCESS && zend_hash_has_more_elements_ex(aht, &intern->pos) == SUCCESS) {
    1127               0 :                         return; /* ok */
    1128                 :                 }
    1129                 :         }
    1130               0 :         zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0 TSRMLS_CC, "Seek position %ld is out of range", opos);
    1131                 : } /* }}} */
    1132                 : 
    1133                 : int spl_array_object_count_elements(zval *object, long *count TSRMLS_DC) /* {{{ */
    1134               0 : {
    1135               0 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1136               0 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
    1137                 :         HashPosition pos;
    1138                 : 
    1139               0 :         if (!aht) {
    1140               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
    1141               0 :                 *count = 0;
    1142               0 :                 return FAILURE;
    1143                 :         }
    1144                 : 
    1145               0 :         if (Z_TYPE_P(intern->array) == IS_OBJECT) {
    1146                 :                 /* We need to store the 'pos' since we'll modify it in the functions 
    1147                 :                  * we're going to call and which do not support 'pos' as parameter. */
    1148               0 :                 pos = intern->pos;
    1149               0 :                 *count = 0;
    1150               0 :                 zend_hash_internal_pointer_reset_ex(aht, &intern->pos);
    1151               0 :                 while(intern->pos && spl_array_next(intern TSRMLS_CC) == SUCCESS) {
    1152               0 :                         (*count)++;
    1153                 :                 }
    1154               0 :                 intern->pos = pos;
    1155               0 :                 return SUCCESS;
    1156                 :         } else {
    1157               0 :                 *count = zend_hash_num_elements(aht);
    1158               0 :                 return SUCCESS;
    1159                 :         }
    1160                 : } /* }}} */
    1161                 : 
    1162                 : /* {{{ proto int ArrayObject::count()
    1163                 :        proto int ArrayIterator::count()
    1164                 :  Return the number of elements in the Iterator. */
    1165                 : SPL_METHOD(Array, count)
    1166               0 : {
    1167                 :         long count;
    1168                 : 
    1169               0 :         spl_array_object_count_elements(getThis(), &count TSRMLS_CC);
    1170               0 :         RETURN_LONG(count);
    1171                 : } /* }}} */
    1172                 : 
    1173                 : static void spl_array_method(INTERNAL_FUNCTION_PARAMETERS, char *fname, int fname_len, int use_arg)
    1174               0 : {
    1175               0 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
    1176               0 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
    1177                 :         zval tmp, *arg;
    1178                 :         
    1179               0 :         INIT_PZVAL(&tmp);
    1180               0 :         Z_TYPE(tmp) = IS_ARRAY;
    1181               0 :         Z_ARRVAL(tmp) = aht;
    1182                 :         
    1183               0 :         if (use_arg) {
    1184               0 :                 if (ZEND_NUM_ARGS() != 1 || zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "z", &arg) == FAILURE) {
    1185               0 :                         zend_throw_exception(spl_ce_BadMethodCallException, "Function expects exactly one argument", 0 TSRMLS_CC);
    1186               0 :                         return;
    1187                 :                 }
    1188               0 :                 zend_call_method(NULL, NULL, NULL, fname, fname_len, &return_value, 2, &tmp, arg TSRMLS_CC);
    1189                 :         } else {
    1190               0 :                 zend_call_method(NULL, NULL, NULL, fname, fname_len, &return_value, 1, &tmp, NULL TSRMLS_CC);
    1191                 :         }
    1192                 : }
    1193                 : 
    1194                 : #define SPL_ARRAY_METHOD(cname, fname, use_arg) \
    1195                 : SPL_METHOD(cname, fname) \
    1196                 : { \
    1197                 :         spl_array_method(INTERNAL_FUNCTION_PARAM_PASSTHRU, #fname, sizeof(#fname)-1, use_arg); \
    1198                 : }
    1199                 : 
    1200                 : /* {{{ proto int ArrayObject::asort()
    1201                 :        proto int ArrayIterator::asort()
    1202                 :  Sort the entries by values. */
    1203               0 : SPL_ARRAY_METHOD(Array, asort, 0)
    1204                 : 
    1205                 : /* {{{ proto int ArrayObject::ksort()
    1206                 :        proto int ArrayIterator::ksort()
    1207                 :  Sort the entries by key. */
    1208               0 : SPL_ARRAY_METHOD(Array, ksort, 0)
    1209                 : 
    1210                 : /* {{{ proto int ArrayObject::uasort(callback cmp_function)
    1211                 :        proto int ArrayIterator::uasort(callback cmp_function)
    1212                 :  Sort the entries by values user defined function. */
    1213               0 : SPL_ARRAY_METHOD(Array, uasort, 1)
    1214                 : 
    1215                 : /* {{{ proto int ArrayObject::uksort(callback cmp_function)
    1216                 :        proto int ArrayIterator::uksort(callback cmp_function)
    1217                 :  Sort the entries by key using user defined function. */
    1218               0 : SPL_ARRAY_METHOD(Array, uksort, 1)
    1219                 : 
    1220                 : /* {{{ proto int ArrayObject::natsort()
    1221                 :        proto int ArrayIterator::natsort()
    1222                 :  Sort the entries by values using "natural order" algorithm. */
    1223               0 : SPL_ARRAY_METHOD(Array, natsort, 0)
    1224                 : 
    1225                 : /* {{{ proto int ArrayObject::natcasesort()
    1226                 :        proto int ArrayIterator::natcasesort()
    1227                 :  Sort the entries by key using case insensitive "natural order" algorithm. */
    1228               0 : SPL_ARRAY_METHOD(Array, natcasesort, 0)
    1229                 : 
    1230                 : /* {{{ proto mixed|NULL ArrayIterator::current()
    1231                 :    Return current array entry */
    1232                 : SPL_METHOD(Array, current)
    1233               0 : {
    1234               0 :         zval *object = getThis();
    1235               0 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1236                 :         zval **entry;
    1237               0 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
    1238                 : 
    1239               0 :         if (!aht) {
    1240               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
    1241               0 :                 return;
    1242                 :         }
    1243                 : 
    1244               0 :         if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(intern TSRMLS_CC) == FAILURE) {
    1245               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
    1246               0 :                 return;
    1247                 :         }
    1248                 : 
    1249               0 :         if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) {
    1250               0 :                 return;
    1251                 :         }
    1252               0 :         RETVAL_ZVAL(*entry, 1, 0);
    1253                 : }
    1254                 : /* }}} */
    1255                 : 
    1256                 : /* {{{ proto mixed|NULL ArrayIterator::key()
    1257                 :    Return current array key */
    1258                 : SPL_METHOD(Array, key)
    1259               0 : {
    1260               0 :         spl_array_iterator_key(getThis(), return_value TSRMLS_CC);
    1261               0 : }
    1262                 : 
    1263                 : void spl_array_iterator_key(zval *object, zval *return_value TSRMLS_DC) /* {{{ */
    1264               0 : {
    1265               0 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1266                 :         char *string_key;
    1267                 :         uint string_length;
    1268                 :         ulong num_key;
    1269               0 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
    1270                 : 
    1271               0 :         if (!aht) {
    1272               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
    1273               0 :                 return;
    1274                 :         }
    1275                 : 
    1276               0 :         if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(intern TSRMLS_CC) == FAILURE) {
    1277               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
    1278               0 :                 return;
    1279                 :         }
    1280                 : 
    1281               0 :         switch (zend_hash_get_current_key_ex(aht, &string_key, &string_length, &num_key, 1, &intern->pos)) {
    1282                 :                 case HASH_KEY_IS_STRING:
    1283               0 :                         RETVAL_STRINGL(string_key, string_length - 1, 0);
    1284               0 :                         break;
    1285                 :                 case HASH_KEY_IS_LONG:
    1286               0 :                         RETVAL_LONG(num_key);
    1287               0 :                         break;
    1288                 :                 case HASH_KEY_NON_EXISTANT:
    1289               0 :                         return;
    1290                 :         }
    1291                 : }
    1292                 : /* }}} */
    1293                 : 
    1294                 : /* {{{ proto void ArrayIterator::next()
    1295                 :    Move to next entry */
    1296                 : SPL_METHOD(Array, next)
    1297               0 : {
    1298               0 :         zval *object = getThis();
    1299               0 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1300               0 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
    1301                 : 
    1302               0 :         if (!aht) {
    1303               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
    1304               0 :                 return;
    1305                 :         }
    1306                 : 
    1307               0 :         spl_array_next(intern TSRMLS_CC);
    1308                 : }
    1309                 : /* }}} */
    1310                 : 
    1311                 : /* {{{ proto bool ArrayIterator::valid()
    1312                 :    Check whether array contains more entries */
    1313                 : SPL_METHOD(Array, valid)
    1314               0 : {
    1315               0 :         zval *object = getThis();
    1316               0 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1317               0 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
    1318                 : 
    1319               0 :         if (!aht) {
    1320               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
    1321               0 :                 return;
    1322                 :         }
    1323                 : 
    1324               0 :         if (intern->pos && (intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(intern TSRMLS_CC) == FAILURE) {
    1325               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
    1326               0 :                 RETURN_FALSE;
    1327                 :         } else {
    1328               0 :                 RETURN_BOOL(zend_hash_has_more_elements_ex(aht, &intern->pos) == SUCCESS);
    1329                 :         }
    1330                 : }
    1331                 : /* }}} */
    1332                 : 
    1333                 : /* {{{ proto bool RecursiveArrayIterator::hasChildren()
    1334                 :    Check whether current element has children (e.g. is an array) */
    1335                 : SPL_METHOD(Array, hasChildren)
    1336               0 : {
    1337               0 :         zval *object = getThis(), **entry;
    1338               0 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1339               0 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
    1340                 :         
    1341               0 :         if (!aht) {
    1342               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
    1343               0 :                 RETURN_FALSE;
    1344                 :         }
    1345                 : 
    1346               0 :         if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(intern TSRMLS_CC) == FAILURE) {
    1347               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
    1348               0 :                 RETURN_FALSE;
    1349                 :         }
    1350                 : 
    1351               0 :         if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) {
    1352               0 :                 RETURN_FALSE;
    1353                 :         }
    1354                 : 
    1355               0 :         RETURN_BOOL(Z_TYPE_PP(entry) == IS_ARRAY || Z_TYPE_PP(entry) == IS_OBJECT);
    1356                 : }
    1357                 : /* }}} */
    1358                 : 
    1359                 : /* {{{ proto object RecursiveArrayIterator::getChildren()
    1360                 :    Create a sub iterator for the current element (same class as $this) */
    1361                 : SPL_METHOD(Array, getChildren)
    1362               0 : {
    1363               0 :         zval *object = getThis(), **entry;
    1364               0 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1365               0 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
    1366                 : 
    1367               0 :         if (!aht) {
    1368               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
    1369               0 :                 return;
    1370                 :         }
    1371                 : 
    1372               0 :         if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(intern TSRMLS_CC) == FAILURE) {
    1373               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
    1374               0 :                 return;
    1375                 :         }
    1376                 : 
    1377               0 :         if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) {
    1378               0 :                 return;
    1379                 :         }
    1380                 : 
    1381               0 :         if (Z_TYPE_PP(entry) == IS_OBJECT && instanceof_function(Z_OBJCE_PP(entry), Z_OBJCE_P(getThis()) TSRMLS_CC)) {
    1382               0 :                 RETURN_ZVAL(*entry, 0, 0);
    1383                 :         }
    1384                 : 
    1385               0 :         spl_instantiate_arg_ex1(Z_OBJCE_P(getThis()), &return_value, 0, *entry TSRMLS_CC);
    1386                 : }
    1387                 : /* }}} */
    1388                 : 
    1389                 : static
    1390                 : ZEND_BEGIN_ARG_INFO(arginfo_array___construct, 0)
    1391                 :         ZEND_ARG_INFO(0, array)
    1392                 : ZEND_END_ARG_INFO()
    1393                 : 
    1394                 : static
    1395                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_array_offsetGet, 0, 0, 1)
    1396                 :         ZEND_ARG_INFO(0, index)
    1397                 : ZEND_END_ARG_INFO()
    1398                 : 
    1399                 : static
    1400                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_array_offsetSet, 0, 0, 2)
    1401                 :         ZEND_ARG_INFO(0, index)
    1402                 :         ZEND_ARG_INFO(0, newval)
    1403                 : ZEND_END_ARG_INFO()
    1404                 : 
    1405                 : static
    1406                 : ZEND_BEGIN_ARG_INFO(arginfo_array_append, 0)
    1407                 :         ZEND_ARG_INFO(0, value)
    1408                 : ZEND_END_ARG_INFO()
    1409                 : 
    1410                 : static
    1411                 : ZEND_BEGIN_ARG_INFO(arginfo_array_seek, 0)
    1412                 :         ZEND_ARG_INFO(0, position)
    1413                 : ZEND_END_ARG_INFO()
    1414                 : 
    1415                 : static
    1416                 : ZEND_BEGIN_ARG_INFO(arginfo_array_exchangeArray, 0)
    1417                 :         ZEND_ARG_INFO(0, array)
    1418                 : ZEND_END_ARG_INFO()
    1419                 : 
    1420                 : static
    1421                 : ZEND_BEGIN_ARG_INFO(arginfo_array_setFlags, 0)
    1422                 :         ZEND_ARG_INFO(0, flags)
    1423                 : ZEND_END_ARG_INFO()
    1424                 : 
    1425                 : static
    1426                 : ZEND_BEGIN_ARG_INFO(arginfo_array_setIteratorClass, 0)
    1427                 :         ZEND_ARG_INFO(0, iteratorClass)
    1428                 : ZEND_END_ARG_INFO()
    1429                 : 
    1430                 : static
    1431                 : ZEND_BEGIN_ARG_INFO(arginfo_array_uXsort, 0)
    1432                 :         ZEND_ARG_INFO(0, cmp_function )
    1433                 : ZEND_END_ARG_INFO();
    1434                 : 
    1435                 : static zend_function_entry spl_funcs_ArrayObject[] = {
    1436                 :         SPL_ME(Array, __construct,      arginfo_array___construct,      ZEND_ACC_PUBLIC)
    1437                 :         SPL_ME(Array, offsetExists,     arginfo_array_offsetGet,        ZEND_ACC_PUBLIC)
    1438                 :         SPL_ME(Array, offsetGet,        arginfo_array_offsetGet,        ZEND_ACC_PUBLIC)
    1439                 :         SPL_ME(Array, offsetSet,        arginfo_array_offsetSet,        ZEND_ACC_PUBLIC)
    1440                 :         SPL_ME(Array, offsetUnset,      arginfo_array_offsetGet,        ZEND_ACC_PUBLIC)
    1441                 :         SPL_ME(Array, append,           arginfo_array_append,           ZEND_ACC_PUBLIC)
    1442                 :         SPL_ME(Array, getArrayCopy,     NULL,                           ZEND_ACC_PUBLIC)
    1443                 :         SPL_ME(Array, count,            NULL,                           ZEND_ACC_PUBLIC)
    1444                 :         SPL_ME(Array, getFlags,         NULL,                           ZEND_ACC_PUBLIC)
    1445                 :         SPL_ME(Array, setFlags,         arginfo_array_setFlags,         ZEND_ACC_PUBLIC)
    1446                 :         SPL_ME(Array, asort,            NULL,                           ZEND_ACC_PUBLIC)
    1447                 :         SPL_ME(Array, ksort,            NULL,                           ZEND_ACC_PUBLIC)
    1448                 :         SPL_ME(Array, uasort,           arginfo_array_uXsort,           ZEND_ACC_PUBLIC)
    1449                 :         SPL_ME(Array, uksort,           arginfo_array_uXsort,           ZEND_ACC_PUBLIC)
    1450                 :         SPL_ME(Array, natsort,          NULL,                           ZEND_ACC_PUBLIC)
    1451                 :         SPL_ME(Array, natcasesort,      NULL,                           ZEND_ACC_PUBLIC)
    1452                 :         /* ArrayObject specific */
    1453                 :         SPL_ME(Array, getIterator,      NULL,                           ZEND_ACC_PUBLIC)
    1454                 :         SPL_ME(Array, exchangeArray,    arginfo_array_exchangeArray,    ZEND_ACC_PUBLIC)
    1455                 :         SPL_ME(Array, setIteratorClass, arginfo_array_setIteratorClass, ZEND_ACC_PUBLIC)
    1456                 :         SPL_ME(Array, getIteratorClass, NULL,                           ZEND_ACC_PUBLIC)
    1457                 :         {NULL, NULL, NULL}
    1458                 : };
    1459                 : 
    1460                 : static zend_function_entry spl_funcs_ArrayIterator[] = {
    1461                 :         SPL_ME(Array, __construct,      arginfo_array___construct,      ZEND_ACC_PUBLIC)
    1462                 :         SPL_ME(Array, offsetExists,     arginfo_array_offsetGet,        ZEND_ACC_PUBLIC)
    1463                 :         SPL_ME(Array, offsetGet,        arginfo_array_offsetGet,        ZEND_ACC_PUBLIC)
    1464                 :         SPL_ME(Array, offsetSet,        arginfo_array_offsetSet,        ZEND_ACC_PUBLIC)
    1465                 :         SPL_ME(Array, offsetUnset,      arginfo_array_offsetGet,        ZEND_ACC_PUBLIC)
    1466                 :         SPL_ME(Array, append,           arginfo_array_append,           ZEND_ACC_PUBLIC)
    1467                 :         SPL_ME(Array, getArrayCopy,     NULL,                           ZEND_ACC_PUBLIC)
    1468                 :         SPL_ME(Array, count,            NULL,                           ZEND_ACC_PUBLIC)
    1469                 :         SPL_ME(Array, getFlags,         NULL,                           ZEND_ACC_PUBLIC)
    1470                 :         SPL_ME(Array, setFlags,         arginfo_array_setFlags,         ZEND_ACC_PUBLIC)
    1471                 :         SPL_ME(Array, asort,            NULL,                           ZEND_ACC_PUBLIC)
    1472                 :         SPL_ME(Array, ksort,            NULL,                           ZEND_ACC_PUBLIC)
    1473                 :         SPL_ME(Array, uasort,           arginfo_array_uXsort,           ZEND_ACC_PUBLIC)
    1474                 :         SPL_ME(Array, uksort,           arginfo_array_uXsort,           ZEND_ACC_PUBLIC)
    1475                 :         SPL_ME(Array, natsort,          NULL,                           ZEND_ACC_PUBLIC)
    1476                 :         SPL_ME(Array, natcasesort,      NULL,                           ZEND_ACC_PUBLIC)
    1477                 :         /* ArrayIterator specific */
    1478                 :         SPL_ME(Array, rewind,           NULL,                           ZEND_ACC_PUBLIC)
    1479                 :         SPL_ME(Array, current,          NULL,                           ZEND_ACC_PUBLIC)
    1480                 :         SPL_ME(Array, key,              NULL,                           ZEND_ACC_PUBLIC)
    1481                 :         SPL_ME(Array, next,             NULL,                           ZEND_ACC_PUBLIC)
    1482                 :         SPL_ME(Array, valid,            NULL,                           ZEND_ACC_PUBLIC)
    1483                 :         SPL_ME(Array, seek,             arginfo_array_seek,             ZEND_ACC_PUBLIC)
    1484                 :         {NULL, NULL, NULL}
    1485                 : };
    1486                 : 
    1487                 : static zend_function_entry spl_funcs_RecursiveArrayIterator[] = {
    1488                 :         SPL_ME(Array, hasChildren,   NULL, ZEND_ACC_PUBLIC)
    1489                 :         SPL_ME(Array, getChildren,   NULL, ZEND_ACC_PUBLIC)
    1490                 :         {NULL, NULL, NULL}
    1491                 : };
    1492                 : 
    1493                 : /* {{{ PHP_MINIT_FUNCTION(spl_array) */
    1494                 : PHP_MINIT_FUNCTION(spl_array)
    1495             220 : {
    1496             220 :         REGISTER_SPL_STD_CLASS_EX(ArrayObject, spl_array_object_new, spl_funcs_ArrayObject);
    1497             220 :         REGISTER_SPL_IMPLEMENTS(ArrayObject, Aggregate);
    1498             220 :         REGISTER_SPL_IMPLEMENTS(ArrayObject, ArrayAccess);
    1499             220 :         memcpy(&spl_handler_ArrayObject, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
    1500                 : 
    1501             220 :         spl_handler_ArrayObject.clone_obj = spl_array_object_clone;
    1502             220 :         spl_handler_ArrayObject.read_dimension = spl_array_read_dimension;
    1503             220 :         spl_handler_ArrayObject.write_dimension = spl_array_write_dimension;
    1504             220 :         spl_handler_ArrayObject.unset_dimension = spl_array_unset_dimension;
    1505             220 :         spl_handler_ArrayObject.has_dimension = spl_array_has_dimension;
    1506             220 :         spl_handler_ArrayObject.count_elements = spl_array_object_count_elements;
    1507                 : 
    1508             220 :         spl_handler_ArrayObject.get_properties = spl_array_get_properties;
    1509             220 :         spl_handler_ArrayObject.read_property = spl_array_read_property;
    1510             220 :         spl_handler_ArrayObject.write_property = spl_array_write_property;
    1511             220 :         spl_handler_ArrayObject.get_property_ptr_ptr = spl_array_get_property_ptr_ptr;
    1512             220 :         spl_handler_ArrayObject.has_property = spl_array_has_property;
    1513             220 :         spl_handler_ArrayObject.unset_property = spl_array_unset_property;
    1514                 : 
    1515             220 :         REGISTER_SPL_STD_CLASS_EX(ArrayIterator, spl_array_object_new, spl_funcs_ArrayIterator);
    1516             220 :         REGISTER_SPL_IMPLEMENTS(ArrayIterator, Iterator);
    1517             220 :         REGISTER_SPL_IMPLEMENTS(ArrayIterator, ArrayAccess);
    1518             220 :         REGISTER_SPL_IMPLEMENTS(ArrayIterator, SeekableIterator);
    1519             220 :         memcpy(&spl_handler_ArrayIterator, &spl_handler_ArrayObject, sizeof(zend_object_handlers));
    1520             220 :         spl_ce_ArrayIterator->get_iterator = spl_array_get_iterator;
    1521                 :         
    1522             220 :         REGISTER_SPL_SUB_CLASS_EX(RecursiveArrayIterator, ArrayIterator, spl_array_object_new, spl_funcs_RecursiveArrayIterator);
    1523             220 :         REGISTER_SPL_IMPLEMENTS(RecursiveArrayIterator, RecursiveIterator);
    1524             220 :         spl_ce_RecursiveArrayIterator->get_iterator = spl_array_get_iterator;
    1525                 : 
    1526             220 :         REGISTER_SPL_IMPLEMENTS(ArrayObject, Countable);
    1527             220 :         REGISTER_SPL_IMPLEMENTS(ArrayIterator, Countable);
    1528                 : 
    1529             220 :         REGISTER_SPL_CLASS_CONST_LONG(ArrayObject,   "STD_PROP_LIST",    SPL_ARRAY_STD_PROP_LIST);
    1530             220 :         REGISTER_SPL_CLASS_CONST_LONG(ArrayObject,   "ARRAY_AS_PROPS",   SPL_ARRAY_ARRAY_AS_PROPS);
    1531                 : 
    1532             220 :         REGISTER_SPL_CLASS_CONST_LONG(ArrayIterator, "STD_PROP_LIST",    SPL_ARRAY_STD_PROP_LIST);
    1533             220 :         REGISTER_SPL_CLASS_CONST_LONG(ArrayIterator, "ARRAY_AS_PROPS",   SPL_ARRAY_ARRAY_AS_PROPS);
    1534             220 :         return SUCCESS;
    1535                 : }
    1536                 : /* }}} */
    1537                 : 
    1538                 : /*
    1539                 :  * Local variables:
    1540                 :  * tab-width: 4
    1541                 :  * c-basic-offset: 4
    1542                 :  * End:
    1543                 :  * vim600: fdm=marker
    1544                 :  * vim: noet sw=4 ts=4
    1545                 :  */

Generated by: LTP GCOV extension version 1.5