Back to index

php5  5.3.10
com_iterator.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Author: Wez Furlong <wez@thebrainroom.com>                           |
00016    +----------------------------------------------------------------------+
00017  */
00018 
00019 /* $Id: com_iterator.c 321634 2012-01-01 13:15:04Z felipe $ */
00020 
00021 #ifdef HAVE_CONFIG_H
00022 #include "config.h"
00023 #endif
00024 
00025 #include "php.h"
00026 #include "php_ini.h"
00027 #include "ext/standard/info.h"
00028 #include "php_com_dotnet.h"
00029 #include "php_com_dotnet_internal.h"
00030 #include "Zend/zend_exceptions.h"
00031 
00032 struct php_com_iterator {
00033        zend_object_iterator iter;
00034        IEnumVARIANT *ev;
00035        ulong key;
00036        VARIANT v; /* cached element */
00037        int code_page;
00038        VARIANT safe_array;
00039        VARTYPE sa_type;
00040        LONG sa_max;
00041        zval *zdata;
00042 };
00043 
00044 static void com_iter_dtor(zend_object_iterator *iter TSRMLS_DC)
00045 {
00046        struct php_com_iterator *I = (struct php_com_iterator*)iter->data;
00047        
00048        if (I->ev) {
00049               IEnumVARIANT_Release(I->ev);
00050        }
00051        VariantClear(&I->v);
00052        VariantClear(&I->safe_array);
00053        if (I->zdata) {
00054               zval_ptr_dtor((zval**)&I->zdata);
00055        }
00056        efree(I);
00057 }
00058 
00059 static int com_iter_valid(zend_object_iterator *iter TSRMLS_DC)
00060 {
00061        struct php_com_iterator *I = (struct php_com_iterator*)iter->data;
00062 
00063        if (I->zdata) {
00064               return SUCCESS;
00065        }
00066 
00067        return FAILURE;
00068 }
00069 
00070 static void com_iter_get_data(zend_object_iterator *iter, zval ***data TSRMLS_DC)
00071 {
00072        struct php_com_iterator *I = (struct php_com_iterator*)iter->data;
00073 
00074        *data = &I->zdata;
00075 }
00076 
00077 static int com_iter_get_key(zend_object_iterator *iter, char **str_key, uint *str_key_len,
00078        ulong *int_key TSRMLS_DC)
00079 {
00080        struct php_com_iterator *I = (struct php_com_iterator*)iter->data;
00081 
00082        if (I->key == (ulong)-1) {
00083               return HASH_KEY_NON_EXISTANT;
00084        }
00085        *int_key = I->key;
00086        return HASH_KEY_IS_LONG;
00087 }
00088 
00089 static int com_iter_move_forwards(zend_object_iterator *iter TSRMLS_DC)
00090 {
00091        struct php_com_iterator *I = (struct php_com_iterator*)iter->data;
00092        unsigned long n_fetched;
00093        zval *ptr;
00094 
00095        /* release current cached element */
00096        VariantClear(&I->v);
00097 
00098        if (I->zdata) {
00099               zval_ptr_dtor((zval**)&I->zdata);
00100               I->zdata = NULL;
00101        }
00102 
00103        if (I->ev) {
00104               /* Get the next element */
00105               if (SUCCEEDED(IEnumVARIANT_Next(I->ev, 1, &I->v, &n_fetched)) && n_fetched > 0) {
00106                      I->key++;
00107               } else {
00108                      /* indicate that there are no more items */
00109                      I->key = (ulong)-1;
00110                      return FAILURE;
00111               }
00112        } else {
00113               /* safe array */
00114               if (I->key >= (ULONG) I->sa_max) {
00115                      I->key = (ulong)-1;
00116                      return FAILURE;
00117               }
00118               I->key++;
00119               if (php_com_safearray_get_elem(&I->safe_array, &I->v, (LONG)I->key TSRMLS_CC) == 0) {
00120                      I->key = (ulong)-1;
00121                      return FAILURE;
00122               }
00123        }
00124 
00125        MAKE_STD_ZVAL(ptr);
00126        php_com_zval_from_variant(ptr, &I->v, I->code_page TSRMLS_CC);
00127        /* php_com_wrap_variant(ptr, &I->v, I->code_page TSRMLS_CC); */
00128        I->zdata = ptr;
00129        return SUCCESS;
00130 }
00131 
00132 
00133 static zend_object_iterator_funcs com_iter_funcs = {
00134        com_iter_dtor,
00135        com_iter_valid,
00136        com_iter_get_data,
00137        com_iter_get_key,
00138        com_iter_move_forwards,
00139        NULL
00140 };
00141 
00142 zend_object_iterator *php_com_iter_get(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC)
00143 {
00144        php_com_dotnet_object *obj;
00145        struct php_com_iterator *I;
00146        IEnumVARIANT *iev = NULL;
00147        DISPPARAMS dp;
00148        VARIANT v;
00149        unsigned long n_fetched;
00150        zval *ptr;
00151 
00152        if (by_ref) {
00153               zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
00154        }
00155 
00156        obj = CDNO_FETCH(object);
00157 
00158        if (V_VT(&obj->v) != VT_DISPATCH && !V_ISARRAY(&obj->v)) {
00159               php_error_docref(NULL TSRMLS_CC, E_WARNING, "variant is not an object or array VT=%d", V_VT(&obj->v));
00160               return NULL;
00161        }
00162 
00163        memset(&dp, 0, sizeof(dp));
00164        VariantInit(&v);     
00165 
00166        I = (struct php_com_iterator*)ecalloc(1, sizeof(*I));
00167        I->iter.funcs = &com_iter_funcs;
00168        I->iter.data = I;
00169        I->code_page = obj->code_page;
00170        I->zdata = NULL;
00171        VariantInit(&I->safe_array);
00172        VariantInit(&I->v);
00173 
00174        if (V_ISARRAY(&obj->v)) {
00175               LONG bound;
00176               UINT dims;
00177        
00178               dims = SafeArrayGetDim(V_ARRAY(&obj->v));
00179 
00180               if (dims != 1) {
00181                      php_error_docref(NULL TSRMLS_CC, E_WARNING,
00182                                "Can only handle single dimension variant arrays (this array has %d)", dims);
00183                      goto fail;
00184               }
00185               
00186               /* same semantics as foreach on a PHP array;
00187                * make a copy and enumerate that copy */
00188               VariantCopy(&I->safe_array, &obj->v);
00189 
00190               /* determine the key value for the array */
00191               SafeArrayGetLBound(V_ARRAY(&I->safe_array), 1, &bound);
00192               SafeArrayGetUBound(V_ARRAY(&I->safe_array), 1, &I->sa_max);
00193 
00194               /* pre-fetch the element */
00195               if (php_com_safearray_get_elem(&I->safe_array, &I->v, bound TSRMLS_CC)) {
00196                      I->key = bound;
00197                      MAKE_STD_ZVAL(ptr);
00198                      php_com_zval_from_variant(ptr, &I->v, I->code_page TSRMLS_CC);
00199                      I->zdata = ptr;
00200               } else {
00201                      I->key = (ulong)-1;
00202               }
00203               
00204        } else {
00205               /* can we enumerate it? */
00206               if (FAILED(IDispatch_Invoke(V_DISPATCH(&obj->v), DISPID_NEWENUM,
00207                                           &IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD|DISPATCH_PROPERTYGET,
00208                                           &dp, &v, NULL, NULL))) {
00209                      goto fail;
00210               }
00211 
00212               /* get something useful out of it */
00213               if (V_VT(&v) == VT_UNKNOWN) {
00214                      IUnknown_QueryInterface(V_UNKNOWN(&v), &IID_IEnumVARIANT, (void**)&iev);
00215               } else if (V_VT(&v) == VT_DISPATCH) {
00216                      IDispatch_QueryInterface(V_DISPATCH(&v), &IID_IEnumVARIANT, (void**)&iev);
00217               }
00218 
00219               VariantClear(&v);
00220 
00221               if (iev == NULL) {
00222                      goto fail;
00223               }
00224        
00225               I->ev = iev;
00226 
00227               /* Get the first element now */
00228               if (SUCCEEDED(IEnumVARIANT_Next(I->ev, 1, &I->v, &n_fetched)) && n_fetched > 0) {
00229                      /* indicate that we have element 0 */
00230                      I->key = 0;
00231                      MAKE_STD_ZVAL(ptr);
00232                      php_com_zval_from_variant(ptr, &I->v, I->code_page TSRMLS_CC);
00233                      I->zdata = ptr;
00234               } else {
00235                      /* indicate that there are no more items */
00236                      I->key = (ulong)-1;
00237               }
00238        }
00239 
00240        return &I->iter;
00241 
00242 fail:
00243        if (I) {
00244               VariantClear(&I->safe_array);
00245               VariantClear(&I->v);
00246               efree(I);
00247        }
00248        return NULL;
00249 }
00250