Annotation of embedaddon/php/ext/com_dotnet/com_iterator.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | PHP Version 5                                                        |
                      4:    +----------------------------------------------------------------------+
                      5:    | Copyright (c) 1997-2012 The PHP Group                                |
                      6:    +----------------------------------------------------------------------+
                      7:    | This source file is subject to version 3.01 of the PHP license,      |
                      8:    | that is bundled with this package in the file LICENSE, and is        |
                      9:    | available through the world-wide-web at the following url:           |
                     10:    | http://www.php.net/license/3_01.txt                                  |
                     11:    | If you did not receive a copy of the PHP license and are unable to   |
                     12:    | obtain it through the world-wide-web, please send a note to          |
                     13:    | license@php.net so we can mail you a copy immediately.               |
                     14:    +----------------------------------------------------------------------+
                     15:    | Author: Wez Furlong <wez@thebrainroom.com>                           |
                     16:    +----------------------------------------------------------------------+
                     17:  */
                     18: 
                     19: /* $Id: com_iterator.c 321634 2012-01-01 13:15:04Z felipe $ */
                     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 "php_com_dotnet.h"
                     29: #include "php_com_dotnet_internal.h"
                     30: #include "Zend/zend_exceptions.h"
                     31: 
                     32: struct php_com_iterator {
                     33:        zend_object_iterator iter;
                     34:        IEnumVARIANT *ev;
                     35:        ulong key;
                     36:        VARIANT v; /* cached element */
                     37:        int code_page;
                     38:        VARIANT safe_array;
                     39:        VARTYPE sa_type;
                     40:        LONG sa_max;
                     41:        zval *zdata;
                     42: };
                     43: 
                     44: static void com_iter_dtor(zend_object_iterator *iter TSRMLS_DC)
                     45: {
                     46:        struct php_com_iterator *I = (struct php_com_iterator*)iter->data;
                     47:        
                     48:        if (I->ev) {
                     49:                IEnumVARIANT_Release(I->ev);
                     50:        }
                     51:        VariantClear(&I->v);
                     52:        VariantClear(&I->safe_array);
                     53:        if (I->zdata) {
                     54:                zval_ptr_dtor((zval**)&I->zdata);
                     55:        }
                     56:        efree(I);
                     57: }
                     58: 
                     59: static int com_iter_valid(zend_object_iterator *iter TSRMLS_DC)
                     60: {
                     61:        struct php_com_iterator *I = (struct php_com_iterator*)iter->data;
                     62: 
                     63:        if (I->zdata) {
                     64:                return SUCCESS;
                     65:        }
                     66: 
                     67:        return FAILURE;
                     68: }
                     69: 
                     70: static void com_iter_get_data(zend_object_iterator *iter, zval ***data TSRMLS_DC)
                     71: {
                     72:        struct php_com_iterator *I = (struct php_com_iterator*)iter->data;
                     73: 
                     74:        *data = &I->zdata;
                     75: }
                     76: 
                     77: static int com_iter_get_key(zend_object_iterator *iter, char **str_key, uint *str_key_len,
                     78:        ulong *int_key TSRMLS_DC)
                     79: {
                     80:        struct php_com_iterator *I = (struct php_com_iterator*)iter->data;
                     81: 
                     82:        if (I->key == (ulong)-1) {
                     83:                return HASH_KEY_NON_EXISTANT;
                     84:        }
                     85:        *int_key = I->key;
                     86:        return HASH_KEY_IS_LONG;
                     87: }
                     88: 
                     89: static int com_iter_move_forwards(zend_object_iterator *iter TSRMLS_DC)
                     90: {
                     91:        struct php_com_iterator *I = (struct php_com_iterator*)iter->data;
                     92:        unsigned long n_fetched;
                     93:        zval *ptr;
                     94: 
                     95:        /* release current cached element */
                     96:        VariantClear(&I->v);
                     97: 
                     98:        if (I->zdata) {
                     99:                zval_ptr_dtor((zval**)&I->zdata);
                    100:                I->zdata = NULL;
                    101:        }
                    102: 
                    103:        if (I->ev) {
                    104:                /* Get the next element */
                    105:                if (SUCCEEDED(IEnumVARIANT_Next(I->ev, 1, &I->v, &n_fetched)) && n_fetched > 0) {
                    106:                        I->key++;
                    107:                } else {
                    108:                        /* indicate that there are no more items */
                    109:                        I->key = (ulong)-1;
                    110:                        return FAILURE;
                    111:                }
                    112:        } else {
                    113:                /* safe array */
                    114:                if (I->key >= (ULONG) I->sa_max) {
                    115:                        I->key = (ulong)-1;
                    116:                        return FAILURE;
                    117:                }
                    118:                I->key++;
                    119:                if (php_com_safearray_get_elem(&I->safe_array, &I->v, (LONG)I->key TSRMLS_CC) == 0) {
                    120:                        I->key = (ulong)-1;
                    121:                        return FAILURE;
                    122:                }
                    123:        }
                    124: 
                    125:        MAKE_STD_ZVAL(ptr);
                    126:        php_com_zval_from_variant(ptr, &I->v, I->code_page TSRMLS_CC);
                    127:        /* php_com_wrap_variant(ptr, &I->v, I->code_page TSRMLS_CC); */
                    128:        I->zdata = ptr;
                    129:        return SUCCESS;
                    130: }
                    131: 
                    132: 
                    133: static zend_object_iterator_funcs com_iter_funcs = {
                    134:        com_iter_dtor,
                    135:        com_iter_valid,
                    136:        com_iter_get_data,
                    137:        com_iter_get_key,
                    138:        com_iter_move_forwards,
                    139:        NULL
                    140: };
                    141: 
                    142: zend_object_iterator *php_com_iter_get(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC)
                    143: {
                    144:        php_com_dotnet_object *obj;
                    145:        struct php_com_iterator *I;
                    146:        IEnumVARIANT *iev = NULL;
                    147:        DISPPARAMS dp;
                    148:        VARIANT v;
                    149:        unsigned long n_fetched;
                    150:        zval *ptr;
                    151: 
                    152:        if (by_ref) {
                    153:                zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
                    154:        }
                    155: 
                    156:        obj = CDNO_FETCH(object);
                    157: 
                    158:        if (V_VT(&obj->v) != VT_DISPATCH && !V_ISARRAY(&obj->v)) {
                    159:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "variant is not an object or array VT=%d", V_VT(&obj->v));
                    160:                return NULL;
                    161:        }
                    162: 
                    163:        memset(&dp, 0, sizeof(dp));
                    164:        VariantInit(&v);        
                    165: 
                    166:        I = (struct php_com_iterator*)ecalloc(1, sizeof(*I));
                    167:        I->iter.funcs = &com_iter_funcs;
                    168:        I->iter.data = I;
                    169:        I->code_page = obj->code_page;
                    170:        I->zdata = NULL;
                    171:        VariantInit(&I->safe_array);
                    172:        VariantInit(&I->v);
                    173: 
                    174:        if (V_ISARRAY(&obj->v)) {
                    175:                LONG bound;
                    176:                UINT dims;
                    177:        
                    178:                dims = SafeArrayGetDim(V_ARRAY(&obj->v));
                    179: 
                    180:                if (dims != 1) {
                    181:                        php_error_docref(NULL TSRMLS_CC, E_WARNING,
                    182:                                   "Can only handle single dimension variant arrays (this array has %d)", dims);
                    183:                        goto fail;
                    184:                }
                    185:                
                    186:                /* same semantics as foreach on a PHP array;
                    187:                 * make a copy and enumerate that copy */
                    188:                VariantCopy(&I->safe_array, &obj->v);
                    189: 
                    190:                /* determine the key value for the array */
                    191:                SafeArrayGetLBound(V_ARRAY(&I->safe_array), 1, &bound);
                    192:                SafeArrayGetUBound(V_ARRAY(&I->safe_array), 1, &I->sa_max);
                    193: 
                    194:                /* pre-fetch the element */
                    195:                if (php_com_safearray_get_elem(&I->safe_array, &I->v, bound TSRMLS_CC)) {
                    196:                        I->key = bound;
                    197:                        MAKE_STD_ZVAL(ptr);
                    198:                        php_com_zval_from_variant(ptr, &I->v, I->code_page TSRMLS_CC);
                    199:                        I->zdata = ptr;
                    200:                } else {
                    201:                        I->key = (ulong)-1;
                    202:                }
                    203:                
                    204:        } else {
                    205:                /* can we enumerate it? */
                    206:                if (FAILED(IDispatch_Invoke(V_DISPATCH(&obj->v), DISPID_NEWENUM,
                    207:                                                &IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD|DISPATCH_PROPERTYGET,
                    208:                                                &dp, &v, NULL, NULL))) {
                    209:                        goto fail;
                    210:                }
                    211: 
                    212:                /* get something useful out of it */
                    213:                if (V_VT(&v) == VT_UNKNOWN) {
                    214:                        IUnknown_QueryInterface(V_UNKNOWN(&v), &IID_IEnumVARIANT, (void**)&iev);
                    215:                } else if (V_VT(&v) == VT_DISPATCH) {
                    216:                        IDispatch_QueryInterface(V_DISPATCH(&v), &IID_IEnumVARIANT, (void**)&iev);
                    217:                }
                    218: 
                    219:                VariantClear(&v);
                    220: 
                    221:                if (iev == NULL) {
                    222:                        goto fail;
                    223:                }
                    224:        
                    225:                I->ev = iev;
                    226: 
                    227:                /* Get the first element now */
                    228:                if (SUCCEEDED(IEnumVARIANT_Next(I->ev, 1, &I->v, &n_fetched)) && n_fetched > 0) {
                    229:                        /* indicate that we have element 0 */
                    230:                        I->key = 0;
                    231:                        MAKE_STD_ZVAL(ptr);
                    232:                        php_com_zval_from_variant(ptr, &I->v, I->code_page TSRMLS_CC);
                    233:                        I->zdata = ptr;
                    234:                } else {
                    235:                        /* indicate that there are no more items */
                    236:                        I->key = (ulong)-1;
                    237:                }
                    238:        }
                    239: 
                    240:        return &I->iter;
                    241: 
                    242: fail:
                    243:        if (I) {
                    244:                VariantClear(&I->safe_array);
                    245:                VariantClear(&I->v);
                    246:                efree(I);
                    247:        }
                    248:        return NULL;
                    249: }
                    250: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>