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

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