root/ext/com_dotnet/com_iterator.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. com_iter_dtor
  2. com_iter_valid
  3. com_iter_get_data
  4. com_iter_get_key
  5. com_iter_move_forwards
  6. php_com_iter_get

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 7                                                        |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1997-2016 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$ */
  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         zend_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)
  45 {
  46         struct php_com_iterator *I = (struct php_com_iterator*)Z_PTR(iter->data);
  47 
  48         if (I->ev) {
  49                 IEnumVARIANT_Release(I->ev);
  50         }
  51         VariantClear(&I->v);
  52         VariantClear(&I->safe_array);
  53         zval_ptr_dtor(&I->zdata);
  54 }
  55 
  56 static int com_iter_valid(zend_object_iterator *iter)
  57 {
  58         struct php_com_iterator *I = (struct php_com_iterator*)Z_PTR(iter->data);
  59 
  60         if (Z_TYPE(I->zdata) != IS_UNDEF) {
  61                 return SUCCESS;
  62         }
  63 
  64         return FAILURE;
  65 }
  66 
  67 static zval* com_iter_get_data(zend_object_iterator *iter)
  68 {
  69         struct php_com_iterator *I = (struct php_com_iterator*)Z_PTR(iter->data);
  70 
  71         return &I->zdata;
  72 }
  73 
  74 static void com_iter_get_key(zend_object_iterator *iter, zval *key)
  75 {
  76         struct php_com_iterator *I = (struct php_com_iterator*)Z_PTR(iter->data);
  77 
  78         if (I->key == (zend_ulong)-1) {
  79                 ZVAL_NULL(key);
  80         } else {
  81                 ZVAL_LONG(key, I->key);
  82         }
  83 }
  84 
  85 static int com_iter_move_forwards(zend_object_iterator *iter)
  86 {
  87         struct php_com_iterator *I = (struct php_com_iterator*)Z_PTR(iter->data);
  88         unsigned long n_fetched;
  89         zval ptr;
  90 
  91         /* release current cached element */
  92         VariantClear(&I->v);
  93 
  94         if (Z_TYPE(I->zdata) != IS_UNDEF) {
  95                 zval_ptr_dtor(&I->zdata);
  96                 ZVAL_UNDEF(&I->zdata);
  97         }
  98 
  99         if (I->ev) {
 100                 /* Get the next element */
 101                 if (SUCCEEDED(IEnumVARIANT_Next(I->ev, 1, &I->v, &n_fetched)) && n_fetched > 0) {
 102                         I->key++;
 103                 } else {
 104                         /* indicate that there are no more items */
 105                         I->key = (ulong)-1;
 106                         return FAILURE;
 107                 }
 108         } else {
 109                 /* safe array */
 110                 if (I->key >= (ULONG) I->sa_max) {
 111                         I->key = (ulong)-1;
 112                         return FAILURE;
 113                 }
 114                 I->key++;
 115                 if (php_com_safearray_get_elem(&I->safe_array, &I->v, (LONG)I->key) == 0) {
 116                         I->key = (ulong)-1;
 117                         return FAILURE;
 118                 }
 119         }
 120 
 121         ZVAL_NULL(&ptr);
 122         php_com_zval_from_variant(&ptr, &I->v, I->code_page);
 123         /* php_com_wrap_variant(ptr, &I->v, I->code_page); */
 124         ZVAL_COPY_VALUE(&I->zdata, &ptr);
 125         return SUCCESS;
 126 }
 127 
 128 
 129 static zend_object_iterator_funcs com_iter_funcs = {
 130         com_iter_dtor,
 131         com_iter_valid,
 132         com_iter_get_data,
 133         com_iter_get_key,
 134         com_iter_move_forwards,
 135         NULL
 136 };
 137 
 138 zend_object_iterator *php_com_iter_get(zend_class_entry *ce, zval *object, int by_ref)
 139 {
 140         php_com_dotnet_object *obj;
 141         struct php_com_iterator *I;
 142         IEnumVARIANT *iev = NULL;
 143         DISPPARAMS dp;
 144         VARIANT v;
 145         unsigned long n_fetched;
 146         zval ptr;
 147 
 148         if (by_ref) {
 149                 zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
 150         }
 151 
 152         obj = CDNO_FETCH(object);
 153 
 154         if (V_VT(&obj->v) != VT_DISPATCH && !V_ISARRAY(&obj->v)) {
 155                 php_error_docref(NULL, E_WARNING, "variant is not an object or array VT=%d", V_VT(&obj->v));
 156                 return NULL;
 157         }
 158 
 159         memset(&dp, 0, sizeof(dp));
 160         VariantInit(&v);
 161 
 162         I = (struct php_com_iterator*)ecalloc(1, sizeof(*I));
 163         zend_iterator_init(&I->iter);
 164         I->iter.funcs = &com_iter_funcs;
 165         Z_PTR(I->iter.data) = I;
 166         I->code_page = obj->code_page;
 167         ZVAL_UNDEF(&I->zdata);
 168         VariantInit(&I->safe_array);
 169         VariantInit(&I->v);
 170 
 171         if (V_ISARRAY(&obj->v)) {
 172                 LONG bound;
 173                 UINT dims;
 174 
 175                 dims = SafeArrayGetDim(V_ARRAY(&obj->v));
 176 
 177                 if (dims != 1) {
 178                         php_error_docref(NULL, E_WARNING,
 179                                    "Can only handle single dimension variant arrays (this array has %d)", dims);
 180                         goto fail;
 181                 }
 182 
 183                 /* same semantics as foreach on a PHP array;
 184                  * make a copy and enumerate that copy */
 185                 VariantCopy(&I->safe_array, &obj->v);
 186 
 187                 /* determine the key value for the array */
 188                 SafeArrayGetLBound(V_ARRAY(&I->safe_array), 1, &bound);
 189                 SafeArrayGetUBound(V_ARRAY(&I->safe_array), 1, &I->sa_max);
 190 
 191                 /* pre-fetch the element */
 192                 if (php_com_safearray_get_elem(&I->safe_array, &I->v, bound)) {
 193                         I->key = bound;
 194                         ZVAL_NULL(&ptr);
 195                         php_com_zval_from_variant(&ptr, &I->v, I->code_page);
 196                         ZVAL_COPY_VALUE(&I->zdata, &ptr);
 197                 } else {
 198                         I->key = (ulong)-1;
 199                 }
 200 
 201         } else {
 202                 /* can we enumerate it? */
 203                 if (FAILED(IDispatch_Invoke(V_DISPATCH(&obj->v), DISPID_NEWENUM,
 204                                                 &IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD|DISPATCH_PROPERTYGET,
 205                                                 &dp, &v, NULL, NULL))) {
 206                         goto fail;
 207                 }
 208 
 209                 /* get something useful out of it */
 210                 if (V_VT(&v) == VT_UNKNOWN) {
 211                         IUnknown_QueryInterface(V_UNKNOWN(&v), &IID_IEnumVARIANT, (void**)&iev);
 212                 } else if (V_VT(&v) == VT_DISPATCH) {
 213                         IDispatch_QueryInterface(V_DISPATCH(&v), &IID_IEnumVARIANT, (void**)&iev);
 214                 }
 215 
 216                 VariantClear(&v);
 217 
 218                 if (iev == NULL) {
 219                         goto fail;
 220                 }
 221 
 222                 I->ev = iev;
 223 
 224                 /* Get the first element now */
 225                 if (SUCCEEDED(IEnumVARIANT_Next(I->ev, 1, &I->v, &n_fetched)) && n_fetched > 0) {
 226                         /* indicate that we have element 0 */
 227                         I->key = 0;
 228                         ZVAL_NULL(&ptr);
 229                         php_com_zval_from_variant(&ptr, &I->v, I->code_page);
 230                         ZVAL_COPY_VALUE(&I->zdata, &ptr);
 231                 } else {
 232                         /* indicate that there are no more items */
 233                         I->key = (ulong)-1;
 234                 }
 235         }
 236 
 237         return &I->iter;
 238 
 239 fail:
 240         if (I) {
 241                 VariantClear(&I->safe_array);
 242                 VariantClear(&I->v);
 243                 efree(I);
 244         }
 245         return NULL;
 246 }
 247 

/* [<][>][^][v][top][bottom][index][help] */