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-21 Instrumented lines: 883
Code covered: 87.5 % Executed lines: 773
Legend: not executed executed

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

Generated by: LTP GCOV extension version 1.5

Generated at Sat, 21 Nov 2009 12:27:09 +0000 (3 days ago)

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