PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LTP GCOV extension - code coverage report
Current view: directory - spl - spl_array.c
Test: PHP Code Coverage
Date: 2009-11-23 Instrumented lines: 893
Code covered: 86.8 % Executed lines: 775
Legend: not executed executed

       1                 : /*
       2                 :    +----------------------------------------------------------------------+
       3                 :    | PHP Version 6                                                        |
       4                 :    +----------------------------------------------------------------------+
       5                 :    | Copyright (c) 1997-2009 The PHP Group                                |
       6                 :    +----------------------------------------------------------------------+
       7                 :    | This source file is subject to version 3.01 of the PHP license,      |
       8                 :    | that is bundled with this package in the file LICENSE, and is        |
       9                 :    | available through the world-wide-web at the following url:           |
      10                 :    | http://www.php.net/license/3_01.txt                                  |
      11                 :    | If you did not receive a copy of the PHP license and are unable to   |
      12                 :    | obtain it through the world-wide-web, please send a note to          |
      13                 :    | license@php.net so we can mail you a copy immediately.               |
      14                 :    +----------------------------------------------------------------------+
      15                 :    | Authors: Marcus Boerger <helly@php.net>                              |
      16                 :    +----------------------------------------------------------------------+
      17                 :  */
      18                 : 
      19                 : /* $Id: spl_array.c 288551 2009-09-22 07:54:06Z dmitry $ */
      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 "ext/standard/php_var.h"
      29                 : #include "ext/standard/php_smart_str.h"
      30                 : #include "zend_interfaces.h"
      31                 : #include "zend_API.h"
      32                 : #include "zend_exceptions.h"
      33                 : 
      34                 : #include "php_spl.h"
      35                 : #include "spl_functions.h"
      36                 : #include "spl_engine.h"
      37                 : #include "spl_iterators.h"
      38                 : #include "spl_array.h"
      39                 : #include "spl_exceptions.h"
      40                 : 
      41                 : zend_object_handlers spl_handler_ArrayObject;
      42                 : PHPAPI zend_class_entry  *spl_ce_ArrayObject;
      43                 : 
      44                 : zend_object_handlers spl_handler_ArrayIterator;
      45                 : PHPAPI zend_class_entry  *spl_ce_ArrayIterator;
      46                 : PHPAPI zend_class_entry  *spl_ce_RecursiveArrayIterator;
      47                 : 
      48                 : #define SPL_ARRAY_STD_PROP_LIST      0x00000001
      49                 : #define SPL_ARRAY_ARRAY_AS_PROPS     0x00000002
      50                 : #define SPL_ARRAY_CHILD_ARRAYS_ONLY  0x00000004
      51                 : #define SPL_ARRAY_OVERLOADED_REWIND  0x00010000
      52                 : #define SPL_ARRAY_OVERLOADED_VALID   0x00020000
      53                 : #define SPL_ARRAY_OVERLOADED_KEY     0x00040000
      54                 : #define SPL_ARRAY_OVERLOADED_CURRENT 0x00080000
      55                 : #define SPL_ARRAY_OVERLOADED_NEXT    0x00100000
      56                 : #define SPL_ARRAY_IS_REF             0x01000000
      57                 : #define SPL_ARRAY_IS_SELF            0x02000000
      58                 : #define SPL_ARRAY_USE_OTHER          0x04000000
      59                 : #define SPL_ARRAY_INT_MASK           0xFFFF0000
      60                 : #define SPL_ARRAY_CLONE_MASK         0x0300FFFF
      61                 : 
      62                 : typedef struct _spl_array_object {
      63                 :         zend_object            std;
      64                 :         zval                   *array;
      65                 :         zval                   *retval;
      66                 :         HashPosition           pos;
      67                 :         ulong                  pos_h;
      68                 :         int                    ar_flags;
      69                 :         int                    is_self;
      70                 :         zend_function          *fptr_offset_get;
      71                 :         zend_function          *fptr_offset_set;
      72                 :         zend_function          *fptr_offset_has;
      73                 :         zend_function          *fptr_offset_del;
      74                 :         zend_function          *fptr_count;
      75                 :         zend_function          *fptr_serialize;
      76                 :         zend_function          *fptr_unserialize;
      77                 :         zend_class_entry       *ce_get_iterator;
      78                 :         php_serialize_data_t   *serialize_data;
      79                 :         php_unserialize_data_t *unserialize_data;
      80                 :         HashTable              *debug_info;
      81                 : } spl_array_object;
      82                 : 
      83           10985 : static inline HashTable *spl_array_get_hash_table(spl_array_object* intern, int check_std_props TSRMLS_DC) { /* {{{ */
      84           10985 :         if ((intern->ar_flags & SPL_ARRAY_IS_SELF) != 0) {
      85             102 :                 return intern->std.properties;
      86           10883 :         } else if ((intern->ar_flags & SPL_ARRAY_USE_OTHER) && (check_std_props == 0 || (intern->ar_flags & SPL_ARRAY_STD_PROP_LIST) == 0) && Z_TYPE_P(intern->array) == IS_OBJECT) {
      87            1150 :                 spl_array_object *other  = (spl_array_object*)zend_object_store_get_object(intern->array TSRMLS_CC);
      88            1150 :                 return spl_array_get_hash_table(other, check_std_props TSRMLS_CC);
      89            9733 :         } else if ((intern->ar_flags & ((check_std_props ? SPL_ARRAY_STD_PROP_LIST : 0) | SPL_ARRAY_IS_SELF)) != 0) {
      90               7 :                 return intern->std.properties;
      91                 :         } else {
      92            9726 :                 return HASH_OF(intern->array);
      93                 :         }
      94                 : } /* }}} */
      95                 : 
      96                 : static void spl_array_rewind(spl_array_object *intern TSRMLS_DC);
      97                 : 
      98                 : static void spl_array_update_pos(spl_array_object* intern) /* {{{ */
      99            3023 : {
     100            3023 :         Bucket *pos = intern->pos;
     101            3023 :         if (pos != NULL) {
     102            1977 :                 intern->pos_h = pos->h;
     103                 :         }
     104            3023 : } /* }}} */
     105                 : 
     106                 : static void spl_array_set_pos(spl_array_object* intern, HashPosition pos) /* {{{ */
     107              17 : {
     108              17 :         intern->pos = pos;
     109              17 :         spl_array_update_pos(intern);
     110              17 : } /* }}} */
     111                 : 
     112                 : SPL_API int spl_hash_verify_pos_ex(spl_array_object * intern, HashTable * ht TSRMLS_DC) /* {{{ */
     113             602 : {
     114                 :         Bucket *p;
     115                 : 
     116                 : /*      IS_CONSISTENT(ht);*/
     117                 : 
     118                 : /*      HASH_PROTECT_RECURSION(ht);*/
     119             602 :         p = ht->arBuckets[intern->pos_h & ht->nTableMask];
     120            1209 :         while (p != NULL) {
     121             574 :                 if (p == intern->pos) {
     122             569 :                         return SUCCESS;
     123                 :                 }
     124               5 :                 p = p->pNext;
     125                 :         }
     126                 : /*      HASH_UNPROTECT_RECURSION(ht); */
     127              33 :         spl_array_rewind(intern TSRMLS_CC);
     128              33 :         return FAILURE;
     129                 : 
     130                 : } /* }}} */
     131                 : 
     132                 : SPL_API int spl_hash_verify_pos(spl_array_object * intern TSRMLS_DC) /* {{{ */
     133              47 : {
     134              47 :         HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
     135              47 :         return spl_hash_verify_pos_ex(intern, ht TSRMLS_CC);
     136                 : }
     137                 : /* }}} */
     138                 : 
     139                 : /* {{{ spl_array_object_free_storage */
     140                 : static void spl_array_object_free_storage(void *object TSRMLS_DC)
     141             629 : {
     142             629 :         spl_array_object *intern = (spl_array_object *)object;
     143                 : 
     144             629 :         zend_object_std_dtor(&intern->std TSRMLS_CC);
     145                 : 
     146             629 :         zval_ptr_dtor(&intern->array);
     147             629 :         zval_ptr_dtor(&intern->retval);
     148                 : 
     149             629 :         if (intern->debug_info != NULL) {
     150             105 :                 zend_hash_destroy(intern->debug_info);
     151             105 :                 efree(intern->debug_info);
     152                 :         }
     153                 : 
     154             629 :         efree(object);
     155             629 : }
     156                 : /* }}} */
     157                 : 
     158                 : zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC);
     159                 : int spl_array_serialize(zval *object, int *type, zstr *buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC);
     160                 : int spl_array_unserialize(zval **object, zend_class_entry *ce, int type, const zstr buf, zend_uint buf_len, zend_unserialize_data *data TSRMLS_DC);
     161                 : 
     162                 : /* {{{ spl_array_object_new_ex */
     163                 : 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)
     164             629 : {
     165                 :         zend_object_value retval;
     166                 :         spl_array_object *intern;
     167                 :         zval *tmp;
     168             629 :         zend_class_entry * parent = class_type;
     169             629 :         int inherited = 0;
     170                 : 
     171             629 :         intern = emalloc(sizeof(spl_array_object));
     172             629 :         memset(intern, 0, sizeof(spl_array_object));
     173             629 :         *obj = intern;
     174             629 :         ALLOC_INIT_ZVAL(intern->retval);
     175                 : 
     176             629 :         zend_object_std_init(&intern->std, class_type TSRMLS_CC);
     177             629 :         zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
     178                 : 
     179             629 :         intern->ar_flags = 0;
     180             629 :         intern->serialize_data   = NULL;
     181             629 :         intern->unserialize_data = NULL;
     182             629 :         intern->debug_info       = NULL;
     183             629 :         intern->ce_get_iterator = spl_ce_ArrayIterator;
     184             629 :         if (orig) {
     185              74 :                 spl_array_object *other = (spl_array_object*)zend_object_store_get_object(orig TSRMLS_CC);
     186                 : 
     187              74 :                 intern->ar_flags &= ~ SPL_ARRAY_CLONE_MASK;
     188              74 :                 intern->ar_flags |= (other->ar_flags & SPL_ARRAY_CLONE_MASK);
     189              74 :                 intern->ce_get_iterator = other->ce_get_iterator;
     190              74 :                 if (clone_orig) {
     191               8 :                         intern->array = other->array;
     192               8 :                         if (Z_OBJ_HT_P(orig) == &spl_handler_ArrayObject) {
     193               6 :                                 MAKE_STD_ZVAL(intern->array);
     194               6 :                                 array_init(intern->array);
     195               6 :                                 zend_hash_copy(HASH_OF(intern->array), HASH_OF(other->array), (copy_ctor_func_t) zval_add_ref, &tmp, sizeof(zval*));
     196                 :                         }
     197               8 :                         if (Z_OBJ_HT_P(orig) == &spl_handler_ArrayIterator) {
     198               2 :                                 Z_ADDREF_P(other->array);
     199                 :                         }
     200                 :                 } else {
     201              66 :                         intern->array = orig;
     202              66 :                         Z_ADDREF_P(intern->array);
     203              66 :                         intern->ar_flags |= SPL_ARRAY_IS_REF | SPL_ARRAY_USE_OTHER;
     204                 :                 }
     205                 :         } else {
     206             555 :                 MAKE_STD_ZVAL(intern->array);
     207             555 :                 array_init(intern->array);
     208             555 :                 intern->ar_flags &= ~SPL_ARRAY_IS_REF;
     209                 :         }
     210                 : 
     211             629 :         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);
     212            1395 :         while (parent) {
     213             766 :                 if (parent == spl_ce_ArrayIterator || parent == spl_ce_RecursiveArrayIterator) {
     214             476 :                         retval.handlers = &spl_handler_ArrayIterator;
     215             476 :                         class_type->get_iterator = spl_array_get_iterator;
     216             476 :                         break;
     217             290 :                 } else if (parent == spl_ce_ArrayObject) {
     218             153 :                         retval.handlers = &spl_handler_ArrayObject;
     219             153 :                         break;
     220                 :                 }
     221             137 :                 parent = parent->parent;
     222             137 :                 inherited = 1;
     223                 :         }
     224             629 :         if (!parent) { /* this must never happen */
     225               0 :                 php_error_docref(NULL TSRMLS_CC, E_COMPILE_ERROR, "Internal compiler error, Class is not child of ArrayObject or ArrayIterator");
     226                 :         }
     227             629 :         if (inherited) {
     228             137 :                 zend_hash_find(&class_type->function_table, "offsetget",    sizeof("offsetget"),    (void **) &intern->fptr_offset_get);
     229             137 :                 if (intern->fptr_offset_get->common.scope == parent) {
     230             106 :                         intern->fptr_offset_get = NULL;
     231                 :                 }
     232             137 :                 zend_hash_find(&class_type->function_table, "offsetset",    sizeof("offsetset"),    (void **) &intern->fptr_offset_set);
     233             137 :                 if (intern->fptr_offset_set->common.scope == parent) {
     234             106 :                         intern->fptr_offset_set = NULL;
     235                 :                 }
     236             137 :                 zend_hash_find(&class_type->function_table, "offsetexists", sizeof("offsetexists"), (void **) &intern->fptr_offset_has);
     237             137 :                 if (intern->fptr_offset_has->common.scope == parent) {
     238             109 :                         intern->fptr_offset_has = NULL;
     239                 :                 }
     240             137 :                 zend_hash_find(&class_type->function_table, "offsetunset",  sizeof("offsetunset"),  (void **) &intern->fptr_offset_del);
     241             137 :                 if (intern->fptr_offset_del->common.scope == parent) {
     242             109 :                         intern->fptr_offset_del = NULL;
     243                 :                 }
     244             137 :                 zend_hash_find(&class_type->function_table, "count",        sizeof("count"),        (void **) &intern->fptr_count);
     245             137 :                 if (intern->fptr_count->common.scope == parent) {
     246             106 :                         intern->fptr_count = NULL;
     247                 :                 }
     248             137 :                 zend_hash_find(&class_type->function_table, "serialize",    sizeof("serialize"),     (void **) &intern->fptr_serialize);
     249             137 :                 if (intern->fptr_serialize->common.scope == parent) {
     250             105 :                         intern->fptr_serialize = NULL;
     251                 :                 }
     252             137 :                 zend_hash_find(&class_type->function_table, "unserialize",  sizeof("unserialize"),   (void **) &intern->fptr_unserialize);
     253             137 :                 if (intern->fptr_unserialize->common.scope == parent) {
     254             105 :                         intern->fptr_unserialize = NULL;
     255                 :                 }
     256                 :         }
     257                 :         /* Cache iterator functions if ArrayIterator or derived. Check current's */
     258                 :         /* cache since only current is always required */
     259             629 :         if (retval.handlers == &spl_handler_ArrayIterator) {
     260             476 :                 if (!class_type->iterator_funcs.zf_current) {
     261             152 :                         zend_hash_find(&class_type->function_table, "rewind",  sizeof("rewind"),  (void **) &class_type->iterator_funcs.zf_rewind);
     262             152 :                         zend_hash_find(&class_type->function_table, "valid",   sizeof("valid"),   (void **) &class_type->iterator_funcs.zf_valid);
     263             152 :                         zend_hash_find(&class_type->function_table, "key",     sizeof("key"),     (void **) &class_type->iterator_funcs.zf_key);
     264             152 :                         zend_hash_find(&class_type->function_table, "current", sizeof("current"), (void **) &class_type->iterator_funcs.zf_current);
     265             152 :                         zend_hash_find(&class_type->function_table, "next",    sizeof("next"),    (void **) &class_type->iterator_funcs.zf_next);
     266                 :                 }
     267             476 :                 if (inherited) {
     268              97 :                         if (class_type->iterator_funcs.zf_rewind->common.scope  != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_REWIND;
     269              97 :                         if (class_type->iterator_funcs.zf_valid->common.scope   != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_VALID;
     270              97 :                         if (class_type->iterator_funcs.zf_key->common.scope     != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_KEY;
     271              97 :                         if (class_type->iterator_funcs.zf_current->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_CURRENT;
     272              97 :                         if (class_type->iterator_funcs.zf_next->common.scope    != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_NEXT;
     273                 :                 }
     274                 :         }
     275                 : 
     276             629 :         spl_array_rewind(intern TSRMLS_CC);
     277             629 :         return retval;
     278                 : }
     279                 : /* }}} */
     280                 : 
     281                 : /* {{{ spl_array_object_new */
     282                 : static zend_object_value spl_array_object_new(zend_class_entry *class_type TSRMLS_DC)
     283             555 : {
     284                 :         spl_array_object *tmp;
     285             555 :         return spl_array_object_new_ex(class_type, &tmp, NULL, 0 TSRMLS_CC);
     286                 : }
     287                 : /* }}} */
     288                 : 
     289                 : /* {{{ spl_array_object_clone */
     290                 : static zend_object_value spl_array_object_clone(zval *zobject TSRMLS_DC)
     291               8 : {
     292                 :         zend_object_value new_obj_val;
     293                 :         zend_object *old_object;
     294                 :         zend_object *new_object;
     295               8 :         zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
     296                 :         spl_array_object *intern;
     297                 : 
     298               8 :         old_object = zend_objects_get_address(zobject TSRMLS_CC);
     299               8 :         new_obj_val = spl_array_object_new_ex(old_object->ce, &intern, zobject, 1 TSRMLS_CC);
     300               8 :         new_object = &intern->std;
     301                 : 
     302               8 :         zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC);
     303                 : 
     304               8 :         return new_obj_val;
     305                 : }
     306                 : /* }}} */
     307                 : 
     308                 : static zval **spl_array_get_dimension_ptr_ptr(int check_inherited, zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
     309             124 : {
     310             124 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     311                 :         zval **retval;
     312                 :         long index;
     313             124 :         HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
     314                 : 
     315                 : /*  We cannot get the pointer pointer so we don't allow it here for now
     316                 :         if (check_inherited && intern->fptr_offset_get) {
     317                 :                 return zend_call_method_with_1_params(&object, intern->std.ce, &intern->fptr_offset_get, "offsetGet", NULL, offset);
     318                 :         }*/
     319                 : 
     320             124 :         if (!offset) {
     321               1 :                 return &EG(uninitialized_zval_ptr);
     322                 :         }
     323                 :         
     324             123 :         switch(Z_TYPE_P(offset)) {
     325                 :         case IS_STRING:
     326                 :         case IS_UNICODE:
     327              70 :                 if (zend_u_symtable_find(ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, (void **) &retval) == FAILURE) {
     328              23 :                         if (type == BP_VAR_W || type == BP_VAR_RW) {
     329                 :                                 zval *value;
     330               1 :                                 ALLOC_INIT_ZVAL(value);
     331               1 :                                 zend_u_symtable_update(ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, (void**)&value, sizeof(void*), NULL);
     332               1 :                                 zend_u_symtable_find(ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, (void **) &retval);
     333               1 :                                 return retval;
     334                 :                         } else {
     335              22 :                                 zend_error(E_NOTICE, "Undefined index:  %R", Z_TYPE_P(offset), Z_STRVAL_P(offset));
     336              22 :                                 return &EG(uninitialized_zval_ptr);
     337                 :                         }
     338                 :                 } else {
     339              47 :                         return retval;
     340                 :                 }
     341                 :         case IS_DOUBLE:
     342                 :         case IS_RESOURCE:
     343                 :         case IS_BOOL: 
     344                 :         case IS_LONG: 
     345              53 :                 if (offset->type == IS_DOUBLE) {
     346               0 :                         index = (long)Z_DVAL_P(offset);
     347                 :                 } else {
     348              53 :                         index = Z_LVAL_P(offset);
     349                 :                 }
     350              53 :                 if (zend_hash_index_find(ht, index, (void **) &retval) == FAILURE) {
     351               2 :                         if (type == BP_VAR_W || type == BP_VAR_RW) {
     352                 :                                 zval *value;
     353               0 :                                 ALLOC_INIT_ZVAL(value);
     354               0 :                                 zend_hash_index_update(ht, index, (void**)&value, sizeof(void*), NULL);
     355               0 :                                 zend_hash_index_find(ht, index, (void **) &retval);
     356               0 :                                 return retval;
     357                 :                         } else {
     358               2 :                                 zend_error(E_NOTICE, "Undefined offset:  %ld", index);
     359               2 :                                 return &EG(uninitialized_zval_ptr);
     360                 :                         }
     361                 :                 } else {
     362              51 :                         return retval;
     363                 :                 }
     364                 :                 break;
     365                 :         default:
     366               0 :                 zend_error(E_WARNING, "Illegal offset type");
     367               0 :                 return &EG(uninitialized_zval_ptr);
     368                 :         }
     369                 : } /* }}} */
     370                 : 
     371                 : static zval *spl_array_read_dimension_ex(int check_inherited, zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
     372             130 : {
     373                 :         zval **ret;
     374                 : 
     375             130 :         if (check_inherited) {
     376             124 :                 spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     377             124 :                 if (intern->fptr_offset_get) {
     378                 :                         zval *rv;
     379               6 :                         SEPARATE_ARG_IF_REF(offset);
     380               6 :                         zend_call_method_with_1_params(&object, intern->std.ce, &intern->fptr_offset_get, "offsetGet", &rv, offset);        
     381               6 :                         zval_ptr_dtor(&offset);
     382               6 :                         if (rv) {
     383               5 :                                 zval_ptr_dtor(&intern->retval);
     384               5 :                                 MAKE_STD_ZVAL(intern->retval);
     385               5 :                                 ZVAL_ZVAL(intern->retval, rv, 1, 1);
     386               5 :                                 return intern->retval;
     387                 :                         }
     388               1 :                         return EG(uninitialized_zval_ptr);
     389                 :                 }
     390                 :         }
     391             124 :         ret = spl_array_get_dimension_ptr_ptr(check_inherited, object, offset, type TSRMLS_CC);
     392                 : 
     393                 :         /* When in a write context,
     394                 :          * ZE has to be fooled into thinking this is in a reference set
     395                 :          * by separating (if necessary) and returning as an is_ref=1 zval (even if refcount == 1) */
     396             124 :         if ((type == BP_VAR_W || type == BP_VAR_RW) && !Z_ISREF_PP(ret)) {
     397               3 :                 if (Z_REFCOUNT_PP(ret) > 1) {
     398                 :                         zval *newval;
     399                 : 
     400                 :                         /* Separate */
     401               1 :                         MAKE_STD_ZVAL(newval);
     402               1 :                         *newval = **ret;
     403               1 :                         zval_copy_ctor(newval);
     404               1 :                         Z_SET_REFCOUNT_P(newval, 1);
     405                 : 
     406                 :                         /* Replace */
     407               1 :                         Z_DELREF_PP(ret);
     408               1 :                         *ret = newval;
     409                 :                 }
     410                 : 
     411               3 :                 Z_SET_ISREF_PP(ret);
     412                 :         }
     413                 : 
     414             124 :         return *ret;
     415                 : } /* }}} */
     416                 : 
     417                 : static zval *spl_array_read_dimension(zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
     418             124 : {
     419             124 :         return spl_array_read_dimension_ex(1, object, offset, type TSRMLS_CC);
     420                 : } /* }}} */
     421                 : 
     422                 : static void spl_array_write_dimension_ex(int check_inherited, zval *object, zval *offset, zval *value TSRMLS_DC) /* {{{ */
     423             142 : {
     424             142 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     425                 :         long index;
     426                 : 
     427             142 :         if (check_inherited && intern->fptr_offset_set) {
     428               6 :                 if (!offset) {
     429               4 :                         ALLOC_INIT_ZVAL(offset);
     430                 :                 } else {
     431               2 :                         SEPARATE_ARG_IF_REF(offset);
     432                 :                 }
     433               6 :                 zend_call_method_with_2_params(&object, intern->std.ce, &intern->fptr_offset_set, "offsetSet", NULL, offset, value);
     434               6 :                 zval_ptr_dtor(&offset);
     435               6 :                 return;
     436                 :         }
     437                 :         
     438             136 :         if (!offset) {
     439              54 :                 Z_ADDREF_P(value);
     440              54 :                 zend_hash_next_index_insert(spl_array_get_hash_table(intern, 0 TSRMLS_CC), (void**)&value, sizeof(void*), NULL);
     441              54 :                 return;
     442                 :         }
     443              82 :         switch(Z_TYPE_P(offset)) {
     444                 :         case IS_STRING:
     445                 :         case IS_UNICODE:
     446              57 :                 Z_ADDREF_P(value);
     447              57 :                 zend_u_symtable_update(spl_array_get_hash_table(intern, 0 TSRMLS_CC), Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, (void**)&value, sizeof(void*), NULL);
     448              57 :                 return;
     449                 :         case IS_DOUBLE:
     450                 :         case IS_RESOURCE:
     451                 :         case IS_BOOL: 
     452                 :         case IS_LONG: 
     453              21 :                 if (offset->type == IS_DOUBLE) {
     454               0 :                         index = (long)Z_DVAL_P(offset);
     455                 :                 } else {
     456              21 :                         index = Z_LVAL_P(offset);
     457                 :                 }
     458              21 :                 Z_ADDREF_P(value);
     459              21 :                 zend_hash_index_update(spl_array_get_hash_table(intern, 0 TSRMLS_CC), index, (void**)&value, sizeof(void*), NULL);
     460              21 :                 return;
     461                 :         case IS_NULL:
     462               4 :                 Z_ADDREF_P(value);
     463               4 :                 zend_hash_next_index_insert(spl_array_get_hash_table(intern, 0 TSRMLS_CC), (void**)&value, sizeof(void*), NULL);
     464               4 :                 return;
     465                 :         default:
     466               0 :                 zend_error(E_WARNING, "Illegal offset type");
     467               0 :                 return;
     468                 :         }
     469                 : } /* }}} */
     470                 : 
     471                 : static void spl_array_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC) /* {{{ */
     472             125 : {
     473             125 :         spl_array_write_dimension_ex(1, object, offset, value TSRMLS_CC);
     474             125 : } /* }}} */
     475                 : 
     476                 : static void spl_array_unset_dimension_ex(int check_inherited, zval *object, zval *offset TSRMLS_DC) /* {{{ */
     477              47 : {
     478              47 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     479                 :         long index;
     480                 : 
     481              47 :         if (check_inherited && intern->fptr_offset_del) {
     482               0 :                 SEPARATE_ARG_IF_REF(offset);
     483               0 :                 zend_call_method_with_1_params(&object, intern->std.ce, &intern->fptr_offset_del, "offsetUnset", NULL, offset);
     484               0 :                 zval_ptr_dtor(&offset);
     485               0 :                 return;
     486                 :         }
     487                 : 
     488              47 :         switch(Z_TYPE_P(offset)) {
     489                 :         case IS_STRING:
     490                 :         case IS_UNICODE:
     491              33 :                 if (spl_array_get_hash_table(intern, 0 TSRMLS_CC) == &EG(symbol_table)) {
     492               1 :                         if (zend_u_delete_global_variable(Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset) TSRMLS_CC)) {
     493               0 :                                 zend_error(E_NOTICE,"Undefined index:  %s", Z_STRVAL_P(offset));
     494                 :                         }
     495                 :                 } else {
     496              32 :                         if (zend_u_symtable_del(spl_array_get_hash_table(intern, 0 TSRMLS_CC), Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1) == FAILURE) {
     497               9 :                                 zend_error(E_NOTICE,"Undefined index:  %R", Z_TYPE_P(offset), Z_UNIVAL_P(offset));
     498                 :                         }
     499                 :                 }
     500              33 :                 break;
     501                 :         case IS_DOUBLE:
     502                 :         case IS_RESOURCE:
     503                 :         case IS_BOOL: 
     504                 :         case IS_LONG: 
     505              14 :                 if (offset->type == IS_DOUBLE) {
     506               0 :                         index = (long)Z_DVAL_P(offset);
     507                 :                 } else {
     508              14 :                         index = Z_LVAL_P(offset);
     509                 :                 }
     510              14 :                 if (zend_hash_index_del(spl_array_get_hash_table(intern, 0 TSRMLS_CC), index) == FAILURE) {
     511               2 :                         zend_error(E_NOTICE,"Undefined offset:  %ld", Z_LVAL_P(offset));
     512                 :                 }
     513              14 :                 break;
     514                 :         default:
     515               0 :                 zend_error(E_WARNING, "Illegal offset type");
     516               0 :                 return;
     517                 :         }
     518              47 :         spl_hash_verify_pos(intern TSRMLS_CC); /* call rewind on FAILURE */
     519                 : } /* }}} */
     520                 : 
     521                 : static void spl_array_unset_dimension(zval *object, zval *offset TSRMLS_DC) /* {{{ */
     522              39 : {
     523              39 :         spl_array_unset_dimension_ex(1, object, offset TSRMLS_CC);
     524              39 : } /* }}} */
     525                 : 
     526                 : static int spl_array_has_dimension_ex(int check_inherited, zval *object, zval *offset, int check_empty TSRMLS_DC) /* {{{ */
     527              56 : {
     528              56 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     529                 :         long index;
     530                 :         zval *rv, **tmp;
     531                 : 
     532              56 :         if (check_inherited && intern->fptr_offset_has) {
     533               0 :                 SEPARATE_ARG_IF_REF(offset);
     534               0 :                 zend_call_method_with_1_params(&object, intern->std.ce, &intern->fptr_offset_has, "offsetExists", &rv, offset);
     535               0 :                 zval_ptr_dtor(&offset);
     536               0 :                 if (rv && zend_is_true(rv)) {
     537               0 :                         zval_ptr_dtor(&rv);
     538               0 :                         return 1;
     539                 :                 }
     540               0 :                 if (rv) {
     541               0 :                         zval_ptr_dtor(&rv);
     542                 :                 }
     543               0 :                 return 0;
     544                 :         }
     545                 :         
     546              56 :         switch(Z_TYPE_P(offset)) {
     547                 :         case IS_STRING:
     548                 :         case IS_UNICODE:
     549              47 :                 if (check_empty) {
     550               5 :                         if (zend_u_symtable_find(spl_array_get_hash_table(intern, 0 TSRMLS_CC), Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, (void **) &tmp) != FAILURE && zend_is_true(*tmp)) {
     551               1 :                                 return 1;
     552                 :                         }
     553               4 :                         return 0;
     554                 :                 } else {
     555              42 :                         return zend_u_symtable_exists(spl_array_get_hash_table(intern, 0 TSRMLS_CC), Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1);
     556                 :                 }
     557                 :         case IS_DOUBLE:
     558                 :         case IS_RESOURCE:
     559                 :         case IS_BOOL: 
     560                 :         case IS_LONG: 
     561               9 :                 if (offset->type == IS_DOUBLE) {
     562               0 :                         index = (long)Z_DVAL_P(offset);
     563                 :                 } else {
     564               9 :                         index = Z_LVAL_P(offset);
     565                 :                 }
     566               9 :                 if (check_empty) {
     567               4 :                         HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
     568               4 :                         if (zend_hash_index_find(ht, index, (void **)&tmp) != FAILURE && zend_is_true(*tmp)) {
     569               3 :                                 return 1;
     570                 :                         }
     571               1 :                         return 0;
     572                 :                 } else {
     573               5 :                         return zend_hash_index_exists(spl_array_get_hash_table(intern, 0 TSRMLS_CC), index);
     574                 :                 }
     575                 :         default:
     576               0 :                 zend_error(E_WARNING, "Illegal offset type");
     577                 :         }
     578               0 :         return 0;
     579                 : } /* }}} */
     580                 : 
     581                 : static int spl_array_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC) /* {{{ */
     582              51 : {
     583              51 :         return spl_array_has_dimension_ex(1, object, offset, check_empty TSRMLS_CC);
     584                 : } /* }}} */
     585                 : 
     586                 : /* {{{ proto bool ArrayObject::offsetExists(mixed $index) U
     587                 :        proto bool ArrayIterator::offsetExists(mixed $index) U
     588                 :    Returns whether the requested $index exists. */
     589                 : SPL_METHOD(Array, offsetExists)
     590               5 : {
     591                 :         zval *index;
     592               5 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) {
     593               0 :                 return;
     594                 :         }
     595               5 :         RETURN_BOOL(spl_array_has_dimension_ex(0, getThis(), index, 0 TSRMLS_CC));
     596                 : } /* }}} */
     597                 : 
     598                 : /* {{{ proto mixed ArrayObject::offsetGet(mixed $index) U
     599                 :        proto mixed ArrayIterator::offsetGet(mixed $index) U
     600                 :    Returns the value at the specified $index. */
     601                 : SPL_METHOD(Array, offsetGet)
     602               6 : {
     603                 :         zval *index, *value;
     604               6 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) {
     605               0 :                 return;
     606                 :         }
     607               6 :         value = spl_array_read_dimension_ex(0, getThis(), index, BP_VAR_R TSRMLS_CC);
     608               6 :         RETURN_ZVAL(value, 1, 0);
     609                 : } /* }}} */
     610                 : 
     611                 : /* {{{ proto void ArrayObject::offsetSet(mixed $index, mixed $newval) U
     612                 :        proto void ArrayIterator::offsetSet(mixed $index, mixed $newval) U
     613                 :    Sets the value at the specified $index to $newval. */
     614                 : SPL_METHOD(Array, offsetSet)
     615              17 : {
     616                 :         zval *index, *value;
     617              17 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &index, &value) == FAILURE) {
     618               0 :                 return;
     619                 :         }
     620              17 :         spl_array_write_dimension_ex(0, getThis(), index, value TSRMLS_CC);
     621                 : } /* }}} */
     622                 : 
     623                 : void spl_array_iterator_append(zval *object, zval *append_value TSRMLS_DC) /* {{{ */
     624              27 : {
     625              27 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     626              27 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
     627                 : 
     628              27 :         if (!aht) {
     629               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
     630               0 :                 return;
     631                 :         }
     632                 :         
     633              27 :         if (Z_TYPE_P(intern->array) == IS_OBJECT) {
     634               1 :                 php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Cannot append properties to objects, use %v::offsetSet() instead", intern->std.ce->name);
     635               0 :                 return;
     636                 :         }
     637                 : 
     638              26 :         spl_array_write_dimension(object, NULL, append_value TSRMLS_CC);
     639              26 :         if (!intern->pos) {
     640              12 :                 spl_array_set_pos(intern, aht->pListTail);
     641                 :         }
     642                 : } /* }}} */
     643                 : 
     644                 : /* {{{ proto void ArrayObject::append(mixed $newval) U
     645                 :        proto void ArrayIterator::append(mixed $newval) U
     646                 :    Appends the value (cannot be called for objects). */
     647                 : SPL_METHOD(Array, append)
     648              15 : {
     649                 :         zval *value;
     650                 : 
     651              15 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
     652               0 :                 return;
     653                 :         }
     654              15 :         spl_array_iterator_append(getThis(), value TSRMLS_CC);
     655                 : } /* }}} */
     656                 : 
     657                 : /* {{{ proto void ArrayObject::offsetUnset(mixed $index) U
     658                 :        proto void ArrayIterator::offsetUnset(mixed $index) U
     659                 :    Unsets the value at the specified $index. */
     660                 : SPL_METHOD(Array, offsetUnset)
     661               8 : {
     662                 :         zval *index;
     663               8 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) {
     664               0 :                 return;
     665                 :         }
     666               8 :         spl_array_unset_dimension_ex(0, getThis(), index TSRMLS_CC);
     667                 : } /* }}} */
     668                 : 
     669                 : /* {{{ proto array ArrayObject::getArrayCopy() U
     670                 :       proto array ArrayIterator::getArrayCopy() U
     671                 :    Return a copy of the contained array */
     672                 : SPL_METHOD(Array, getArrayCopy)
     673              11 : {
     674              11 :         zval *object = getThis(), *tmp;
     675              11 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     676                 : 
     677              11 :     array_init(return_value);
     678              11 :         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*));
     679              11 : } /* }}} */
     680                 : 
     681                 : static HashTable *spl_array_get_properties(zval *object TSRMLS_DC) /* {{{ */
     682              52 : {
     683              52 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     684                 : 
     685              52 :         return spl_array_get_hash_table(intern, 1 TSRMLS_CC);
     686                 : } /* }}} */
     687                 : 
     688                 : static HashTable* spl_array_get_debug_info(zval *obj, int *is_temp TSRMLS_DC) /* {{{ */
     689             159 : {
     690             159 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(obj TSRMLS_CC);
     691                 :         zval *tmp, *storage;
     692                 :         int name_len;
     693                 :         zstr zname;
     694                 :         zend_class_entry *base;
     695                 : 
     696             159 :         *is_temp = 0;
     697             159 :         if (HASH_OF(intern->array) == intern->std.properties) {
     698               9 :                 return intern->std.properties;
     699                 :         } else {
     700             150 :                 if (intern->debug_info == NULL) {
     701             105 :                         ALLOC_HASHTABLE(intern->debug_info);
     702             105 :                         ZEND_INIT_SYMTABLE_EX(intern->debug_info, zend_hash_num_elements(intern->std.properties) + 1, 0);
     703                 :                 }
     704                 :         
     705             150 :                 if (intern->debug_info->nApplyCount == 0) {
     706             148 :                         zend_hash_clean(intern->debug_info);
     707             148 :                         zend_hash_copy(intern->debug_info, intern->std.properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
     708                 :                 
     709             148 :                         storage = intern->array;
     710             148 :                         zval_add_ref(&storage);
     711                 :                 
     712             148 :                         base = (Z_OBJ_HT_P(obj) == &spl_handler_ArrayIterator) ? spl_ce_ArrayIterator : spl_ce_ArrayObject;
     713             148 :                         zname = spl_gen_private_prop_name(base, "storage", sizeof("storage")-1, &name_len TSRMLS_CC);
     714             148 :                         zend_u_symtable_update(intern->debug_info, IS_UNICODE, zname, name_len+1, &storage, sizeof(zval *), NULL);
     715             148 :                         efree(zname.v);
     716                 :                 }
     717                 :         
     718             150 :                 return intern->debug_info;
     719                 :         }
     720                 : }
     721                 : /* }}} */
     722                 : 
     723                 : static zval *spl_array_read_property(zval *object, zval *member, int type TSRMLS_DC) /* {{{ */
     724              79 : {
     725              79 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     726                 : 
     727              79 :         if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
     728                 :         && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) {
     729              25 :                 return spl_array_read_dimension(object, member, type TSRMLS_CC);
     730                 :         }
     731              54 :         return std_object_handlers.read_property(object, member, type TSRMLS_CC);
     732                 : } /* }}} */
     733                 : 
     734                 : static void spl_array_write_property(zval *object, zval *member, zval *value TSRMLS_DC) /* {{{ */
     735              82 : {
     736              82 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     737                 : 
     738              82 :         if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
     739                 :         && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) {
     740              15 :                 spl_array_write_dimension(object, member, value TSRMLS_CC);
     741              15 :                 return;
     742                 :         }
     743              67 :         std_object_handlers.write_property(object, member, value TSRMLS_CC);
     744                 : } /* }}} */
     745                 : 
     746                 : static zval **spl_array_get_property_ptr_ptr(zval *object, zval *member TSRMLS_DC) /* {{{ */
     747               0 : {
     748               0 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     749                 : 
     750               0 :         if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
     751                 :         && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) {
     752               0 :                 return spl_array_get_dimension_ptr_ptr(1, object, member, 0 TSRMLS_CC);         
     753                 :         }
     754               0 :         return std_object_handlers.get_property_ptr_ptr(object, member TSRMLS_CC);
     755                 : } /* }}} */
     756                 : 
     757                 : static int spl_array_has_property(zval *object, zval *member, int has_set_exists TSRMLS_DC) /* {{{ */
     758              44 : {
     759              44 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     760                 : 
     761              44 :         if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
     762                 :         && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) {
     763              22 :                 return spl_array_has_dimension(object, member, has_set_exists TSRMLS_CC);
     764                 :         }
     765              22 :         return std_object_handlers.has_property(object, member, has_set_exists TSRMLS_CC);
     766                 : 
     767                 : } /* }}} */
     768                 : 
     769                 : static void spl_array_unset_property(zval *object, zval *member TSRMLS_DC) /* {{{ */
     770              25 : {
     771              25 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     772                 : 
     773              25 :         if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
     774                 :         && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) {
     775              11 :                 spl_array_unset_dimension(object, member TSRMLS_CC);
     776              11 :                 spl_array_rewind(intern TSRMLS_CC); /* because deletion might invalidate position */
     777              11 :                 return;
     778                 :         }
     779              14 :         std_object_handlers.unset_property(object, member TSRMLS_CC);
     780                 : } /* }}} */
     781                 : 
     782                 : static int spl_array_skip_protected(spl_array_object *intern, HashTable *aht TSRMLS_DC) /* {{{ */
     783            1917 : {
     784                 :         zstr string_key;
     785                 :         uint string_length;
     786                 :         ulong num_key;
     787                 : 
     788            1917 :         if (Z_TYPE_P(intern->array) == IS_OBJECT) {
     789                 :                 do {
     790             512 :                         if (zend_hash_get_current_key_ex(aht, &string_key, &string_length, &num_key, 0, &intern->pos) == HASH_KEY_IS_UNICODE) {
     791             191 :                                 if (!string_length || string_key.u[0]) {
     792             151 :                                         return SUCCESS;
     793                 :                                 }
     794                 :                         } else {
     795             321 :                                 return SUCCESS;
     796                 :                         }
     797              40 :                         if (zend_hash_has_more_elements_ex(aht, &intern->pos) != SUCCESS) {
     798               0 :                                 return FAILURE;
     799                 :                         }
     800              40 :                         zend_hash_move_forward_ex(aht, &intern->pos);
     801              40 :                         spl_array_update_pos(intern);
     802              40 :                 } while (1);
     803                 :         }
     804            1445 :         return FAILURE;
     805                 : } /* }}} */
     806                 : 
     807                 : static int spl_array_next_no_verify(spl_array_object *intern, HashTable *aht TSRMLS_DC) /* {{{ */
     808            1267 : {
     809            1267 :         zend_hash_move_forward_ex(aht, &intern->pos);
     810            1267 :         spl_array_update_pos(intern);
     811            1267 :         if (Z_TYPE_P(intern->array) == IS_OBJECT) {
     812             218 :                 return spl_array_skip_protected(intern, aht TSRMLS_CC);
     813                 :         } else {
     814            1049 :                 return zend_hash_has_more_elements_ex(aht, &intern->pos);
     815                 :         }
     816                 : } /* }}} */
     817                 : 
     818                 : static int spl_array_next_ex(spl_array_object *intern, HashTable *aht TSRMLS_DC) /* {{{ */
     819             311 : {
     820             311 :         if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(intern, aht TSRMLS_CC) == FAILURE) {
     821               2 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
     822               2 :                 return FAILURE;
     823                 :         }
     824                 : 
     825             309 :         return spl_array_next_no_verify(intern, aht TSRMLS_CC);
     826                 : } /* }}} */
     827                 : 
     828                 : static int spl_array_next(spl_array_object *intern TSRMLS_DC) /* {{{ */
     829             102 : {
     830             102 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
     831                 : 
     832             102 :         return spl_array_next_ex(intern, aht TSRMLS_CC);
     833                 : 
     834                 : } /* }}} */
     835                 : 
     836                 : /* {{{ define an overloaded iterator structure */
     837                 : typedef struct {
     838                 :         zend_user_iterator    intern;
     839                 :         spl_array_object      *object;
     840                 : } spl_array_it; /* }}} */
     841                 : 
     842                 : static void spl_array_it_dtor(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
     843             455 : {
     844             455 :         spl_array_it *iterator = (spl_array_it *)iter;
     845                 : 
     846             455 :         zend_user_it_invalidate_current(iter TSRMLS_CC);
     847             455 :         zval_ptr_dtor((zval**)&iterator->intern.it.data);
     848                 : 
     849             455 :         efree(iterator);
     850             455 : }
     851                 : /* }}} */
     852                 : 
     853                 : static int spl_array_it_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
     854            2414 : {
     855            2414 :         spl_array_it       *iterator = (spl_array_it *)iter;
     856            2414 :         spl_array_object   *object   = iterator->object;
     857            2414 :         HashTable          *aht      = spl_array_get_hash_table(object, 0 TSRMLS_CC);
     858                 : 
     859            2414 :         if (object->ar_flags & SPL_ARRAY_OVERLOADED_VALID) {
     860             197 :                 return zend_user_it_valid(iter TSRMLS_CC);
     861                 :         } else {
     862            2217 :                 if (!aht) {
     863               2 :                         php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::valid(): Array was modified outside object and is no longer an array");
     864               2 :                         return FAILURE;
     865                 :                 }
     866                 :         
     867            2215 :                 if (object->pos && (object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(object, aht TSRMLS_CC) == FAILURE) {
     868               0 :                         php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::valid(): Array was modified outside object and internal position is no longer valid");
     869               0 :                         return FAILURE;
     870                 :                 } else {
     871            2215 :                         return zend_hash_has_more_elements_ex(aht, &object->pos);
     872                 :                 }
     873                 :         }
     874                 : }
     875                 : /* }}} */
     876                 : 
     877                 : static void spl_array_it_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) /* {{{ */
     878             966 : {
     879             966 :         spl_array_it       *iterator = (spl_array_it *)iter;
     880             966 :         spl_array_object   *object   = iterator->object;
     881             966 :         HashTable          *aht      = spl_array_get_hash_table(object, 0 TSRMLS_CC);
     882                 : 
     883             966 :         if (object->ar_flags & SPL_ARRAY_OVERLOADED_CURRENT) {
     884              93 :                 zend_user_it_get_current_data(iter, data TSRMLS_CC);
     885                 :         } else {
     886             873 :                 if (zend_hash_get_current_data_ex(aht, (void**)data, &object->pos) == FAILURE) {
     887               0 :                         *data = NULL;
     888                 :                 }
     889                 :         }
     890             966 : }
     891                 : /* }}} */
     892                 : 
     893                 : static int spl_array_it_get_current_key(zend_object_iterator *iter, zstr *str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */
     894             779 : {
     895             779 :         spl_array_it       *iterator = (spl_array_it *)iter;
     896             779 :         spl_array_object   *object   = iterator->object;
     897             779 :         HashTable          *aht      = spl_array_get_hash_table(object, 0 TSRMLS_CC);
     898                 : 
     899             779 :         if (object->ar_flags & SPL_ARRAY_OVERLOADED_KEY) {
     900              72 :                 return zend_user_it_get_current_key(iter, str_key, str_key_len, int_key TSRMLS_CC);
     901                 :         } else {
     902             707 :                 if (!aht) {
     903               0 :                         php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::current(): Array was modified outside object and is no longer an array");
     904               0 :                         return HASH_KEY_NON_EXISTANT;
     905                 :                 }
     906                 :         
     907             707 :                 if ((object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(object, aht TSRMLS_CC) == FAILURE) {
     908               0 :                         php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::current(): Array was modified outside object and internal position is no longer valid");
     909               0 :                         return HASH_KEY_NON_EXISTANT;
     910                 :                 }
     911                 :         
     912             707 :                 return zend_hash_get_current_key_ex(aht, str_key, str_key_len, int_key, 1, &object->pos);
     913                 :         }
     914                 : }
     915                 : /* }}} */
     916                 : 
     917                 : static void spl_array_it_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
     918            1068 : {
     919            1068 :         spl_array_it       *iterator = (spl_array_it *)iter;
     920            1068 :         spl_array_object   *object   = iterator->object;
     921            1068 :         HashTable          *aht      = spl_array_get_hash_table(object, 0 TSRMLS_CC);
     922                 : 
     923            1068 :         if (object->ar_flags & SPL_ARRAY_OVERLOADED_NEXT) {
     924             104 :                 zend_user_it_move_forward(iter TSRMLS_CC);
     925                 :         } else {
     926             964 :                 zend_user_it_invalidate_current(iter TSRMLS_CC);
     927             964 :                 if (!aht) {
     928               2 :                         php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::current(): Array was modified outside object and is no longer an array");
     929               2 :                         return;
     930                 :                 }
     931                 :         
     932             966 :                 if ((object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(object, aht TSRMLS_CC) == FAILURE) {
     933               4 :                         php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::next(): Array was modified outside object and internal position is no longer valid");
     934                 :                 } else {
     935             958 :                         spl_array_next_no_verify(object, aht TSRMLS_CC);
     936                 :                 }
     937                 :         }
     938                 : }
     939                 : /* }}} */
     940                 : 
     941                 : static void spl_array_rewind_ex(spl_array_object *intern, HashTable *aht TSRMLS_DC) /* {{{ */
     942            1699 : {
     943                 : 
     944            1699 :         zend_hash_internal_pointer_reset_ex(aht, &intern->pos);
     945            1699 :         spl_array_update_pos(intern);
     946            1699 :         spl_array_skip_protected(intern, aht TSRMLS_CC);
     947                 : 
     948            1699 : } /* }}} */
     949                 : 
     950                 : static void spl_array_rewind(spl_array_object *intern TSRMLS_DC) /* {{{ */
     951            1699 : {
     952            1699 :         HashTable          *aht      = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
     953                 : 
     954            1699 :         if (!aht) {
     955               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::rewind(): Array was modified outside object and is no longer an array");
     956               0 :                 return;
     957                 :         }
     958                 : 
     959            1699 :         spl_array_rewind_ex(intern, aht TSRMLS_CC);
     960                 : }
     961                 : /* }}} */
     962                 : 
     963                 : static void spl_array_it_rewind(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
     964             449 : {
     965             449 :         spl_array_it       *iterator = (spl_array_it *)iter;
     966             449 :         spl_array_object   *object   = iterator->object;
     967                 : 
     968             449 :         if (object->ar_flags & SPL_ARRAY_OVERLOADED_REWIND) {
     969              69 :                 zend_user_it_rewind(iter TSRMLS_CC);
     970                 :         } else {
     971             380 :                 zend_user_it_invalidate_current(iter TSRMLS_CC);
     972             380 :                 spl_array_rewind(object TSRMLS_CC);
     973                 :         }
     974             449 : }
     975                 : /* }}} */
     976                 : 
     977                 : /* {{{ spl_array_set_array */
     978             502 : static void spl_array_set_array(zval *object, spl_array_object *intern, zval **array, long ar_flags, int just_array TSRMLS_DC) {
     979                 : 
     980             502 :         if (Z_TYPE_PP(array) == IS_ARRAY) {
     981             432 :                 SEPARATE_ZVAL_IF_NOT_REF(array);
     982                 :         }
     983                 : 
     984             531 :         if (Z_TYPE_PP(array) == IS_OBJECT && (Z_OBJ_HT_PP(array) == &spl_handler_ArrayObject || Z_OBJ_HT_PP(array) == &spl_handler_ArrayIterator)) {
     985              29 :                 zval_ptr_dtor(&intern->array);
     986              29 :                 if (just_array) {
     987              16 :                         spl_array_object *other = (spl_array_object*)zend_object_store_get_object(*array TSRMLS_CC);
     988              16 :                         ar_flags = other->ar_flags & ~SPL_ARRAY_INT_MASK;
     989                 :                 }               
     990              29 :                 ar_flags |= SPL_ARRAY_USE_OTHER;
     991              29 :                 intern->array = *array;
     992                 :         } else {
     993             473 :                 if (Z_TYPE_PP(array) != IS_OBJECT && Z_TYPE_PP(array) != IS_ARRAY) {
     994               2 :                         zend_throw_exception(spl_ce_InvalidArgumentException, "Passed variable is not an array or object, using empty array instead", 0 TSRMLS_CC);
     995               2 :                         return;
     996                 :                 }
     997             471 :                 zval_ptr_dtor(&intern->array);
     998             471 :                 intern->array = *array;
     999                 :         }
    1000             500 :         if (object == *array) {
    1001               4 :                 intern->ar_flags |= SPL_ARRAY_IS_SELF;
    1002               4 :                 intern->ar_flags &= ~SPL_ARRAY_USE_OTHER;
    1003                 :         } else {
    1004             496 :                 intern->ar_flags &= ~SPL_ARRAY_IS_SELF;
    1005                 :         }
    1006             500 :         intern->ar_flags |= ar_flags;
    1007             500 :         Z_ADDREF_P(intern->array);
    1008             500 :         if (Z_TYPE_PP(array) == IS_OBJECT) {
    1009              68 :                 zend_object_get_properties_t handler = Z_OBJ_HANDLER_PP(array, get_properties);
    1010              68 :                 if ((handler != std_object_handlers.get_properties && handler != spl_array_get_properties)
    1011                 :                 || !spl_array_get_hash_table(intern, 0 TSRMLS_CC)) {
    1012               0 :                         zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Overloaded object of type %v is not compatible with %v", Z_OBJCE_PP(array)->name, intern->std.ce->name);
    1013                 :                 }
    1014                 :         }
    1015                 : 
    1016             500 :         spl_array_rewind(intern TSRMLS_CC);
    1017                 : }
    1018                 : /* }}} */
    1019                 : 
    1020                 : /* {{{ iterator handler table */
    1021                 : zend_object_iterator_funcs spl_array_it_funcs = {
    1022                 :         spl_array_it_dtor,
    1023                 :         spl_array_it_valid,
    1024                 :         spl_array_it_get_current_data,
    1025                 :         spl_array_it_get_current_key,
    1026                 :         spl_array_it_move_forward,
    1027                 :         spl_array_it_rewind
    1028                 : }; /* }}} */
    1029                 : 
    1030                 : zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */
    1031             456 : {
    1032                 :         spl_array_it       *iterator;
    1033             456 :         spl_array_object   *array_object = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1034                 : 
    1035             456 :         if (by_ref && (array_object->ar_flags & SPL_ARRAY_OVERLOADED_CURRENT)) {
    1036               1 :                 zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
    1037                 :         }
    1038                 : 
    1039             455 :         iterator     = emalloc(sizeof(spl_array_it));
    1040                 : 
    1041             455 :         Z_ADDREF_P(object);
    1042             455 :         iterator->intern.it.data = (void*)object;
    1043             455 :         iterator->intern.it.funcs = &spl_array_it_funcs;
    1044             455 :         iterator->intern.ce = ce;
    1045             455 :         iterator->intern.value = NULL;
    1046             455 :         iterator->object = array_object;
    1047                 :         
    1048             455 :         return (zend_object_iterator*)iterator;
    1049                 : }
    1050                 : /* }}} */
    1051                 : 
    1052                 : /* {{{ proto void ArrayObject::__construct(array|object ar = array() [, int flags = 0 [, string iterator_class = "ArrayIterator"]]) U
    1053                 :        proto void ArrayIterator::__construct(array|object ar = array() [, int flags = 0]) U
    1054                 :    Constructs a new array iterator from a path. */
    1055                 : SPL_METHOD(Array, __construct)
    1056             542 : {
    1057             542 :         zval *object = getThis();
    1058                 :         spl_array_object *intern;
    1059                 :         zval **array;
    1060             542 :         long ar_flags = 0;
    1061             542 :         zend_class_entry *ce_get_iterator = spl_ce_Iterator;
    1062                 :         zend_error_handling error_handling;
    1063                 : 
    1064             542 :         if (ZEND_NUM_ARGS() == 0) {
    1065              45 :                 return; /* nothing to do */
    1066                 :         }
    1067                 : 
    1068             497 :         zend_replace_error_handling(EH_THROW, spl_ce_InvalidArgumentException, &error_handling TSRMLS_CC);
    1069                 : 
    1070             497 :         intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1071                 : 
    1072             497 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|lC", &array, &ar_flags, &ce_get_iterator) == FAILURE) {
    1073               5 :                 zend_restore_error_handling(&error_handling TSRMLS_CC);
    1074               5 :                 return;
    1075                 :         }
    1076                 : 
    1077             492 :         if (ZEND_NUM_ARGS() > 2) {
    1078               3 :                 intern->ce_get_iterator = ce_get_iterator;
    1079                 :         }
    1080                 : 
    1081             492 :         ar_flags &= ~SPL_ARRAY_INT_MASK;
    1082                 : 
    1083             492 :         spl_array_set_array(object, intern, array, ar_flags, ZEND_NUM_ARGS() == 1 TSRMLS_CC);
    1084             492 :         zend_restore_error_handling(&error_handling TSRMLS_CC);
    1085                 : }
    1086                 : /* }}} */
    1087                 : 
    1088                 : /* {{{ proto void ArrayObject::setIteratorClass(string iterator_class) U
    1089                 :    Set the class used in getIterator. */
    1090                 : SPL_METHOD(Array, setIteratorClass)
    1091               4 : {
    1092               4 :         zval *object = getThis();
    1093               4 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1094               4 :         zend_class_entry *ce_get_iterator = spl_ce_Iterator;
    1095                 : 
    1096               4 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "C", &ce_get_iterator) == FAILURE) {
    1097               2 :                 return;
    1098                 :         }
    1099                 : 
    1100               2 :         intern->ce_get_iterator = ce_get_iterator;
    1101                 : }
    1102                 : /* }}} */
    1103                 : 
    1104                 : /* {{{ proto string ArrayObject::getIteratorClass() U
    1105                 :    Get the class used in getIterator. */
    1106                 : SPL_METHOD(Array, getIteratorClass)
    1107               4 : {
    1108               4 :         zval *object = getThis();
    1109               4 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1110                 : 
    1111               4 :         RETURN_UNICODEL(intern->ce_get_iterator->name.u, intern->ce_get_iterator->name_length, 1);
    1112                 : }
    1113                 : /* }}} */
    1114                 : 
    1115                 : /* {{{ proto int ArrayObject::getFlags() U
    1116                 :    Get flags */
    1117                 : SPL_METHOD(Array, getFlags)
    1118              30 : {
    1119              30 :         zval *object = getThis();
    1120              30 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1121                 :         
    1122              30 :         RETURN_LONG(intern->ar_flags & ~SPL_ARRAY_INT_MASK);
    1123                 : }
    1124                 : /* }}} */
    1125                 : 
    1126                 : /* {{{ proto void ArrayObject::setFlags(int flags) U
    1127                 :    Set flags */
    1128                 : SPL_METHOD(Array, setFlags)
    1129              16 : {
    1130              16 :         zval *object = getThis();
    1131              16 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1132              16 :         long ar_flags = 0;
    1133                 : 
    1134              16 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &ar_flags) == FAILURE) {
    1135               0 :                 return;
    1136                 :         }
    1137                 :         
    1138              16 :         intern->ar_flags = (intern->ar_flags & SPL_ARRAY_INT_MASK) | (ar_flags & ~SPL_ARRAY_INT_MASK);
    1139                 : }
    1140                 : /* }}} */
    1141                 : 
    1142                 : /* {{{ proto Array|Object ArrayObject::exchangeArray(Array|Object ar = array()) U
    1143                 :    Replace the referenced array or object with a new one and return the old one (right now copy - to be changed) */
    1144                 : SPL_METHOD(Array, exchangeArray)
    1145              11 : {
    1146              11 :         zval *object = getThis(), *tmp, **array;
    1147              11 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1148                 : 
    1149              11 :         array_init(return_value);
    1150              11 :         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*));
    1151                 :         
    1152              11 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &array) == FAILURE) {
    1153               1 :                 return;
    1154                 :         }
    1155                 : 
    1156              10 :         spl_array_set_array(object, intern, array, 0L, 1 TSRMLS_CC);
    1157                 : 
    1158                 : }
    1159                 : /* }}} */
    1160                 : 
    1161                 : /* {{{ proto ArrayIterator ArrayObject::getIterator() U
    1162                 :    Create a new iterator from a ArrayObject instance */
    1163                 : SPL_METHOD(Array, getIterator)
    1164              66 : {
    1165              66 :         zval *object = getThis();
    1166              66 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1167                 :         spl_array_object *iterator;
    1168              66 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
    1169                 : 
    1170              66 :         if (!aht) {
    1171               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
    1172               0 :                 return;
    1173                 :         }
    1174                 : 
    1175              66 :         return_value->type = IS_OBJECT;
    1176              66 :         return_value->value.obj = spl_array_object_new_ex(intern->ce_get_iterator, &iterator, object, 0 TSRMLS_CC);
    1177              66 :         Z_SET_REFCOUNT_P(return_value, 1);
    1178              66 :         Z_SET_ISREF_P(return_value);
    1179                 : }
    1180                 : /* }}} */
    1181                 : 
    1182                 : /* {{{ proto void ArrayIterator::rewind() U
    1183                 :    Rewind array back to the start */
    1184                 : SPL_METHOD(Array, rewind)
    1185             115 : {
    1186             115 :         zval *object = getThis();
    1187             115 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1188                 : 
    1189             115 :         spl_array_rewind(intern TSRMLS_CC);
    1190             115 : }
    1191                 : /* }}} */
    1192                 : 
    1193                 : /* {{{ proto void ArrayIterator::seek(int $position) U
    1194                 :    Seek to position. */
    1195                 : SPL_METHOD(Array, seek)
    1196              27 : {
    1197                 :         long opos, position;
    1198              27 :         zval *object = getThis();
    1199              27 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1200              27 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
    1201                 :         int result;
    1202                 : 
    1203              27 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &position) == FAILURE) {
    1204               0 :                 return;
    1205                 :         }
    1206                 : 
    1207              27 :         if (!aht) {
    1208               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
    1209               0 :                 return;
    1210                 :         }
    1211                 : 
    1212              27 :         opos = position;
    1213                 : 
    1214              27 :         if (position >= 0) { /* negative values are not supported */
    1215              26 :                 spl_array_rewind(intern TSRMLS_CC);
    1216              26 :                 result = SUCCESS;
    1217                 :                 
    1218             112 :                 while (position-- > 0 && (result = spl_array_next(intern TSRMLS_CC)) == SUCCESS);
    1219                 :         
    1220              26 :                 if (result == SUCCESS && zend_hash_has_more_elements_ex(aht, &intern->pos) == SUCCESS) {
    1221              25 :                         return; /* ok */
    1222                 :                 }
    1223                 :         }
    1224               2 :         zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0 TSRMLS_CC, "Seek position %ld is out of range", opos);
    1225                 : } /* }}} */
    1226                 : 
    1227                 : int static spl_array_object_count_elements_helper(spl_array_object *intern, long *count TSRMLS_DC) /* {{{ */
    1228              25 : {
    1229              25 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
    1230                 :         HashPosition pos;
    1231                 : 
    1232              25 :         if (!aht) {
    1233               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
    1234               0 :                 *count = 0;
    1235               0 :                 return FAILURE;
    1236                 :         }
    1237                 : 
    1238              25 :         if (Z_TYPE_P(intern->array) == IS_OBJECT) {
    1239                 :                 /* We need to store the 'pos' since we'll modify it in the functions 
    1240                 :                  * we're going to call and which do not support 'pos' as parameter. */
    1241               5 :                 pos = intern->pos;
    1242               5 :                 *count = 0;
    1243               5 :                 spl_array_rewind(intern TSRMLS_CC);
    1244              25 :                 while(intern->pos && spl_array_next(intern TSRMLS_CC) == SUCCESS) {
    1245              15 :                         (*count)++;
    1246                 :                 }
    1247               5 :                 spl_array_set_pos(intern, pos);
    1248               5 :                 return SUCCESS;
    1249                 :         } else {
    1250              20 :                 *count = zend_hash_num_elements(aht);
    1251              20 :                 return SUCCESS;
    1252                 :         }
    1253                 : } /* }}} */
    1254                 : 
    1255                 : int spl_array_object_count_elements(zval *object, long *count TSRMLS_DC) /* {{{ */
    1256              16 : {
    1257              16 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1258                 : 
    1259              16 :         if (intern->fptr_count) {
    1260                 :                 zval *rv;
    1261               7 :                 zend_call_method_with_0_params(&object, intern->std.ce, &intern->fptr_count, "count", &rv);
    1262               7 :                 if (rv) {
    1263               7 :                         zval_ptr_dtor(&intern->retval);
    1264               7 :                         MAKE_STD_ZVAL(intern->retval);
    1265               7 :                         ZVAL_ZVAL(intern->retval, rv, 1, 1);
    1266               7 :                         convert_to_long(intern->retval);
    1267               7 :                         *count = (long) Z_LVAL_P(intern->retval);
    1268               7 :                         return SUCCESS;
    1269                 :                 }
    1270               0 :                 *count = 0;
    1271               0 :                 return FAILURE;
    1272                 :         }
    1273               9 :         return spl_array_object_count_elements_helper(intern, count TSRMLS_CC);
    1274                 : } /* }}} */
    1275                 : 
    1276                 : /* {{{ proto int ArrayObject::count() U
    1277                 :        proto int ArrayIterator::count() U
    1278                 :    Return the number of elements in the Iterator. */
    1279                 : SPL_METHOD(Array, count)
    1280              16 : {
    1281                 :         long count;
    1282              16 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
    1283                 : 
    1284              16 :         spl_array_object_count_elements_helper(intern, &count TSRMLS_CC);
    1285              16 :         RETURN_LONG(count);
    1286                 : } /* }}} */
    1287                 : 
    1288                 : /* {{{ static void spl_array_method
    1289                 : */
    1290                 : static void spl_array_method(INTERNAL_FUNCTION_PARAMETERS, char *fname, int fname_len, int use_arg)
    1291              17 : {
    1292              17 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
    1293              17 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
    1294                 :         zval *tmp, *arg;
    1295              17 :         zval *retval_ptr = NULL;
    1296                 :         
    1297              17 :         MAKE_STD_ZVAL(tmp);
    1298              17 :         Z_TYPE_P(tmp) = IS_ARRAY;
    1299              17 :         Z_ARRVAL_P(tmp) = aht;
    1300                 :         
    1301              17 :         if (use_arg) {
    1302               6 :                 if (ZEND_NUM_ARGS() != 1 || zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "z", &arg) == FAILURE) {
    1303               4 :                         Z_TYPE_P(tmp) = IS_NULL;
    1304               4 :                         zval_ptr_dtor(&tmp);
    1305               4 :                         zend_throw_exception(spl_ce_BadMethodCallException, "Function expects exactly one argument", 0 TSRMLS_CC);
    1306               4 :                         return;
    1307                 :                 }
    1308               2 :                 zend_call_method(NULL, NULL, NULL, fname, fname_len, &retval_ptr, 2, tmp, arg TSRMLS_CC);
    1309                 :         } else {
    1310              11 :                 zend_call_method(NULL, NULL, NULL, fname, fname_len, &retval_ptr, 1, tmp, NULL TSRMLS_CC);
    1311                 :         }
    1312              13 :         Z_TYPE_P(tmp) = IS_NULL; /* we want to destroy the zval, not the hashtable */
    1313              13 :         zval_ptr_dtor(&tmp);
    1314              13 :         if (retval_ptr) {
    1315              13 :                 COPY_PZVAL_TO_ZVAL(*return_value, retval_ptr);
    1316                 :         }
    1317                 : } /* }}} */
    1318                 : 
    1319                 : /* {{{ SPL_ARRAY_METHOD */
    1320                 : #define SPL_ARRAY_METHOD(cname, fname, use_arg) \
    1321                 : SPL_METHOD(cname, fname) \
    1322                 : { \
    1323                 :         spl_array_method(INTERNAL_FUNCTION_PARAM_PASSTHRU, #fname, sizeof(#fname)-1, use_arg); \
    1324                 : } /* }}} */
    1325                 : 
    1326                 : /* {{{ proto int ArrayObject::asort() U
    1327                 :        proto int ArrayIterator::asort() U
    1328                 :    Sort the entries by values. */
    1329               4 : SPL_ARRAY_METHOD(Array, asort, 0) /* }}} */
    1330                 : 
    1331                 : /* {{{ proto int ArrayObject::ksort() U
    1332                 :        proto int ArrayIterator::ksort() U
    1333                 :    Sort the entries by key. */
    1334               3 : SPL_ARRAY_METHOD(Array, ksort, 0) /* }}} */
    1335                 : 
    1336                 : /* {{{ proto int ArrayObject::uasort(callback cmp_function) U
    1337                 :        proto int ArrayIterator::uasort(callback cmp_function) U
    1338                 :    Sort the entries by values user defined function. */
    1339               3 : SPL_ARRAY_METHOD(Array, uasort, 1) /* }}} */
    1340                 : 
    1341                 : /* {{{ proto int ArrayObject::uksort(callback cmp_function) U
    1342                 :        proto int ArrayIterator::uksort(callback cmp_function) U
    1343                 :    Sort the entries by key using user defined function. */
    1344               3 : SPL_ARRAY_METHOD(Array, uksort, 1) /* }}} */
    1345                 : 
    1346                 : /* {{{ proto int ArrayObject::natsort() U
    1347                 :        proto int ArrayIterator::natsort() U
    1348                 :    Sort the entries by values using "natural order" algorithm. */
    1349               2 : SPL_ARRAY_METHOD(Array, natsort, 0) /* }}} */
    1350                 : 
    1351                 : /* {{{ proto int ArrayObject::natcasesort() U
    1352                 :        proto int ArrayIterator::natcasesort() U
    1353                 :    Sort the entries by key using case insensitive "natural order" algorithm. */
    1354               2 : SPL_ARRAY_METHOD(Array, natcasesort, 0) /* }}} */
    1355                 : 
    1356                 : /* {{{ proto mixed|NULL ArrayIterator::current() U
    1357                 :    Return current array entry */
    1358                 : SPL_METHOD(Array, current)
    1359             228 : {
    1360             228 :         zval *object = getThis();
    1361             228 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1362                 :         zval **entry;
    1363             228 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
    1364                 : 
    1365             228 :         if (!aht) {
    1366               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
    1367               0 :                 return;
    1368                 :         }
    1369                 : 
    1370             228 :         if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(intern, aht TSRMLS_CC) == FAILURE) {
    1371               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
    1372               0 :                 return;
    1373                 :         }
    1374                 : 
    1375             228 :         if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) {
    1376               0 :                 return;
    1377                 :         }
    1378             228 :         RETVAL_ZVAL(*entry, 1, 0);
    1379                 : }
    1380                 : /* }}} */
    1381                 : 
    1382                 : void spl_array_iterator_key(zval *object, zval *return_value TSRMLS_DC) /* {{{ */
    1383             186 : {
    1384             186 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1385                 :         zstr string_key;
    1386                 :         uint string_length;
    1387                 :         ulong num_key;
    1388             186 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
    1389                 : 
    1390             186 :         if (!aht) {
    1391               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
    1392               0 :                 return;
    1393                 :         }
    1394                 : 
    1395             186 :         if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(intern, aht TSRMLS_CC) == FAILURE) {
    1396               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
    1397               0 :                 return;
    1398                 :         }
    1399                 : 
    1400             186 :         switch (zend_hash_get_current_key_ex(aht, &string_key, &string_length, &num_key, 1, &intern->pos)) {
    1401                 :                 case HASH_KEY_IS_STRING:
    1402               0 :                         RETVAL_STRINGL(string_key.s, string_length - 1, 0);
    1403               0 :                         break;
    1404                 :                 case HASH_KEY_IS_UNICODE:
    1405              13 :                         RETVAL_UNICODEL(string_key.u, string_length - 1, 0);
    1406              13 :                         break;
    1407                 :                 case HASH_KEY_IS_LONG:
    1408             173 :                         RETVAL_LONG(num_key);
    1409             173 :                         break;
    1410                 :                 case HASH_KEY_NON_EXISTANT:
    1411               0 :                         return;
    1412                 :         }
    1413                 : }
    1414                 : /* }}} */
    1415                 : 
    1416                 : /* {{{  proto mixed|NULL ArrayIterator::key() U
    1417                 :    Return current array key */
    1418                 : SPL_METHOD(Array, key)
    1419             180 : {
    1420             180 :         spl_array_iterator_key(getThis(), return_value TSRMLS_CC);      
    1421             180 : }
    1422                 : /* }}} */
    1423                 : 
    1424                 : /* {{{ proto void ArrayIterator::next() U
    1425                 :    Move to next entry */
    1426                 : SPL_METHOD(Array, next)
    1427             209 : {
    1428             209 :         zval *object = getThis();
    1429             209 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1430             209 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
    1431                 : 
    1432             209 :         if (!aht) {
    1433               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
    1434               0 :                 return;
    1435                 :         }
    1436                 : 
    1437             209 :         spl_array_next_ex(intern, aht TSRMLS_CC);
    1438                 : }
    1439                 : /* }}} */
    1440                 : 
    1441                 : /* {{{ proto bool ArrayIterator::valid() U
    1442                 :    Check whether array contains more entries */
    1443                 : SPL_METHOD(Array, valid)
    1444             558 : {
    1445             558 :         zval *object = getThis();
    1446             558 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1447             558 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
    1448                 : 
    1449             558 :         if (!aht) {
    1450               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
    1451               0 :                 return;
    1452                 :         }
    1453                 : 
    1454             558 :         if (intern->pos && (intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(intern, aht TSRMLS_CC) == FAILURE) {
    1455               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
    1456               0 :                 RETURN_FALSE;
    1457                 :         } else {
    1458             558 :                 RETURN_BOOL(zend_hash_has_more_elements_ex(aht, &intern->pos) == SUCCESS);
    1459                 :         }
    1460                 : }
    1461                 : /* }}} */
    1462                 : 
    1463                 : /* {{{ proto bool RecursiveArrayIterator::hasChildren() U
    1464                 :    Check whether current element has children (e.g. is an array) */
    1465                 : SPL_METHOD(Array, hasChildren)
    1466             685 : {
    1467             685 :         zval *object = getThis(), **entry;
    1468             685 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1469             685 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
    1470                 :         
    1471             685 :         if (!aht) {
    1472               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
    1473               0 :                 RETURN_FALSE;
    1474                 :         }
    1475                 : 
    1476             685 :         if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(intern, aht TSRMLS_CC) == FAILURE) {
    1477               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
    1478               0 :                 RETURN_FALSE;
    1479                 :         }
    1480                 : 
    1481             685 :         if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) {
    1482               9 :                 RETURN_FALSE;
    1483                 :         }
    1484                 : 
    1485             676 :         RETURN_BOOL(Z_TYPE_PP(entry) == IS_ARRAY || (Z_TYPE_PP(entry) == IS_OBJECT && (intern->ar_flags & SPL_ARRAY_CHILD_ARRAYS_ONLY) == 0));
    1486                 : }
    1487                 : /* }}} */
    1488                 : 
    1489                 : /* {{{ proto object RecursiveArrayIterator::getChildren() U
    1490                 :    Create a sub iterator for the current element (same class as $this) */
    1491                 : SPL_METHOD(Array, getChildren)
    1492             183 : {
    1493             183 :         zval *object = getThis(), **entry, *flags;
    1494             183 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1495             183 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
    1496                 : 
    1497             183 :         if (!aht) {
    1498               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
    1499               0 :                 return;
    1500                 :         }
    1501                 : 
    1502             183 :         if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(intern, aht TSRMLS_CC) == FAILURE) {
    1503               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
    1504               0 :                 return;
    1505                 :         }
    1506                 : 
    1507             183 :         if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) {
    1508               0 :                 return;
    1509                 :         }
    1510                 : 
    1511             183 :         if (Z_TYPE_PP(entry) == IS_OBJECT) {
    1512               6 :                 if ((intern->ar_flags & SPL_ARRAY_CHILD_ARRAYS_ONLY) != 0) {
    1513               0 :                         return;
    1514                 :                 }
    1515               6 :                 if (instanceof_function(Z_OBJCE_PP(entry), Z_OBJCE_P(getThis()) TSRMLS_CC)) {
    1516               0 :                         RETURN_ZVAL(*entry, 0, 0);
    1517                 :                 }
    1518                 :         }
    1519                 : 
    1520             183 :         MAKE_STD_ZVAL(flags);
    1521             183 :         ZVAL_LONG(flags, SPL_ARRAY_USE_OTHER | intern->ar_flags);
    1522                 : 
    1523             183 :         spl_instantiate_arg_ex2(intern->std.ce, &return_value, 0, *entry, flags TSRMLS_CC);
    1524             183 :         zval_ptr_dtor(&flags);
    1525                 : }
    1526                 : /* }}} */
    1527                 : 
    1528                 : smart_str spl_array_serialize_helper(spl_array_object *intern, php_serialize_data_t *var_hash_p TSRMLS_DC) /* {{{ */
    1529              12 : {
    1530              12 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
    1531                 :         zval members, *pmembers;
    1532              12 :         smart_str buf = {0};
    1533                 :         zval *flags;
    1534                 : 
    1535              12 :         if (!aht) {
    1536               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
    1537               0 :                 return buf;
    1538                 :         }
    1539                 : 
    1540              12 :         MAKE_STD_ZVAL(flags);
    1541              12 :         ZVAL_LONG(flags, (intern->ar_flags & SPL_ARRAY_CLONE_MASK));
    1542                 : 
    1543                 :         /* storage */
    1544              12 :         smart_str_appendl(&buf, "x:", 2);
    1545              12 :         php_var_serialize(&buf, &flags, var_hash_p TSRMLS_CC);
    1546              12 :         zval_ptr_dtor(&flags);
    1547                 : 
    1548              12 :         if (!(intern->ar_flags & SPL_ARRAY_IS_SELF)) {
    1549              12 :                 php_var_serialize(&buf, &intern->array, var_hash_p TSRMLS_CC);
    1550              12 :                 smart_str_appendc(&buf, ';');
    1551                 :         }
    1552                 : 
    1553                 :         /* members */
    1554              12 :         smart_str_appendl(&buf, "m:", 2);
    1555              12 :         INIT_PZVAL(&members);
    1556              12 :         Z_ARRVAL(members) = intern->std.properties;
    1557              12 :         Z_TYPE(members) = IS_ARRAY;
    1558              12 :         pmembers = &members;
    1559              12 :         php_var_serialize(&buf, &pmembers, var_hash_p TSRMLS_CC); /* finishes the string */
    1560                 : 
    1561              12 :         return buf;
    1562                 : }
    1563                 : /* }}} */
    1564                 : 
    1565                 : /* {{{ proto string ArrayObject::serialize()
    1566                 :    Serialize the object */
    1567                 : SPL_METHOD(Array, serialize)
    1568               4 : {
    1569               4 :         zval *object = getThis();
    1570               4 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1571               4 :         int was_in_serialize = intern->serialize_data != NULL;
    1572                 :         smart_str buf;
    1573                 : 
    1574               4 :         if (!was_in_serialize) {
    1575               2 :                 intern->serialize_data = emalloc(sizeof(php_serialize_data_t));
    1576               2 :                 PHP_VAR_SERIALIZE_INIT(*intern->serialize_data);
    1577                 :         }
    1578                 : 
    1579               4 :         buf = spl_array_serialize_helper(intern, intern->serialize_data TSRMLS_CC);
    1580                 : 
    1581               4 :         if (!was_in_serialize) {
    1582               2 :                 PHP_VAR_SERIALIZE_DESTROY(*intern->serialize_data);
    1583               2 :                 efree(intern->serialize_data);
    1584               2 :                 intern->serialize_data = NULL;
    1585                 :         }
    1586                 : 
    1587               4 :         if (buf.c) {
    1588               4 :                 RETURN_STRINGL(buf.c, buf.len, 0);
    1589                 :         } 
    1590                 : 
    1591               0 :         RETURN_NULL();
    1592                 : } /* }}} */
    1593                 : 
    1594                 : int spl_array_serialize(zval *object, int *type, zstr *buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC) /* {{{ */
    1595              10 : {
    1596              10 :         spl_array_object     *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1597                 : 
    1598              10 :         if (intern->fptr_serialize) {
    1599                 :                 int retval;
    1600                 :                 php_serialize_data_t *before;
    1601                 : 
    1602               2 :                 before = intern->serialize_data;
    1603               2 :                 intern->serialize_data = (php_serialize_data_t *)data;
    1604                 : 
    1605               2 :                 retval = zend_user_serialize(object, type, buffer, buf_len, data TSRMLS_CC);
    1606                 : 
    1607               2 :                 intern->serialize_data = before;
    1608                 : 
    1609               2 :                 return retval;
    1610                 :         } else {
    1611                 :                 smart_str buf;
    1612                 : 
    1613               8 :                 buf = spl_array_serialize_helper(intern, (php_serialize_data_t *)data TSRMLS_CC);
    1614                 : 
    1615               8 :                 if (buf.c) {
    1616               8 :                         buffer->s = estrndup(buf.c, buf.len);
    1617               8 :                         *buf_len  = buf.len;
    1618               8 :                         *type     = IS_STRING;
    1619               8 :                         efree(buf.c);
    1620               8 :                         return SUCCESS;
    1621                 :                 } else {
    1622               0 :                         return FAILURE;
    1623                 :                 }
    1624                 :         }
    1625                 : }
    1626                 : /* }}} */
    1627                 : 
    1628                 : void spl_array_unserialize_helper(spl_array_object *intern, const unsigned char *buf, zend_uint buf_len, php_unserialize_data_t *var_hash_p TSRMLS_DC) /* {{{ */
    1629              11 : {
    1630                 :         const unsigned char *p, *s;
    1631              11 :         zval *pmembers, *pflags = NULL;
    1632                 :         long flags;
    1633                 :         
    1634              11 :         s = p = buf;
    1635                 : 
    1636              11 :         if (*p!= 'x' || *++p != ':') {
    1637                 :                 goto outexcept;
    1638                 :         }
    1639              11 :         ++p;
    1640                 : 
    1641              11 :         ALLOC_INIT_ZVAL(pflags);
    1642              11 :         if (!php_var_unserialize(&pflags, &p, s + buf_len, var_hash_p TSRMLS_CC) || Z_TYPE_P(pflags) != IS_LONG) {
    1643               0 :                 zval_ptr_dtor(&pflags);
    1644               0 :                 goto outexcept;
    1645                 :         }
    1646                 : 
    1647              11 :         --p; /* for ';' */
    1648              11 :         flags = Z_LVAL_P(pflags);
    1649              11 :         zval_ptr_dtor(&pflags);
    1650                 :         /* flags needs to be verified and we also need to verify whether the next
    1651                 :          * thing we get is ';'. After that we require an 'm' or somethign else
    1652                 :          * where 'm' stands for members and anything else should be an array. If
    1653                 :          * neither 'a' or 'm' follows we have an error. */
    1654                 : 
    1655              11 :         if (*p != ';') {
    1656               0 :                 goto outexcept;
    1657                 :         }
    1658              11 :         ++p;
    1659                 : 
    1660              11 :         if (*p!='m') {
    1661              11 :                 if (*p!='a' && *p!='O' && *p!='C') {
    1662               0 :                         goto outexcept;
    1663                 :                 }
    1664              11 :                 intern->ar_flags &= ~SPL_ARRAY_CLONE_MASK;
    1665              11 :                 intern->ar_flags |= flags & SPL_ARRAY_CLONE_MASK;
    1666              11 :                 zval_ptr_dtor(&intern->array);
    1667              11 :                 ALLOC_INIT_ZVAL(intern->array);
    1668              11 :                 if (!php_var_unserialize(&intern->array, &p, s + buf_len, var_hash_p TSRMLS_CC)) {
    1669               0 :                         goto outexcept;
    1670                 :                 }
    1671                 :         }
    1672              11 :         if (*p != ';') {
    1673               0 :                 goto outexcept;
    1674                 :         }
    1675              11 :         ++p;
    1676                 : 
    1677                 :         /* members */
    1678              11 :         if (*p!= 'm' || *++p != ':') {
    1679                 :                 goto outexcept;
    1680                 :         }
    1681              11 :         ++p;
    1682                 : 
    1683              11 :         ALLOC_INIT_ZVAL(pmembers);
    1684              11 :         if (!php_var_unserialize(&pmembers, &p, s + buf_len, var_hash_p TSRMLS_CC)) {
    1685               0 :                 zval_ptr_dtor(&pmembers);
    1686               0 :                 goto outexcept;
    1687                 :         }
    1688                 : 
    1689                 :         /* copy members */
    1690              11 :         zend_hash_copy(intern->std.properties, Z_ARRVAL_P(pmembers), (copy_ctor_func_t) zval_add_ref, (void *) NULL, sizeof(zval *));
    1691              11 :         zval_ptr_dtor(&pmembers);
    1692                 : 
    1693                 :         /* done reading $serialized */
    1694                 : 
    1695              11 :         return;
    1696                 : 
    1697               0 : outexcept:
    1698               0 :         zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Error at offset %ld of %d bytes", (long)((char*)p - (char *)buf), buf_len);
    1699               0 :         return;
    1700                 : }
    1701                 : /* }}} */
    1702                 : 
    1703                 : /* {{{ proto void ArrayObject::unserialize(string serialized)
    1704                 :    Unserialize the object */
    1705                 : SPL_METHOD(Array, unserialize)
    1706               5 : {
    1707                 :         char *buf;
    1708                 :         int buf_len;
    1709               5 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
    1710               5 :         int was_in_unserialize = intern->unserialize_data != NULL;
    1711                 : 
    1712               5 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &buf, &buf_len) == FAILURE) {
    1713               0 :                 return;
    1714                 :         }
    1715                 : 
    1716               5 :         if (buf_len == 0) {
    1717               1 :                 zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Serialized string cannot be empty");
    1718               1 :                 return;
    1719                 :         }
    1720                 : 
    1721               4 :         if (!was_in_unserialize) {
    1722               2 :                 intern->unserialize_data = emalloc(sizeof(php_unserialize_data_t));
    1723               2 :                 PHP_VAR_UNSERIALIZE_INIT(*intern->unserialize_data);
    1724                 :         }
    1725                 : 
    1726               4 :         spl_array_unserialize_helper(intern, (const unsigned char *)buf, buf_len, intern->unserialize_data TSRMLS_CC);
    1727                 : 
    1728               4 :         if (!was_in_unserialize) {
    1729               2 :                 PHP_VAR_UNSERIALIZE_DESTROY(*intern->unserialize_data);
    1730               2 :                 efree(intern->unserialize_data);
    1731               2 :                 intern->unserialize_data = NULL;
    1732                 :         }
    1733                 : }
    1734                 : /* }}} */
    1735                 : 
    1736                 : int spl_array_unserialize(zval **object, zend_class_entry *ce, int type, const zstr buf, zend_uint buf_len, zend_unserialize_data *data TSRMLS_DC) /* {{{ */
    1737               9 : {
    1738                 :         spl_array_object *intern;
    1739                 : 
    1740               9 :         object_init_ex(*object, ce);
    1741               9 :         intern = (spl_array_object*)zend_object_store_get_object(*object TSRMLS_CC);
    1742                 : 
    1743               9 :         if (intern->fptr_unserialize) {
    1744                 :                 zval *zdata;
    1745                 :                 php_unserialize_data_t *before;
    1746               2 :                 MAKE_STD_ZVAL(zdata);
    1747               2 :                 ZVAL_ZSTRL(zdata, type, buf, buf_len, 1);
    1748                 : 
    1749               2 :                 before = intern->unserialize_data;
    1750               2 :                 intern->unserialize_data = (php_unserialize_data_t *)data;
    1751                 : 
    1752               2 :                 zend_call_method_with_1_params(object, ce, &ce->unserialize_func, "unserialize", NULL, zdata);
    1753                 : 
    1754               2 :                 intern->unserialize_data = before;
    1755                 : 
    1756               2 :                 zval_ptr_dtor(&zdata);
    1757                 :         } else {
    1758               7 :                 if (type == IS_STRING) {
    1759               7 :                         spl_array_unserialize_helper(intern, (unsigned char *)buf.s, buf_len, (php_unserialize_data_t *)data TSRMLS_CC);
    1760                 :                 } else {
    1761               0 :                         unsigned char *bufc = (unsigned char*)zend_unicode_to_ascii(buf.u, buf_len TSRMLS_CC);
    1762               0 :                         if (!bufc) {
    1763               0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Binary or ASCII-Unicode string expected, non-ASCII-Unicode string received");
    1764               0 :                                 return FAILURE;
    1765                 :                         }
    1766                 : 
    1767               0 :                         spl_array_unserialize_helper(intern, bufc, buf_len, (php_unserialize_data_t *)data TSRMLS_CC);
    1768                 : 
    1769               0 :                         efree(bufc);
    1770                 :                 }
    1771                 :         }
    1772                 : 
    1773               9 :         if (EG(exception)) {
    1774               0 :                 return FAILURE;
    1775                 :         } else {
    1776               9 :                 return SUCCESS;
    1777                 :         }
    1778                 : }
    1779                 : /* }}} */
    1780                 : 
    1781                 : /* {{{ arginfo */
    1782                 : ZEND_BEGIN_ARG_INFO(arginfo_array___construct, 0)
    1783                 :         ZEND_ARG_INFO(0, array)
    1784                 : ZEND_END_ARG_INFO()
    1785                 : 
    1786                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_array_offsetGet, 0, 0, 1)
    1787                 :         ZEND_ARG_INFO(0, index)
    1788                 : ZEND_END_ARG_INFO()
    1789                 : 
    1790                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_array_offsetSet, 0, 0, 2)
    1791                 :         ZEND_ARG_INFO(0, index)
    1792                 :         ZEND_ARG_INFO(0, newval)
    1793                 : ZEND_END_ARG_INFO()
    1794                 : 
    1795                 : ZEND_BEGIN_ARG_INFO(arginfo_array_append, 0)
    1796                 :         ZEND_ARG_INFO(0, value)
    1797                 : ZEND_END_ARG_INFO()
    1798                 : 
    1799                 : ZEND_BEGIN_ARG_INFO(arginfo_array_seek, 0)
    1800                 :         ZEND_ARG_INFO(0, position)
    1801                 : ZEND_END_ARG_INFO()
    1802                 : 
    1803                 : ZEND_BEGIN_ARG_INFO(arginfo_array_exchangeArray, 0)
    1804                 :         ZEND_ARG_INFO(0, array)
    1805                 : ZEND_END_ARG_INFO()
    1806                 : 
    1807                 : ZEND_BEGIN_ARG_INFO(arginfo_array_setFlags, 0)
    1808                 :         ZEND_ARG_INFO(0, flags)
    1809                 : ZEND_END_ARG_INFO()
    1810                 : 
    1811                 : ZEND_BEGIN_ARG_INFO(arginfo_array_setIteratorClass, 0)
    1812                 :         ZEND_ARG_INFO(0, iteratorClass)
    1813                 : ZEND_END_ARG_INFO()
    1814                 : 
    1815                 : ZEND_BEGIN_ARG_INFO(arginfo_array_uXsort, 0)
    1816                 :         ZEND_ARG_INFO(0, cmp_function)
    1817                 : ZEND_END_ARG_INFO();
    1818                 : 
    1819                 : ZEND_BEGIN_ARG_INFO(arginfo_array_unserialize, 0)
    1820                 :         ZEND_ARG_INFO(0, serialized)
    1821                 : ZEND_END_ARG_INFO();
    1822                 : 
    1823                 : ZEND_BEGIN_ARG_INFO(arginfo_array_void, 0)
    1824                 : ZEND_END_ARG_INFO();
    1825                 : /* }}} */
    1826                 : 
    1827                 : static const zend_function_entry spl_funcs_ArrayObject[] = { /* {{{ */
    1828                 :         SPL_ME(Array, __construct,      arginfo_array___construct,      ZEND_ACC_PUBLIC)
    1829                 :         SPL_ME(Array, offsetExists,     arginfo_array_offsetGet,        ZEND_ACC_PUBLIC)
    1830                 :         SPL_ME(Array, offsetGet,        arginfo_array_offsetGet,        ZEND_ACC_PUBLIC)
    1831                 :         SPL_ME(Array, offsetSet,        arginfo_array_offsetSet,        ZEND_ACC_PUBLIC)
    1832                 :         SPL_ME(Array, offsetUnset,      arginfo_array_offsetGet,        ZEND_ACC_PUBLIC)
    1833                 :         SPL_ME(Array, append,           arginfo_array_append,           ZEND_ACC_PUBLIC)
    1834                 :         SPL_ME(Array, getArrayCopy,     arginfo_array_void,             ZEND_ACC_PUBLIC)
    1835                 :         SPL_ME(Array, count,            arginfo_array_void,             ZEND_ACC_PUBLIC)
    1836                 :         SPL_ME(Array, getFlags,         arginfo_array_void,             ZEND_ACC_PUBLIC)
    1837                 :         SPL_ME(Array, setFlags,         arginfo_array_setFlags,         ZEND_ACC_PUBLIC)
    1838                 :         SPL_ME(Array, asort,            arginfo_array_void,             ZEND_ACC_PUBLIC)
    1839                 :         SPL_ME(Array, ksort,            arginfo_array_void,             ZEND_ACC_PUBLIC)
    1840                 :         SPL_ME(Array, uasort,           arginfo_array_uXsort,           ZEND_ACC_PUBLIC)
    1841                 :         SPL_ME(Array, uksort,           arginfo_array_uXsort,           ZEND_ACC_PUBLIC)
    1842                 :         SPL_ME(Array, natsort,          arginfo_array_void,             ZEND_ACC_PUBLIC)
    1843                 :         SPL_ME(Array, natcasesort,      arginfo_array_void,             ZEND_ACC_PUBLIC)
    1844                 :         SPL_ME(Array, unserialize,      arginfo_array_unserialize,      ZEND_ACC_PUBLIC)
    1845                 :         SPL_ME(Array, serialize,        arginfo_array_void,             ZEND_ACC_PUBLIC)
    1846                 :         /* ArrayObject specific */
    1847                 :         SPL_ME(Array, getIterator,      arginfo_array_void,             ZEND_ACC_PUBLIC)
    1848                 :         SPL_ME(Array, exchangeArray,    arginfo_array_exchangeArray,    ZEND_ACC_PUBLIC)
    1849                 :         SPL_ME(Array, setIteratorClass, arginfo_array_setIteratorClass, ZEND_ACC_PUBLIC)
    1850                 :         SPL_ME(Array, getIteratorClass, arginfo_array_void,             ZEND_ACC_PUBLIC)
    1851                 :         {NULL, NULL, NULL}
    1852                 : }; /* }}} */
    1853                 : 
    1854                 : static const zend_function_entry spl_funcs_ArrayIterator[] = { /* {{{ */
    1855                 :         SPL_ME(Array, __construct,      arginfo_array___construct,      ZEND_ACC_PUBLIC)
    1856                 :         SPL_ME(Array, offsetExists,     arginfo_array_offsetGet,        ZEND_ACC_PUBLIC)
    1857                 :         SPL_ME(Array, offsetGet,        arginfo_array_offsetGet,        ZEND_ACC_PUBLIC)
    1858                 :         SPL_ME(Array, offsetSet,        arginfo_array_offsetSet,        ZEND_ACC_PUBLIC)
    1859                 :         SPL_ME(Array, offsetUnset,      arginfo_array_offsetGet,        ZEND_ACC_PUBLIC)
    1860                 :         SPL_ME(Array, append,           arginfo_array_append,           ZEND_ACC_PUBLIC)
    1861                 :         SPL_ME(Array, getArrayCopy,     arginfo_array_void,             ZEND_ACC_PUBLIC)
    1862                 :         SPL_ME(Array, count,            arginfo_array_void,             ZEND_ACC_PUBLIC)
    1863                 :         SPL_ME(Array, getFlags,         arginfo_array_void,             ZEND_ACC_PUBLIC)
    1864                 :         SPL_ME(Array, setFlags,         arginfo_array_setFlags,         ZEND_ACC_PUBLIC)
    1865                 :         SPL_ME(Array, asort,            arginfo_array_void,             ZEND_ACC_PUBLIC)
    1866                 :         SPL_ME(Array, ksort,            arginfo_array_void,             ZEND_ACC_PUBLIC)
    1867                 :         SPL_ME(Array, uasort,           arginfo_array_uXsort,           ZEND_ACC_PUBLIC)
    1868                 :         SPL_ME(Array, uksort,           arginfo_array_uXsort,           ZEND_ACC_PUBLIC)
    1869                 :         SPL_ME(Array, natsort,          arginfo_array_void,             ZEND_ACC_PUBLIC)
    1870                 :         SPL_ME(Array, natcasesort,      arginfo_array_void,             ZEND_ACC_PUBLIC)
    1871                 :         SPL_ME(Array, unserialize,     arginfo_array_unserialize,       ZEND_ACC_PUBLIC)
    1872                 :         SPL_ME(Array, serialize,        arginfo_array_void,             ZEND_ACC_PUBLIC)
    1873                 :         /* ArrayIterator specific */
    1874                 :         SPL_ME(Array, rewind,           arginfo_array_void,             ZEND_ACC_PUBLIC)
    1875                 :         SPL_ME(Array, current,          arginfo_array_void,             ZEND_ACC_PUBLIC)
    1876                 :         SPL_ME(Array, key,              arginfo_array_void,             ZEND_ACC_PUBLIC)
    1877                 :         SPL_ME(Array, next,             arginfo_array_void,             ZEND_ACC_PUBLIC)
    1878                 :         SPL_ME(Array, valid,            arginfo_array_void,             ZEND_ACC_PUBLIC)
    1879                 :         SPL_ME(Array, seek,             arginfo_array_seek,             ZEND_ACC_PUBLIC)
    1880                 :         {NULL, NULL, NULL}
    1881                 : }; /* }}} */
    1882                 : 
    1883                 : static const zend_function_entry spl_funcs_RecursiveArrayIterator[] = { /* {{{ */
    1884                 :         SPL_ME(Array, hasChildren,   arginfo_array_void, ZEND_ACC_PUBLIC)
    1885                 :         SPL_ME(Array, getChildren,   arginfo_array_void, ZEND_ACC_PUBLIC)
    1886                 :         {NULL, NULL, NULL}
    1887                 : }; /* }}} */
    1888                 : 
    1889                 : /* {{{ PHP_MINIT_FUNCTION(spl_array) */
    1890                 : PHP_MINIT_FUNCTION(spl_array)
    1891           17007 : {
    1892           17007 :         REGISTER_SPL_STD_CLASS_EX(ArrayObject, spl_array_object_new, spl_funcs_ArrayObject);
    1893           17007 :         REGISTER_SPL_IMPLEMENTS(ArrayObject, Aggregate);
    1894           17007 :         REGISTER_SPL_IMPLEMENTS(ArrayObject, ArrayAccess);
    1895           17007 :         REGISTER_SPL_IMPLEMENTS(ArrayObject, Serializable);
    1896           17007 :         spl_ce_ArrayObject->serialize   = spl_array_serialize;
    1897           17007 :         spl_ce_ArrayObject->unserialize = spl_array_unserialize;
    1898           17007 :         memcpy(&spl_handler_ArrayObject, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
    1899                 : 
    1900           17007 :         spl_handler_ArrayObject.clone_obj = spl_array_object_clone;
    1901           17007 :         spl_handler_ArrayObject.read_dimension = spl_array_read_dimension;
    1902           17007 :         spl_handler_ArrayObject.write_dimension = spl_array_write_dimension;
    1903           17007 :         spl_handler_ArrayObject.unset_dimension = spl_array_unset_dimension;
    1904           17007 :         spl_handler_ArrayObject.has_dimension = spl_array_has_dimension;
    1905           17007 :         spl_handler_ArrayObject.count_elements = spl_array_object_count_elements;
    1906                 : 
    1907           17007 :         spl_handler_ArrayObject.get_properties = spl_array_get_properties;
    1908           17007 :         spl_handler_ArrayObject.get_debug_info = spl_array_get_debug_info;
    1909           17007 :         spl_handler_ArrayObject.read_property = spl_array_read_property;
    1910           17007 :         spl_handler_ArrayObject.write_property = spl_array_write_property;
    1911           17007 :         spl_handler_ArrayObject.get_property_ptr_ptr = spl_array_get_property_ptr_ptr;
    1912           17007 :         spl_handler_ArrayObject.has_property = spl_array_has_property;
    1913           17007 :         spl_handler_ArrayObject.unset_property = spl_array_unset_property;
    1914                 : 
    1915           17007 :         REGISTER_SPL_STD_CLASS_EX(ArrayIterator, spl_array_object_new, spl_funcs_ArrayIterator);
    1916           17007 :         REGISTER_SPL_IMPLEMENTS(ArrayIterator, Iterator);
    1917           17007 :         REGISTER_SPL_IMPLEMENTS(ArrayIterator, ArrayAccess);
    1918           17007 :         REGISTER_SPL_IMPLEMENTS(ArrayIterator, SeekableIterator);
    1919           17007 :         REGISTER_SPL_IMPLEMENTS(ArrayIterator, Serializable);
    1920           17007 :         spl_ce_ArrayIterator->serialize   = spl_array_serialize;
    1921           17007 :         spl_ce_ArrayIterator->unserialize = spl_array_unserialize;
    1922           17007 :         memcpy(&spl_handler_ArrayIterator, &spl_handler_ArrayObject, sizeof(zend_object_handlers));
    1923           17007 :         spl_ce_ArrayIterator->get_iterator = spl_array_get_iterator;
    1924                 :         
    1925           17007 :         REGISTER_SPL_SUB_CLASS_EX(RecursiveArrayIterator, ArrayIterator, spl_array_object_new, spl_funcs_RecursiveArrayIterator);
    1926           17007 :         REGISTER_SPL_IMPLEMENTS(RecursiveArrayIterator, RecursiveIterator);
    1927           17007 :         spl_ce_RecursiveArrayIterator->get_iterator = spl_array_get_iterator;
    1928                 : 
    1929           17007 :         REGISTER_SPL_IMPLEMENTS(ArrayObject, Countable);
    1930           17007 :         REGISTER_SPL_IMPLEMENTS(ArrayIterator, Countable);
    1931                 : 
    1932           17007 :         REGISTER_SPL_CLASS_CONST_LONG(ArrayObject,   "STD_PROP_LIST",    SPL_ARRAY_STD_PROP_LIST);
    1933           17007 :         REGISTER_SPL_CLASS_CONST_LONG(ArrayObject,   "ARRAY_AS_PROPS",   SPL_ARRAY_ARRAY_AS_PROPS);
    1934                 : 
    1935           17007 :         REGISTER_SPL_CLASS_CONST_LONG(ArrayIterator, "STD_PROP_LIST",    SPL_ARRAY_STD_PROP_LIST);
    1936           17007 :         REGISTER_SPL_CLASS_CONST_LONG(ArrayIterator, "ARRAY_AS_PROPS",   SPL_ARRAY_ARRAY_AS_PROPS);
    1937                 : 
    1938           17007 :         REGISTER_SPL_CLASS_CONST_LONG(RecursiveArrayIterator, "CHILD_ARRAYS_ONLY", SPL_ARRAY_CHILD_ARRAYS_ONLY);
    1939                 : 
    1940           17007 :         return SUCCESS;
    1941                 : }
    1942                 : /* }}} */
    1943                 : 
    1944                 : /*
    1945                 :  * Local variables:
    1946                 :  * tab-width: 4
    1947                 :  * c-basic-offset: 4
    1948                 :  * End:
    1949                 :  * vim600: fdm=marker
    1950                 :  * vim: noet sw=4 ts=4
    1951                 :  */

Generated by: LTP GCOV extension version 1.5

Generated at Mon, 23 Nov 2009 17:39:39 +0000 (34 hours ago)

Copyright © 2005-2009 The PHP Group
All rights reserved.