![]() ![]() | ![]() |
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | PHP Version 5 |
4: +----------------------------------------------------------------------+
1.1.1.3 ! misho 5: | Copyright (c) 1997-2013 The PHP Group |
1.1 misho 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:
1.1.1.2 misho 19: /* $Id$ */
1.1 misho 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: