Annotation of embedaddon/php/ext/com_dotnet/com_saproxy.c, revision 1.1.1.3
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: /* This module implements a SafeArray proxy which is used internally
22: * by the engine when resolving multi-dimensional array accesses on
23: * SafeArray types.
24: * In addition, the proxy is now able to handle properties of COM objects
25: * that smell like PHP arrays.
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: /* the object we a proxying for; we hold a refcount to it */
41: zval *zobj;
42: php_com_dotnet_object *obj;
43:
44: /* how many dimensions we are indirecting to get into this element */
45: LONG dimensions;
46:
47: /* this is an array whose size_is(dimensions) */
48: zval **indices;
49:
50: } php_com_saproxy;
51:
52: typedef struct {
53: zend_object_iterator iter;
54: zval *proxy_obj;
55: php_com_saproxy *proxy;
56: LONG key;
57: LONG imin, imax;
58: LONG *indices;
59: } php_com_saproxy_iter;
60:
61: #define SA_FETCH(zv) (php_com_saproxy*)zend_object_store_get_object(zv TSRMLS_CC)
62:
63: static inline void clone_indices(php_com_saproxy *dest, php_com_saproxy *src, int ndims)
64: {
65: int i;
66:
67: for (i = 0; i < ndims; i++) {
68: MAKE_STD_ZVAL(dest->indices[i]);
69: *dest->indices[i] = *src->indices[i];
70: zval_copy_ctor(dest->indices[i]);
71: }
72: }
73:
1.1.1.2 misho 74: static zval *saproxy_property_read(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC)
1.1 misho 75: {
76: zval *return_value;
77:
78: MAKE_STD_ZVAL(return_value);
79: ZVAL_NULL(return_value);
80:
81: php_com_throw_exception(E_INVALIDARG, "safearray has no properties" TSRMLS_CC);
82:
83: return return_value;
84: }
85:
1.1.1.2 misho 86: static void saproxy_property_write(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC)
1.1 misho 87: {
88: php_com_throw_exception(E_INVALIDARG, "safearray has no properties" TSRMLS_CC);
89: }
90:
91: static zval *saproxy_read_dimension(zval *object, zval *offset, int type TSRMLS_DC)
92: {
93: php_com_saproxy *proxy = SA_FETCH(object);
94: zval *return_value;
95: UINT dims, i;
96: SAFEARRAY *sa;
97: LONG ubound, lbound;
98: HRESULT res;
99:
100: MAKE_STD_ZVAL(return_value);
101: ZVAL_NULL(return_value);
102:
103: if (V_VT(&proxy->obj->v) == VT_DISPATCH) {
104: VARIANT v;
105: zval **args;
106:
107: /* prop-get using first dimension as the property name,
108: * all subsequent dimensions and the offset as parameters */
109:
110: args = safe_emalloc(proxy->dimensions + 1, sizeof(zval *), 0);
111:
112: for (i = 1; i < (UINT) proxy->dimensions; i++) {
113: args[i-1] = proxy->indices[i];
114: }
115: args[i-1] = offset;
116:
117: convert_to_string(proxy->indices[0]);
118: VariantInit(&v);
119:
120: res = php_com_do_invoke(proxy->obj, Z_STRVAL_P(proxy->indices[0]),
121: Z_STRLEN_P(proxy->indices[0]), DISPATCH_METHOD|DISPATCH_PROPERTYGET, &v,
122: proxy->dimensions, args, 0 TSRMLS_CC);
123:
124: if (res == SUCCESS) {
125: php_com_zval_from_variant(return_value, &v, proxy->obj->code_page TSRMLS_CC);
126: VariantClear(&v);
127: } else if (res == DISP_E_BADPARAMCOUNT) {
128: /* return another proxy */
129: php_com_saproxy_create(object, return_value, offset TSRMLS_CC);
130: }
131:
132: return return_value;
133:
134: } else if (!V_ISARRAY(&proxy->obj->v)) {
135: php_com_throw_exception(E_INVALIDARG, "invalid read from com proxy object" TSRMLS_CC);
136: return return_value;
137: }
138:
139: /* the SafeArray case */
140:
141: /* offset/index must be an integer */
142: convert_to_long(offset);
143:
144: sa = V_ARRAY(&proxy->obj->v);
145: dims = SafeArrayGetDim(sa);
146:
147: if ((UINT) proxy->dimensions >= dims) {
148: /* too many dimensions */
149: php_com_throw_exception(E_INVALIDARG, "too many dimensions!" TSRMLS_CC);
150: return return_value;
151: }
152:
153: /* bounds check */
154: SafeArrayGetLBound(sa, proxy->dimensions, &lbound);
155: SafeArrayGetUBound(sa, proxy->dimensions, &ubound);
156:
157: if (Z_LVAL_P(offset) < lbound || Z_LVAL_P(offset) > ubound) {
158: php_com_throw_exception(DISP_E_BADINDEX, "index out of bounds" TSRMLS_CC);
159: return return_value;
160: }
161:
162: if (dims - 1 == proxy->dimensions) {
163: LONG *indices;
164: VARTYPE vt;
165: VARIANT v;
166:
167: VariantInit(&v);
168:
169: /* we can return a real value */
170: indices = safe_emalloc(dims, sizeof(LONG), 0);
171:
172: /* copy indices from proxy */
173: for (i = 0; i < dims; i++) {
174: convert_to_long(proxy->indices[i]);
175: indices[i] = Z_LVAL_P(proxy->indices[i]);
176: }
177:
178: /* add user-supplied index */
179: indices[dims-1] = Z_LVAL_P(offset);
180:
181: /* now fetch the value */
182: if (FAILED(SafeArrayGetVartype(sa, &vt)) || vt == VT_EMPTY) {
183: vt = V_VT(&proxy->obj->v) & ~VT_ARRAY;
184: }
185:
186: if (vt == VT_VARIANT) {
187: res = SafeArrayGetElement(sa, indices, &v);
188: } else {
189: V_VT(&v) = vt;
190: res = SafeArrayGetElement(sa, indices, &v.lVal);
191: }
192:
193: efree(indices);
194:
195: if (SUCCEEDED(res)) {
196: php_com_wrap_variant(return_value, &v, proxy->obj->code_page TSRMLS_CC);
197: } else {
198: php_com_throw_exception(res, NULL TSRMLS_CC);
199: }
200:
201: VariantClear(&v);
202:
203: } else {
204: /* return another proxy */
205: php_com_saproxy_create(object, return_value, offset TSRMLS_CC);
206: }
207:
208: return return_value;
209: }
210:
211: static void saproxy_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC)
212: {
213: php_com_saproxy *proxy = SA_FETCH(object);
214: UINT dims, i;
215: HRESULT res;
216: VARIANT v;
217:
218: if (V_VT(&proxy->obj->v) == VT_DISPATCH) {
219: /* We do a prop-set using the first dimension as the property name,
220: * all subsequent dimensions and offset as parameters, with value as
221: * the final value */
222: zval **args = safe_emalloc(proxy->dimensions + 2, sizeof(zval *), 0);
223:
224: for (i = 1; i < (UINT) proxy->dimensions; i++) {
225: args[i-1] = proxy->indices[i];
226: }
227: args[i-1] = offset;
228: args[i] = value;
229:
230: convert_to_string(proxy->indices[0]);
231: VariantInit(&v);
232: if (SUCCESS == php_com_do_invoke(proxy->obj, Z_STRVAL_P(proxy->indices[0]),
233: Z_STRLEN_P(proxy->indices[0]), DISPATCH_PROPERTYPUT, &v, proxy->dimensions + 1,
234: args, 0 TSRMLS_CC)) {
235: VariantClear(&v);
236: }
237:
238: efree(args);
239:
240: } else if (V_ISARRAY(&proxy->obj->v)) {
241: LONG *indices;
242: VARTYPE vt;
243:
244: dims = SafeArrayGetDim(V_ARRAY(&proxy->obj->v));
245: indices = safe_emalloc(dims, sizeof(LONG), 0);
246: /* copy indices from proxy */
247: for (i = 0; i < dims; i++) {
248: convert_to_long(proxy->indices[i]);
249: indices[i] = Z_LVAL_P(proxy->indices[i]);
250: }
251:
252: /* add user-supplied index */
253: convert_to_long(offset);
254: indices[dims-1] = Z_LVAL_P(offset);
255:
256: if (FAILED(SafeArrayGetVartype(V_ARRAY(&proxy->obj->v), &vt)) || vt == VT_EMPTY) {
257: vt = V_VT(&proxy->obj->v) & ~VT_ARRAY;
258: }
259:
260: VariantInit(&v);
261: php_com_variant_from_zval(&v, value, proxy->obj->code_page TSRMLS_CC);
262:
263: if (V_VT(&v) != vt) {
264: VariantChangeType(&v, &v, 0, vt);
265: }
266:
267: if (vt == VT_VARIANT) {
268: res = SafeArrayPutElement(V_ARRAY(&proxy->obj->v), indices, &v);
269: } else {
270: res = SafeArrayPutElement(V_ARRAY(&proxy->obj->v), indices, &v.lVal);
271: }
272:
273: efree(indices);
274: VariantClear(&v);
275:
276: if (FAILED(res)) {
277: php_com_throw_exception(res, NULL TSRMLS_CC);
278: }
279: } else {
280: php_com_throw_exception(E_NOTIMPL, "invalid write to com proxy object" TSRMLS_CC);
281: }
282: }
283:
284: #if 0
285: static void saproxy_object_set(zval **property, zval *value TSRMLS_DC)
286: {
287: }
288:
289: static zval *saproxy_object_get(zval *property TSRMLS_DC)
290: {
291: /* Not yet implemented in the engine */
292: return NULL;
293: }
294: #endif
295:
1.1.1.2 misho 296: static int saproxy_property_exists(zval *object, zval *member, int check_empty, const zend_literal *key TSRMLS_DC)
1.1 misho 297: {
298: /* no properties */
299: return 0;
300: }
301:
302: static int saproxy_dimension_exists(zval *object, zval *member, int check_empty TSRMLS_DC)
303: {
304: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Operation not yet supported on a COM object");
305: return 0;
306: }
307:
1.1.1.2 misho 308: static void saproxy_property_delete(zval *object, zval *member, const zend_literal *key TSRMLS_DC)
1.1 misho 309: {
310: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot delete properties from a COM object");
311: }
312:
313: static void saproxy_dimension_delete(zval *object, zval *offset TSRMLS_DC)
314: {
315: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot delete properties from a COM object");
316: }
317:
318: static HashTable *saproxy_properties_get(zval *object TSRMLS_DC)
319: {
320: /* no properties */
321: return NULL;
322: }
323:
1.1.1.2 misho 324: static union _zend_function *saproxy_method_get(zval **object, const char *name, int len, const zend_literal *key TSRMLS_DC)
1.1 misho 325: {
326: /* no methods */
327: return NULL;
328: }
329:
1.1.1.2 misho 330: static int saproxy_call_method(const char *method, INTERNAL_FUNCTION_PARAMETERS)
1.1 misho 331: {
332: return FAILURE;
333: }
334:
335: static union _zend_function *saproxy_constructor_get(zval *object TSRMLS_DC)
336: {
337: /* user cannot instantiate */
338: return NULL;
339: }
340:
341: static zend_class_entry *saproxy_class_entry_get(const zval *object TSRMLS_DC)
342: {
343: return php_com_saproxy_class_entry;
344: }
345:
1.1.1.2 misho 346: static int saproxy_class_name_get(const zval *object, const char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC)
1.1 misho 347: {
348: *class_name = estrndup(php_com_saproxy_class_entry->name, php_com_saproxy_class_entry->name_length);
349: *class_name_len = php_com_saproxy_class_entry->name_length;
350: return 0;
351: }
352:
353: static int saproxy_objects_compare(zval *object1, zval *object2 TSRMLS_DC)
354: {
355: return -1;
356: }
357:
358: static int saproxy_object_cast(zval *readobj, zval *writeobj, int type TSRMLS_DC)
359: {
360: return FAILURE;
361: }
362:
363: static int saproxy_count_elements(zval *object, long *count TSRMLS_DC)
364: {
365: php_com_saproxy *proxy = SA_FETCH(object);
366: LONG ubound, lbound;
367:
368: if (!V_ISARRAY(&proxy->obj->v)) {
369: return FAILURE;
370: }
371:
372: SafeArrayGetLBound(V_ARRAY(&proxy->obj->v), proxy->dimensions, &lbound);
373: SafeArrayGetUBound(V_ARRAY(&proxy->obj->v), proxy->dimensions, &ubound);
374:
375: *count = ubound - lbound + 1;
376:
377: return SUCCESS;
378: }
379:
380: zend_object_handlers php_com_saproxy_handlers = {
381: ZEND_OBJECTS_STORE_HANDLERS,
382: saproxy_property_read,
383: saproxy_property_write,
384: saproxy_read_dimension,
385: saproxy_write_dimension,
386: NULL,
387: NULL, /* saproxy_object_get, */
388: NULL, /* saproxy_object_set, */
389: saproxy_property_exists,
390: saproxy_property_delete,
391: saproxy_dimension_exists,
392: saproxy_dimension_delete,
393: saproxy_properties_get,
394: saproxy_method_get,
395: saproxy_call_method,
396: saproxy_constructor_get,
397: saproxy_class_entry_get,
398: saproxy_class_name_get,
399: saproxy_objects_compare,
400: saproxy_object_cast,
401: saproxy_count_elements
402: };
403:
404: static void saproxy_free_storage(void *object TSRMLS_DC)
405: {
406: php_com_saproxy *proxy = (php_com_saproxy *)object;
407: int i;
408:
409: for (i = 0; i < proxy->dimensions; i++) {
410: if (proxy->indices) {
411: FREE_ZVAL(proxy->indices[i]);
412: }
413: }
414:
415: zval_ptr_dtor(&proxy->zobj);
416: efree(proxy->indices);
417: efree(proxy);
418: }
419:
420: static void saproxy_clone(void *object, void **clone_ptr TSRMLS_DC)
421: {
422: php_com_saproxy *proxy = (php_com_saproxy *)object;
423: php_com_saproxy *cloneproxy;
424:
425: cloneproxy = emalloc(sizeof(*cloneproxy));
426: memcpy(cloneproxy, proxy, sizeof(*cloneproxy));
427:
428: Z_ADDREF_P(cloneproxy->zobj);
429: cloneproxy->indices = safe_emalloc(cloneproxy->dimensions, sizeof(zval *), 0);
430: clone_indices(cloneproxy, proxy, proxy->dimensions);
431:
432: *clone_ptr = cloneproxy;
433: }
434:
435: int php_com_saproxy_create(zval *com_object, zval *proxy_out, zval *index TSRMLS_DC)
436: {
437: php_com_saproxy *proxy, *rel = NULL;
438:
439: proxy = ecalloc(1, sizeof(*proxy));
440: proxy->dimensions = 1;
441:
442: if (Z_OBJCE_P(com_object) == php_com_saproxy_class_entry) {
443: rel = SA_FETCH(com_object);
444: proxy->obj = rel->obj;
445: proxy->zobj = rel->zobj;
446: proxy->dimensions += rel->dimensions;
447: } else {
448: proxy->obj = CDNO_FETCH(com_object);
449: proxy->zobj = com_object;
450: }
451:
452: Z_ADDREF_P(proxy->zobj);
453: proxy->indices = safe_emalloc(proxy->dimensions, sizeof(zval *), 0);
454:
455: if (rel) {
456: clone_indices(proxy, rel, rel->dimensions);
457: }
458:
459: MAKE_STD_ZVAL(proxy->indices[proxy->dimensions-1]);
460: *proxy->indices[proxy->dimensions-1] = *index;
461: zval_copy_ctor(proxy->indices[proxy->dimensions-1]);
462:
463: Z_TYPE_P(proxy_out) = IS_OBJECT;
464: Z_OBJ_HANDLE_P(proxy_out) = zend_objects_store_put(proxy, NULL, saproxy_free_storage, saproxy_clone TSRMLS_CC);
465: Z_OBJ_HT_P(proxy_out) = &php_com_saproxy_handlers;
466:
467: return 1;
468: }
469:
470: /* iterator */
471:
472: static void saproxy_iter_dtor(zend_object_iterator *iter TSRMLS_DC)
473: {
474: php_com_saproxy_iter *I = (php_com_saproxy_iter*)iter->data;
475:
476: zval_ptr_dtor(&I->proxy_obj);
477:
478: efree(I->indices);
479: efree(I);
480: }
481:
482: static int saproxy_iter_valid(zend_object_iterator *iter TSRMLS_DC)
483: {
484: php_com_saproxy_iter *I = (php_com_saproxy_iter*)iter->data;
485:
486: return (I->key < I->imax) ? SUCCESS : FAILURE;
487: }
488:
489: static void saproxy_iter_get_data(zend_object_iterator *iter, zval ***data TSRMLS_DC)
490: {
491: php_com_saproxy_iter *I = (php_com_saproxy_iter*)iter->data;
492: VARIANT v;
493: VARTYPE vt;
494: zval *return_value, **ptr_ptr;
495: SAFEARRAY *sa;
496:
497: I->indices[I->proxy->dimensions-1] = I->key;
498:
499: sa = V_ARRAY(&I->proxy->obj->v);
500:
501: if (FAILED(SafeArrayGetVartype(sa, &vt)) || vt == VT_EMPTY) {
502: vt = V_VT(&I->proxy->obj->v) & ~VT_ARRAY;
503: }
504:
505: VariantInit(&v);
506: if (vt == VT_VARIANT) {
507: SafeArrayGetElement(sa, I->indices, &v);
508: } else {
509: V_VT(&v) = vt;
510: SafeArrayGetElement(sa, I->indices, &v.lVal);
511: }
512:
513: MAKE_STD_ZVAL(return_value);
514: php_com_wrap_variant(return_value, &v, I->proxy->obj->code_page TSRMLS_CC);
515: VariantClear(&v);
516:
517: ptr_ptr = emalloc(sizeof(*ptr_ptr));
518: *ptr_ptr = return_value;
519: *data = ptr_ptr;
520: }
521:
522: static int saproxy_iter_get_key(zend_object_iterator *iter, char **str_key, uint *str_key_len,
523: ulong *int_key TSRMLS_DC)
524: {
525: php_com_saproxy_iter *I = (php_com_saproxy_iter*)iter->data;
526:
527: if (I->key == -1) {
528: return HASH_KEY_NON_EXISTANT;
529: }
530: *int_key = (ulong)I->key;
531: return HASH_KEY_IS_LONG;
532: }
533:
534: static int saproxy_iter_move_forwards(zend_object_iterator *iter TSRMLS_DC)
535: {
536: php_com_saproxy_iter *I = (php_com_saproxy_iter*)iter->data;
537:
538: if (++I->key >= I->imax) {
539: I->key = -1;
540: return FAILURE;
541: }
542: return SUCCESS;
543: }
544:
545: static zend_object_iterator_funcs saproxy_iter_funcs = {
546: saproxy_iter_dtor,
547: saproxy_iter_valid,
548: saproxy_iter_get_data,
549: saproxy_iter_get_key,
550: saproxy_iter_move_forwards,
551: NULL
552: };
553:
554:
555: zend_object_iterator *php_com_saproxy_iter_get(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC)
556: {
557: php_com_saproxy *proxy = SA_FETCH(object);
558: php_com_saproxy_iter *I;
559: int i;
560:
561: if (by_ref) {
562: zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
563: }
564:
565: I = ecalloc(1, sizeof(*I));
566: I->iter.funcs = &saproxy_iter_funcs;
567: I->iter.data = I;
568:
569: I->proxy = proxy;
570: I->proxy_obj = object;
571: Z_ADDREF_P(I->proxy_obj);
572:
573: I->indices = safe_emalloc(proxy->dimensions + 1, sizeof(LONG), 0);
574: for (i = 0; i < proxy->dimensions; i++) {
575: convert_to_long(proxy->indices[i]);
576: I->indices[i] = Z_LVAL_P(proxy->indices[i]);
577: }
578:
579: SafeArrayGetLBound(V_ARRAY(&proxy->obj->v), proxy->dimensions, &I->imin);
580: SafeArrayGetUBound(V_ARRAY(&proxy->obj->v), proxy->dimensions, &I->imax);
581:
582: I->key = I->imin;
583:
584: return &I->iter;
585: }
586:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>