This source file includes following definitions.
- clone_indices
- saproxy_property_read
- saproxy_property_write
- saproxy_read_dimension
- saproxy_write_dimension
- saproxy_object_set
- saproxy_object_get
- saproxy_property_exists
- saproxy_dimension_exists
- saproxy_property_delete
- saproxy_dimension_delete
- saproxy_properties_get
- saproxy_method_get
- saproxy_call_method
- saproxy_constructor_get
- saproxy_class_name_get
- saproxy_objects_compare
- saproxy_object_cast
- saproxy_count_elements
- saproxy_free_storage
- saproxy_clone
- php_com_saproxy_create
- saproxy_iter_dtor
- saproxy_iter_valid
- saproxy_iter_get_data
- saproxy_iter_get_key
- saproxy_iter_move_forwards
- php_com_saproxy_iter_get
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #include "php.h"
33 #include "php_ini.h"
34 #include "ext/standard/info.h"
35 #include "php_com_dotnet.h"
36 #include "php_com_dotnet_internal.h"
37 #include "Zend/zend_exceptions.h"
38
39 typedef struct {
40 zend_object std;
41
42 zval *zobj;
43 php_com_dotnet_object *obj;
44
45
46 LONG dimensions;
47
48
49 zval *indices;
50
51 } php_com_saproxy;
52
53 typedef struct {
54 zend_object_iterator iter;
55 zval proxy_obj;
56 zval data;
57 php_com_saproxy *proxy;
58 LONG key;
59 LONG imin, imax;
60 LONG *indices;
61 } php_com_saproxy_iter;
62
63 #define SA_FETCH(zv) (php_com_saproxy*)Z_OBJ_P(zv)
64
65 static inline void clone_indices(php_com_saproxy *dest, php_com_saproxy *src, int ndims)
66 {
67 int i;
68
69 for (i = 0; i < ndims; i++) {
70 ZVAL_DUP(&dest->indices[i], &src->indices[i]);
71 }
72 }
73
74 static zval *saproxy_property_read(zval *object, zval *member, int type, void **cahce_slot, zval *rv)
75 {
76 ZVAL_NULL(rv);
77
78 php_com_throw_exception(E_INVALIDARG, "safearray has no properties");
79
80 return rv;
81 }
82
83 static void saproxy_property_write(zval *object, zval *member, zval *value, void **cache_slot)
84 {
85 php_com_throw_exception(E_INVALIDARG, "safearray has no properties");
86 }
87
88 static zval *saproxy_read_dimension(zval *object, zval *offset, int type, zval *rv)
89 {
90 php_com_saproxy *proxy = SA_FETCH(object);
91 UINT dims, i;
92 SAFEARRAY *sa;
93 LONG ubound, lbound;
94 HRESULT res;
95
96 ZVAL_NULL(rv);
97
98 if (V_VT(&proxy->obj->v) == VT_DISPATCH) {
99 VARIANT v;
100 zval *args;
101
102
103
104
105 args = safe_emalloc(proxy->dimensions + 1, sizeof(zval), 0);
106
107 for (i = 1; i < (UINT) proxy->dimensions; i++) {
108 args[i-1] = proxy->indices[i];
109 }
110 ZVAL_COPY_VALUE(&args[i-1], offset);
111
112 convert_to_string(&proxy->indices[0]);
113 VariantInit(&v);
114
115 res = php_com_do_invoke(proxy->obj, Z_STRVAL(proxy->indices[0]),
116 Z_STRLEN(proxy->indices[0]), DISPATCH_METHOD|DISPATCH_PROPERTYGET, &v,
117 proxy->dimensions, args, 0);
118
119 if (res == SUCCESS) {
120 php_com_zval_from_variant(rv, &v, proxy->obj->code_page);
121 VariantClear(&v);
122 } else if (res == DISP_E_BADPARAMCOUNT) {
123
124 php_com_saproxy_create(object, rv, offset);
125 }
126
127 return rv;
128
129 } else if (!V_ISARRAY(&proxy->obj->v)) {
130 php_com_throw_exception(E_INVALIDARG, "invalid read from com proxy object");
131 return rv;
132 }
133
134
135
136
137 convert_to_long(offset);
138
139 sa = V_ARRAY(&proxy->obj->v);
140 dims = SafeArrayGetDim(sa);
141
142 if ((UINT) proxy->dimensions >= dims) {
143
144 php_com_throw_exception(E_INVALIDARG, "too many dimensions!");
145 return rv;
146 }
147
148
149 SafeArrayGetLBound(sa, proxy->dimensions, &lbound);
150 SafeArrayGetUBound(sa, proxy->dimensions, &ubound);
151
152 if (Z_LVAL_P(offset) < lbound || Z_LVAL_P(offset) > ubound) {
153 php_com_throw_exception(DISP_E_BADINDEX, "index out of bounds");
154 return rv;
155 }
156
157 if (dims - 1 == proxy->dimensions) {
158 LONG *indices;
159 VARTYPE vt;
160 VARIANT v;
161
162 VariantInit(&v);
163
164
165 indices = safe_emalloc(dims, sizeof(LONG), 0);
166
167
168 for (i = 0; i < dims; i++) {
169 convert_to_long(&proxy->indices[i]);
170 indices[i] = (LONG)Z_LVAL(proxy->indices[i]);
171 }
172
173
174 indices[dims-1] = (LONG)Z_LVAL_P(offset);
175
176
177 if (FAILED(SafeArrayGetVartype(sa, &vt)) || vt == VT_EMPTY) {
178 vt = V_VT(&proxy->obj->v) & ~VT_ARRAY;
179 }
180
181 if (vt == VT_VARIANT) {
182 res = SafeArrayGetElement(sa, indices, &v);
183 } else {
184 V_VT(&v) = vt;
185 res = SafeArrayGetElement(sa, indices, &v.lVal);
186 }
187
188 efree(indices);
189
190 if (SUCCEEDED(res)) {
191 php_com_wrap_variant(rv, &v, proxy->obj->code_page);
192 } else {
193 php_com_throw_exception(res, NULL);
194 }
195
196 VariantClear(&v);
197
198 } else {
199
200 php_com_saproxy_create(object, rv, offset);
201 }
202
203 return rv;
204 }
205
206 static void saproxy_write_dimension(zval *object, zval *offset, zval *value)
207 {
208 php_com_saproxy *proxy = SA_FETCH(object);
209 UINT dims, i;
210 HRESULT res;
211 VARIANT v;
212
213 if (V_VT(&proxy->obj->v) == VT_DISPATCH) {
214
215
216
217 zval *args = safe_emalloc(proxy->dimensions + 2, sizeof(zval), 0);
218
219 for (i = 1; i < (UINT) proxy->dimensions; i++) {
220 ZVAL_COPY_VALUE(&args[i-1], &proxy->indices[i]);
221 }
222 ZVAL_COPY_VALUE(&args[i-1], offset);
223 ZVAL_COPY_VALUE(&args[i], value);
224
225 convert_to_string(&proxy->indices[0]);
226 VariantInit(&v);
227 if (SUCCESS == php_com_do_invoke(proxy->obj, Z_STRVAL(proxy->indices[0]),
228 Z_STRLEN(proxy->indices[0]), DISPATCH_PROPERTYPUT, &v, proxy->dimensions + 1,
229 args, 0)) {
230 VariantClear(&v);
231 }
232
233 efree(args);
234
235 } else if (V_ISARRAY(&proxy->obj->v)) {
236 LONG *indices;
237 VARTYPE vt;
238
239 dims = SafeArrayGetDim(V_ARRAY(&proxy->obj->v));
240 indices = safe_emalloc(dims, sizeof(LONG), 0);
241
242 for (i = 0; i < dims; i++) {
243 convert_to_long(&proxy->indices[i]);
244 indices[i] = (LONG)Z_LVAL(proxy->indices[i]);
245 }
246
247
248 convert_to_long(offset);
249 indices[dims-1] = (LONG)Z_LVAL_P(offset);
250
251 if (FAILED(SafeArrayGetVartype(V_ARRAY(&proxy->obj->v), &vt)) || vt == VT_EMPTY) {
252 vt = V_VT(&proxy->obj->v) & ~VT_ARRAY;
253 }
254
255 VariantInit(&v);
256 php_com_variant_from_zval(&v, value, proxy->obj->code_page);
257
258 if (V_VT(&v) != vt) {
259 VariantChangeType(&v, &v, 0, vt);
260 }
261
262 if (vt == VT_VARIANT) {
263 res = SafeArrayPutElement(V_ARRAY(&proxy->obj->v), indices, &v);
264 } else {
265 res = SafeArrayPutElement(V_ARRAY(&proxy->obj->v), indices, &v.lVal);
266 }
267
268 efree(indices);
269 VariantClear(&v);
270
271 if (FAILED(res)) {
272 php_com_throw_exception(res, NULL);
273 }
274 } else {
275 php_com_throw_exception(E_NOTIMPL, "invalid write to com proxy object");
276 }
277 }
278
279 #if 0
280 static void saproxy_object_set(zval **property, zval *value)
281 {
282 }
283
284 static zval *saproxy_object_get(zval *property)
285 {
286
287 return NULL;
288 }
289 #endif
290
291 static int saproxy_property_exists(zval *object, zval *member, int check_empty, void **cache_slot)
292 {
293
294 return 0;
295 }
296
297 static int saproxy_dimension_exists(zval *object, zval *member, int check_empty)
298 {
299 php_error_docref(NULL, E_WARNING, "Operation not yet supported on a COM object");
300 return 0;
301 }
302
303 static void saproxy_property_delete(zval *object, zval *member, void **cache_slot)
304 {
305 php_error_docref(NULL, E_WARNING, "Cannot delete properties from a COM object");
306 }
307
308 static void saproxy_dimension_delete(zval *object, zval *offset)
309 {
310 php_error_docref(NULL, E_WARNING, "Cannot delete properties from a COM object");
311 }
312
313 static HashTable *saproxy_properties_get(zval *object)
314 {
315
316 return NULL;
317 }
318
319 static union _zend_function *saproxy_method_get(zend_object **object, zend_string *name, const zval *key)
320 {
321
322 return NULL;
323 }
324
325 static int saproxy_call_method(zend_string *method, zend_object *object, INTERNAL_FUNCTION_PARAMETERS)
326 {
327 return FAILURE;
328 }
329
330 static union _zend_function *saproxy_constructor_get(zend_object *object)
331 {
332
333 return NULL;
334 }
335
336 static zend_string* saproxy_class_name_get(const zend_object *object)
337 {
338 return zend_string_copy(php_com_saproxy_class_entry->name);
339 }
340
341 static int saproxy_objects_compare(zval *object1, zval *object2)
342 {
343 return -1;
344 }
345
346 static int saproxy_object_cast(zval *readobj, zval *writeobj, int type)
347 {
348 return FAILURE;
349 }
350
351 static int saproxy_count_elements(zval *object, zend_long *count)
352 {
353 php_com_saproxy *proxy = SA_FETCH(object);
354 LONG ubound, lbound;
355
356 if (!V_ISARRAY(&proxy->obj->v)) {
357 return FAILURE;
358 }
359
360 SafeArrayGetLBound(V_ARRAY(&proxy->obj->v), proxy->dimensions, &lbound);
361 SafeArrayGetUBound(V_ARRAY(&proxy->obj->v), proxy->dimensions, &ubound);
362
363 *count = ubound - lbound + 1;
364
365 return SUCCESS;
366 }
367
368 static void saproxy_free_storage(zend_object *object)
369 {
370 php_com_saproxy *proxy = (php_com_saproxy *)object;
371
372
373
374
375
376
377
378
379 zval_ptr_dtor(proxy->zobj);
380 efree(proxy->indices);
381 }
382
383 static zend_object* saproxy_clone(zval *object)
384 {
385 php_com_saproxy *proxy = (php_com_saproxy *)Z_OBJ_P(object);
386 php_com_saproxy *cloneproxy;
387
388 cloneproxy = emalloc(sizeof(*cloneproxy));
389 memcpy(cloneproxy, proxy, sizeof(*cloneproxy));
390
391 Z_ADDREF_P(cloneproxy->zobj);
392 cloneproxy->indices = safe_emalloc(cloneproxy->dimensions, sizeof(zval *), 0);
393 clone_indices(cloneproxy, proxy, proxy->dimensions);
394
395 return &cloneproxy->std;
396 }
397
398 zend_object_handlers php_com_saproxy_handlers = {
399 0,
400 saproxy_free_storage,
401 zend_objects_destroy_object,
402 saproxy_clone,
403 saproxy_property_read,
404 saproxy_property_write,
405 saproxy_read_dimension,
406 saproxy_write_dimension,
407 NULL,
408 NULL,
409 NULL,
410 saproxy_property_exists,
411 saproxy_property_delete,
412 saproxy_dimension_exists,
413 saproxy_dimension_delete,
414 saproxy_properties_get,
415 saproxy_method_get,
416 saproxy_call_method,
417 saproxy_constructor_get,
418 saproxy_class_name_get,
419 saproxy_objects_compare,
420 saproxy_object_cast,
421 saproxy_count_elements
422 };
423
424 int php_com_saproxy_create(zval *com_object, zval *proxy_out, zval *index)
425 {
426 php_com_saproxy *proxy, *rel = NULL;
427
428 proxy = ecalloc(1, sizeof(*proxy));
429 proxy->dimensions = 1;
430
431 if (Z_OBJCE_P(com_object) == php_com_saproxy_class_entry) {
432 rel = SA_FETCH(com_object);
433 proxy->obj = rel->obj;
434 proxy->zobj = rel->zobj;
435 proxy->dimensions += rel->dimensions;
436 } else {
437 proxy->obj = CDNO_FETCH(com_object);
438 proxy->zobj = com_object;
439 }
440
441 Z_ADDREF_P(proxy->zobj);
442 proxy->indices = safe_emalloc(proxy->dimensions, sizeof(zval *), 0);
443
444 if (rel) {
445 clone_indices(proxy, rel, rel->dimensions);
446 }
447
448 ZVAL_DUP(&proxy->indices[proxy->dimensions-1], index);
449
450 zend_object_std_init(&proxy->std, php_com_saproxy_class_entry);
451 proxy->std.handlers = &php_com_saproxy_handlers;
452 ZVAL_OBJ(proxy_out, &proxy->std);
453
454 return 1;
455 }
456
457
458
459 static void saproxy_iter_dtor(zend_object_iterator *iter)
460 {
461 php_com_saproxy_iter *I = (php_com_saproxy_iter*)Z_PTR(iter->data);
462
463 zval_ptr_dtor(&I->proxy_obj);
464
465 efree(I->indices);
466 efree(I);
467 }
468
469 static int saproxy_iter_valid(zend_object_iterator *iter)
470 {
471 php_com_saproxy_iter *I = (php_com_saproxy_iter*)Z_PTR(iter->data);
472
473 return (I->key < I->imax) ? SUCCESS : FAILURE;
474 }
475
476 static zval* saproxy_iter_get_data(zend_object_iterator *iter)
477 {
478 php_com_saproxy_iter *I = (php_com_saproxy_iter*)Z_PTR(iter->data);
479 VARIANT v;
480 VARTYPE vt;
481 SAFEARRAY *sa;
482
483 I->indices[I->proxy->dimensions-1] = I->key;
484
485 sa = V_ARRAY(&I->proxy->obj->v);
486
487 if (FAILED(SafeArrayGetVartype(sa, &vt)) || vt == VT_EMPTY) {
488 vt = V_VT(&I->proxy->obj->v) & ~VT_ARRAY;
489 }
490
491 VariantInit(&v);
492 if (vt == VT_VARIANT) {
493 SafeArrayGetElement(sa, I->indices, &v);
494 } else {
495 V_VT(&v) = vt;
496 SafeArrayGetElement(sa, I->indices, &v.lVal);
497 }
498
499 ZVAL_NULL(&I->data);
500 php_com_wrap_variant(&I->data, &v, I->proxy->obj->code_page);
501 VariantClear(&v);
502
503 return &I->data;
504 }
505
506 static void saproxy_iter_get_key(zend_object_iterator *iter, zval *key)
507 {
508 php_com_saproxy_iter *I = (php_com_saproxy_iter*)Z_PTR(iter->data);
509
510 if (I->key == -1) {
511 ZVAL_NULL(key);
512 } else {
513 ZVAL_LONG(key, I->key);
514 }
515 }
516
517 static int saproxy_iter_move_forwards(zend_object_iterator *iter)
518 {
519 php_com_saproxy_iter *I = (php_com_saproxy_iter*)Z_PTR(iter->data);
520
521 if (++I->key >= I->imax) {
522 I->key = -1;
523 return FAILURE;
524 }
525 return SUCCESS;
526 }
527
528 static zend_object_iterator_funcs saproxy_iter_funcs = {
529 saproxy_iter_dtor,
530 saproxy_iter_valid,
531 saproxy_iter_get_data,
532 saproxy_iter_get_key,
533 saproxy_iter_move_forwards,
534 NULL
535 };
536
537
538 zend_object_iterator *php_com_saproxy_iter_get(zend_class_entry *ce, zval *object, int by_ref)
539 {
540 php_com_saproxy *proxy = SA_FETCH(object);
541 php_com_saproxy_iter *I;
542 int i;
543
544 if (by_ref) {
545 zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
546 }
547
548 I = ecalloc(1, sizeof(*I));
549 I->iter.funcs = &saproxy_iter_funcs;
550 Z_PTR(I->iter.data) = I;
551
552 I->proxy = proxy;
553 ZVAL_COPY(&I->proxy_obj, object);
554
555 I->indices = safe_emalloc(proxy->dimensions + 1, sizeof(LONG), 0);
556 for (i = 0; i < proxy->dimensions; i++) {
557 convert_to_long(&proxy->indices[i]);
558 I->indices[i] = (LONG)Z_LVAL(proxy->indices[i]);
559 }
560
561 SafeArrayGetLBound(V_ARRAY(&proxy->obj->v), proxy->dimensions, &I->imin);
562 SafeArrayGetUBound(V_ARRAY(&proxy->obj->v), proxy->dimensions, &I->imax);
563
564 I->key = I->imin;
565
566 return &I->iter;
567 }
568