Annotation of embedaddon/php/ext/com_dotnet/com_saproxy.c, revision 1.1
1.1 ! misho 1: /*
! 2: +----------------------------------------------------------------------+
! 3: | PHP Version 5 |
! 4: +----------------------------------------------------------------------+
! 5: | Copyright (c) 1997-2012 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: com_saproxy.c 321634 2012-01-01 13:15:04Z felipe $ */
! 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:
! 74: static zval *saproxy_property_read(zval *object, zval *member, int type TSRMLS_DC)
! 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:
! 86: static void saproxy_property_write(zval *object, zval *member, zval *value TSRMLS_DC)
! 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:
! 296: static int saproxy_property_exists(zval *object, zval *member, int check_empty TSRMLS_DC)
! 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:
! 308: static void saproxy_property_delete(zval *object, zval *member TSRMLS_DC)
! 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:
! 324: static union _zend_function *saproxy_method_get(zval **object, char *name, int len TSRMLS_DC)
! 325: {
! 326: /* no methods */
! 327: return NULL;
! 328: }
! 329:
! 330: static int saproxy_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS)
! 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:
! 346: static int saproxy_class_name_get(const zval *object, char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC)
! 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>