php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
com_saproxy.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Author: Wez Furlong <wez@thebrainroom.com> |
14 +----------------------------------------------------------------------+
15 */
16
17/* This module implements a SafeArray proxy which is used internally
18 * by the engine when resolving multi-dimensional array accesses on
19 * SafeArray types.
20 * In addition, the proxy is now able to handle properties of COM objects
21 * that smell like PHP arrays.
22 * */
23
24#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
27
28#include "php.h"
29#include "php_ini.h"
30#include "ext/standard/info.h"
31#include "php_com_dotnet.h"
34
35typedef struct {
37 /* the object we a proxying for; we hold a refcount to it */
39
40 /* how many dimensions we are indirecting to get into this element */
42
43 /* this is an array whose size_is(dimensions) */
45
47
57
58#define SA_FETCH(zv) (php_com_saproxy*)Z_OBJ_P(zv)
59
60static inline void clone_indices(php_com_saproxy *dest, php_com_saproxy *src, int ndims)
61{
62 int i;
63
64 for (i = 0; i < ndims; i++) {
65 ZVAL_DUP(&dest->indices[i], &src->indices[i]);
66 }
67}
68
69static zval *saproxy_property_read(zend_object *object, zend_string *member, int type, void **cache_slot, zval *rv)
70{
72
73 php_com_throw_exception(E_INVALIDARG, "safearray has no properties");
74
75 return rv;
76}
77
78static zval *saproxy_property_write(zend_object *object, zend_string *member, zval *value, void **cache_slot)
79{
80 php_com_throw_exception(E_INVALIDARG, "safearray has no properties");
81 return value;
82}
83
84static zval *saproxy_read_dimension(zend_object *object, zval *offset, int type, zval *rv)
85{
86 php_com_saproxy *proxy = (php_com_saproxy*) object;
87 UINT dims, i;
88 SAFEARRAY *sa;
89 LONG ubound, lbound;
90 HRESULT res;
91
93
94 if (V_VT(&proxy->obj->v) == VT_DISPATCH) {
95 VARIANT v;
96 zval *args;
97
98 /* prop-get using first dimension as the property name,
99 * all subsequent dimensions and the offset as parameters */
100
101 args = safe_emalloc(proxy->dimensions + 1, sizeof(zval), 0);
102
103 for (i = 1; i < (UINT) proxy->dimensions; i++) {
104 args[i-1] = proxy->indices[i];
105 }
107
108 if (!try_convert_to_string(&proxy->indices[0])) {
109 efree(args);
110 return rv;
111 }
112 VariantInit(&v);
113
114 res = php_com_do_invoke(proxy->obj, Z_STR(proxy->indices[0]),
115 DISPATCH_METHOD|DISPATCH_PROPERTYGET, &v,
116 proxy->dimensions, args, 0);
117
118 efree(args);
119
120 if (res == SUCCESS) {
122 VariantClear(&v);
123 } else if (res == DISP_E_BADPARAMCOUNT) {
124 /* return another proxy */
126 }
127
128 return rv;
129
130 } else if (!V_ISARRAY(&proxy->obj->v)) {
131 php_com_throw_exception(E_INVALIDARG, "invalid read from com proxy object");
132 return rv;
133 }
134
135 /* the SafeArray case */
136
137 /* offset/index must be an integer */
139
140 sa = V_ARRAY(&proxy->obj->v);
141 dims = SafeArrayGetDim(sa);
142
143 if ((UINT) proxy->dimensions >= dims) {
144 /* too many dimensions */
145 php_com_throw_exception(E_INVALIDARG, "too many dimensions!");
146 return rv;
147 }
148
149 /* bounds check */
150 SafeArrayGetLBound(sa, proxy->dimensions, &lbound);
151 SafeArrayGetUBound(sa, proxy->dimensions, &ubound);
152
153 if (Z_LVAL_P(offset) < lbound || Z_LVAL_P(offset) > ubound) {
154 php_com_throw_exception(DISP_E_BADINDEX, "index out of bounds");
155 return rv;
156 }
157
158 if (dims - 1 == proxy->dimensions) {
159 LONG *indices;
160 VARTYPE vt;
161 VARIANT v;
162
163 VariantInit(&v);
164
165 /* we can return a real value */
166 indices = safe_emalloc(dims, sizeof(LONG), 0);
167
168 /* copy indices from proxy */
169 for (i = 0; i < dims; i++) {
170 convert_to_long(&proxy->indices[i]);
171 indices[i] = (LONG)Z_LVAL(proxy->indices[i]);
172 }
173
174 /* add user-supplied index */
175 indices[dims-1] = (LONG)Z_LVAL_P(offset);
176
177 /* now fetch the value */
178 if (FAILED(SafeArrayGetVartype(sa, &vt)) || vt == VT_EMPTY) {
179 vt = V_VT(&proxy->obj->v) & ~VT_ARRAY;
180 }
181
182 if (vt == VT_VARIANT) {
183 res = SafeArrayGetElement(sa, indices, &v);
184 } else {
185 V_VT(&v) = vt;
186 res = SafeArrayGetElement(sa, indices, &v.lVal);
187 }
188
189 efree(indices);
190
191 if (SUCCEEDED(res)) {
193 } else {
195 }
196
197 VariantClear(&v);
198
199 } else {
200 /* return another proxy */
202 }
203
204 return rv;
205}
206
207static void saproxy_write_dimension(zend_object *object, zval *offset, zval *value)
208{
209 php_com_saproxy *proxy = (php_com_saproxy*) object;
210 UINT dims, i;
211 HRESULT res;
212 VARIANT v;
213
214 if (V_VT(&proxy->obj->v) == VT_DISPATCH) {
215 /* We do a prop-set using the first dimension as the property name,
216 * all subsequent dimensions and offset as parameters, with value as
217 * the final value */
218 zval *args = safe_emalloc(proxy->dimensions + 2, sizeof(zval), 0);
219
220 for (i = 1; i < (UINT) proxy->dimensions; i++) {
221 ZVAL_COPY_VALUE(&args[i-1], &proxy->indices[i]);
222 }
225
226 if (!try_convert_to_string(&proxy->indices[0])) {
227 efree(args);
228 return;
229 }
230 VariantInit(&v);
231 if (SUCCESS == php_com_do_invoke(proxy->obj, Z_STR(proxy->indices[0]),
232 DISPATCH_PROPERTYPUT, &v, proxy->dimensions + 1,
233 args, 0)) {
234 VariantClear(&v);
235 }
236
237 efree(args);
238
239 } else if (V_ISARRAY(&proxy->obj->v)) {
240 LONG *indices;
241 VARTYPE vt;
242
243 dims = SafeArrayGetDim(V_ARRAY(&proxy->obj->v));
244 indices = safe_emalloc(dims, sizeof(LONG), 0);
245 /* copy indices from proxy */
246 for (i = 0; i < dims; i++) {
247 convert_to_long(&proxy->indices[i]);
248 indices[i] = (LONG)Z_LVAL(proxy->indices[i]);
249 }
250
251 /* add user-supplied index */
253 indices[dims-1] = (LONG)Z_LVAL_P(offset);
254
255 if (FAILED(SafeArrayGetVartype(V_ARRAY(&proxy->obj->v), &vt)) || vt == VT_EMPTY) {
256 vt = V_VT(&proxy->obj->v) & ~VT_ARRAY;
257 }
258
259 VariantInit(&v);
261
262 if (V_VT(&v) != vt) {
263 VariantChangeType(&v, &v, 0, vt);
264 }
265
266 if (vt == VT_VARIANT) {
267 res = SafeArrayPutElement(V_ARRAY(&proxy->obj->v), indices, &v);
268 } else {
269 res = SafeArrayPutElement(V_ARRAY(&proxy->obj->v), indices, &v.lVal);
270 }
271
272 efree(indices);
273 VariantClear(&v);
274
275 if (FAILED(res)) {
277 }
278 } else {
279 php_com_throw_exception(E_NOTIMPL, "invalid write to com proxy object");
280 }
281}
282
283static int saproxy_property_exists(zend_object *object, zend_string *member, int check_empty, void **cache_slot)
284{
285 /* no properties */
286 return 0;
287}
288
289static int saproxy_dimension_exists(zend_object *object, zval *member, int check_empty)
290{
291 /* TODO Add support */
292 zend_throw_error(NULL, "Cannot check dimension on a COM object");
293 return 0;
294}
295
296static void saproxy_property_delete(zend_object *object, zend_string *member, void **cache_slot)
297{
298 zend_throw_error(NULL, "Cannot delete properties from a COM object");
299}
300
301static void saproxy_dimension_delete(zend_object *object, zval *offset)
302{
303 zend_throw_error(NULL, "Cannot delete dimension from a COM object");
304}
305
306static HashTable *saproxy_properties_get(zend_object *object)
307{
308 /* no properties */
309 return NULL;
310}
311
312static zend_function *saproxy_method_get(zend_object **object, zend_string *name, const zval *key)
313{
314 /* no methods */
315 return NULL;
316}
317
318static zend_function *saproxy_constructor_get(zend_object *object)
319{
320 /* user cannot instantiate */
321 return NULL;
322}
323
324static zend_string* saproxy_class_name_get(const zend_object *object)
325{
326 return zend_string_copy(php_com_saproxy_class_entry->name);
327}
328
329static int saproxy_objects_compare(zval *object1, zval *object2)
330{
331 ZEND_COMPARE_OBJECTS_FALLBACK(object1, object2);
332 return -1;
333}
334
335static zend_result saproxy_object_cast(zend_object *readobj, zval *writeobj, int type)
336{
337 return FAILURE;
338}
339
340static zend_result saproxy_count_elements(zend_object *object, zend_long *count)
341{
342 php_com_saproxy *proxy = (php_com_saproxy*) object;
343 LONG ubound, lbound;
344
345 if (!V_ISARRAY(&proxy->obj->v)) {
346 return FAILURE;
347 }
348
349 SafeArrayGetLBound(V_ARRAY(&proxy->obj->v), proxy->dimensions, &lbound);
350 SafeArrayGetUBound(V_ARRAY(&proxy->obj->v), proxy->dimensions, &ubound);
351
352 *count = ubound - lbound + 1;
353
354 return SUCCESS;
355}
356
357static void saproxy_free_storage(zend_object *object)
358{
359 php_com_saproxy *proxy = (php_com_saproxy *)object;
360//??? int i;
361//???
362//??? for (i = 0; i < proxy->dimensions; i++) {
363//??? if (proxy->indices) {
364//??? FREE_ZVAL(proxy->indices[i]);
365//??? }
366//??? }
367
368 OBJ_RELEASE(&proxy->obj->zo);
369
370 zend_object_std_dtor(object);
371
372 efree(proxy->indices);
373}
374
375static zend_object* saproxy_clone(zend_object *object)
376{
377 php_com_saproxy *proxy = (php_com_saproxy *) object;
378 php_com_saproxy *cloneproxy;
379
380 cloneproxy = emalloc(sizeof(*cloneproxy));
381 memcpy(cloneproxy, proxy, sizeof(*cloneproxy));
382
383 GC_ADDREF(&cloneproxy->obj->zo);
384 cloneproxy->indices = safe_emalloc(cloneproxy->dimensions, sizeof(zval), 0);
385 clone_indices(cloneproxy, proxy, proxy->dimensions);
386
387 return &cloneproxy->std;
388}
389
391 0,
392 saproxy_free_storage,
394 saproxy_clone,
395 saproxy_property_read,
396 saproxy_property_write,
397 saproxy_read_dimension,
398 saproxy_write_dimension,
399 NULL,
400 saproxy_property_exists,
401 saproxy_property_delete,
402 saproxy_dimension_exists,
403 saproxy_dimension_delete,
404 saproxy_properties_get,
405 saproxy_method_get,
406 saproxy_constructor_get,
407 saproxy_class_name_get,
408 saproxy_object_cast,
409 saproxy_count_elements,
410 NULL, /* get_debug_info */
411 NULL, /* get_closure */
412 NULL, /* get_gc */
413 NULL, /* do_operation */
414 saproxy_objects_compare, /* compare */
415 NULL, /* get_properties_for */
416};
417
418void php_com_saproxy_create(zend_object *com_object, zval *proxy_out, zval *index)
419{
420 php_com_saproxy *proxy, *rel = NULL;
421
422 proxy = ecalloc(1, sizeof(*proxy));
423 proxy->dimensions = 1;
424
425 if (com_object->ce == php_com_saproxy_class_entry) {
426 rel = (php_com_saproxy*) com_object;
427 proxy->obj = rel->obj;
428 proxy->dimensions += rel->dimensions;
429 } else {
430 proxy->obj = (php_com_dotnet_object*) com_object;
431 }
432
433 GC_ADDREF(&proxy->obj->zo);
434 proxy->indices = safe_emalloc(proxy->dimensions, sizeof(zval), 0);
435
436 if (rel) {
437 clone_indices(proxy, rel, rel->dimensions);
438 }
439
440 ZVAL_DUP(&proxy->indices[proxy->dimensions-1], index);
441
443 ZVAL_OBJ(proxy_out, &proxy->std);
444}
445
446/* iterator */
447
448static void saproxy_iter_dtor(zend_object_iterator *iter)
449{
451
452 zval_ptr_dtor(&I->proxy_obj);
453
454 efree(I->indices);
455 efree(I);
456}
457
458static zend_result saproxy_iter_valid(zend_object_iterator *iter)
459{
461
462 return (I->key < I->imax) ? SUCCESS : FAILURE;
463}
464
465static zval* saproxy_iter_get_data(zend_object_iterator *iter)
466{
468 VARIANT v;
469 VARTYPE vt;
470 SAFEARRAY *sa;
471
472 I->indices[I->proxy->dimensions-1] = I->key;
473
474 sa = V_ARRAY(&I->proxy->obj->v);
475
476 if (FAILED(SafeArrayGetVartype(sa, &vt)) || vt == VT_EMPTY) {
477 vt = V_VT(&I->proxy->obj->v) & ~VT_ARRAY;
478 }
479
480 VariantInit(&v);
481 if (vt == VT_VARIANT) {
482 SafeArrayGetElement(sa, I->indices, &v);
483 } else {
484 V_VT(&v) = vt;
485 SafeArrayGetElement(sa, I->indices, &v.lVal);
486 }
487
488 ZVAL_NULL(&I->data);
489 php_com_wrap_variant(&I->data, &v, I->proxy->obj->code_page);
490 VariantClear(&v);
491
492 return &I->data;
493}
494
495static void saproxy_iter_get_key(zend_object_iterator *iter, zval *key)
496{
498
499 if (I->key == -1) {
500 ZVAL_NULL(key);
501 } else {
502 ZVAL_LONG(key, I->key);
503 }
504}
505
506static void saproxy_iter_move_forwards(zend_object_iterator *iter)
507{
509
510 if (++I->key >= I->imax) {
511 I->key = -1;
512 }
513}
514
515static const zend_object_iterator_funcs saproxy_iter_funcs = {
516 saproxy_iter_dtor,
517 saproxy_iter_valid,
518 saproxy_iter_get_data,
519 saproxy_iter_get_key,
520 saproxy_iter_move_forwards,
521 NULL,
522 NULL, /* get_gc */
523};
524
525
527{
528 php_com_saproxy *proxy = SA_FETCH(object);
530 int i;
531
532 if (by_ref) {
533 zend_throw_error(NULL, "An iterator cannot be used with foreach by reference");
534 return NULL;
535 }
536
537 I = ecalloc(1, sizeof(*I));
538 I->iter.funcs = &saproxy_iter_funcs;
539 Z_PTR(I->iter.data) = I;
540
541 I->proxy = proxy;
542 Z_ADDREF_P(object);
543 ZVAL_OBJ(&I->proxy_obj, Z_OBJ_P(object));
544
545 I->indices = safe_emalloc(proxy->dimensions + 1, sizeof(LONG), 0);
546 for (i = 0; i < proxy->dimensions; i++) {
547 convert_to_long(&proxy->indices[i]);
548 I->indices[i] = (LONG)Z_LVAL(proxy->indices[i]);
549 }
550
551 SafeArrayGetLBound(V_ARRAY(&proxy->obj->v), proxy->dimensions, &I->imin);
552 SafeArrayGetUBound(V_ARRAY(&proxy->obj->v), proxy->dimensions, &I->imax);
553
554 I->key = I->imin;
555
556 return &I->iter;
557}
count(Countable|array $value, int $mode=COUNT_NORMAL)
uint32_t v
Definition cdf.c:1237
zend_result php_com_do_invoke(php_com_dotnet_object *obj, zend_string *name, WORD flags, VARIANT *v, int nargs, zval *args, bool allow_noarg)
Definition com_com.c:631
zend_class_entry * php_com_saproxy_class_entry
const DISP_E_BADINDEX
const VT_DISPATCH
const VT_VARIANT
const VT_EMPTY
const VT_ARRAY
PHP_COM_DOTNET_API void php_com_wrap_variant(zval *z, VARIANT *v, int codepage)
Definition com_misc.c:67
void php_com_throw_exception(HRESULT code, char *message)
Definition com_misc.c:28
#define SA_FETCH(zv)
Definition com_saproxy.c:58
zend_object_iterator * php_com_saproxy_iter_get(zend_class_entry *ce, zval *object, int by_ref)
zend_object_handlers php_com_saproxy_handlers
void php_com_saproxy_create(zend_object *com_object, zval *proxy_out, zval *index)
VARTYPE vt
PHP_COM_DOTNET_API zend_result php_com_zval_from_variant(zval *z, VARIANT *v, int codepage)
PHP_COM_DOTNET_API void php_com_variant_from_zval(VARIANT *v, zval *z, int codepage)
HashTable * dims
Definition ffi.c:4261
zend_ffi_type * type
Definition ffi.c:3812
zend_string * res
Definition ffi.c:4692
memcpy(ptr1, ptr2, size)
#define I
Definition encoding.c:237
zend_long offset
#define NULL
Definition gdcache.h:45
#define SUCCESS
Definition hash_sha3.c:261
struct _php_com_dotnet_object php_com_dotnet_object
unsigned char key[REFLECTION_KEY_LEN]
zval rv
Definition session.c:1024
zend_class_entry * ce
Definition zend_types.h:560
zend_object_iterator iter
Definition com_saproxy.c:49
php_com_saproxy * proxy
Definition com_saproxy.c:52
zend_object std
Definition com_saproxy.c:36
php_com_dotnet_object * obj
Definition com_saproxy.c:38
ZEND_API ZEND_COLD void zend_throw_error(zend_class_entry *exception_ce, const char *format,...)
Definition zend.c:1772
#define ecalloc(nmemb, size)
Definition zend_alloc.h:158
#define efree(ptr)
Definition zend_alloc.h:155
#define safe_emalloc(nmemb, size, offset)
Definition zend_alloc.h:154
#define emalloc(size)
Definition zend_alloc.h:151
struct _zval_struct zval
zval * args
union _zend_function zend_function
struct _zend_object_iterator zend_object_iterator
struct _zend_object_iterator_funcs zend_object_iterator_funcs
int32_t zend_long
Definition zend_long.h:42
struct _zend_string zend_string
#define ZEND_COMPARE_OBJECTS_FALLBACK(op1, op2)
ZEND_API void zend_objects_destroy_object(zend_object *object)
ZEND_API void ZEND_FASTCALL zend_object_std_init(zend_object *object, zend_class_entry *ce)
ZEND_API void zend_object_std_dtor(zend_object *object)
#define OBJ_RELEASE(obj)
ZEND_API void ZEND_FASTCALL convert_to_long(zval *op)
struct _zend_class_entry zend_class_entry
struct _zend_object zend_object
#define ZVAL_DUP(z, v)
#define ZVAL_NULL(z)
#define ZVAL_LONG(z, l)
struct _zend_array HashTable
Definition zend_types.h:386
#define Z_OBJ_P(zval_p)
Definition zend_types.h:990
#define Z_STR(zval)
Definition zend_types.h:971
#define GC_ADDREF(p)
Definition zend_types.h:709
#define Z_ADDREF_P(pz)
#define Z_PTR(zval)
#define ZVAL_OBJ(z, o)
@ FAILURE
Definition zend_types.h:61
ZEND_RESULT_CODE zend_result
Definition zend_types.h:64
struct _zend_object_handlers zend_object_handlers
Definition zend_types.h:88
#define Z_LVAL_P(zval_p)
Definition zend_types.h:966
#define ZVAL_COPY_VALUE(z, v)
#define Z_LVAL(zval)
Definition zend_types.h:965
ZEND_API void zval_ptr_dtor(zval *zval_ptr)
zend_string * name
value