root/ext/com_dotnet/com_saproxy.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. clone_indices
  2. saproxy_property_read
  3. saproxy_property_write
  4. saproxy_read_dimension
  5. saproxy_write_dimension
  6. saproxy_object_set
  7. saproxy_object_get
  8. saproxy_property_exists
  9. saproxy_dimension_exists
  10. saproxy_property_delete
  11. saproxy_dimension_delete
  12. saproxy_properties_get
  13. saproxy_method_get
  14. saproxy_call_method
  15. saproxy_constructor_get
  16. saproxy_class_name_get
  17. saproxy_objects_compare
  18. saproxy_object_cast
  19. saproxy_count_elements
  20. saproxy_free_storage
  21. saproxy_clone
  22. php_com_saproxy_create
  23. saproxy_iter_dtor
  24. saproxy_iter_valid
  25. saproxy_iter_get_data
  26. saproxy_iter_get_key
  27. saproxy_iter_move_forwards
  28. php_com_saproxy_iter_get

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 7                                                        |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1997-2016 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$ */
  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         zend_object std;
  41         /* the object we a proxying for; we hold a refcount to it */
  42         zval *zobj;
  43         php_com_dotnet_object *obj;
  44 
  45         /* how many dimensions we are indirecting to get into this element */
  46         LONG dimensions;
  47 
  48         /* this is an array whose size_is(dimensions) */
  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                 /* prop-get using first dimension as the property name,
 103                  * all subsequent dimensions and the offset as parameters */
 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                         /* return another proxy */
 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         /* the SafeArray case */
 135 
 136         /* offset/index must be an integer */
 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                 /* too many dimensions */
 144                 php_com_throw_exception(E_INVALIDARG, "too many dimensions!");
 145                 return rv;
 146         }
 147 
 148         /* bounds check */
 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                 /* we can return a real value */
 165                 indices = safe_emalloc(dims, sizeof(LONG), 0);
 166 
 167                 /* copy indices from proxy */
 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                 /* add user-supplied index */
 174                 indices[dims-1] = (LONG)Z_LVAL_P(offset);
 175 
 176                 /* now fetch the value */
 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                 /* return another proxy */
 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                 /* We do a prop-set using the first dimension as the property name,
 215                  * all subsequent dimensions and offset as parameters, with value as
 216                  * the final value */
 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                 /* copy indices from proxy */
 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                 /* add user-supplied index */
 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         /* Not yet implemented in the engine */
 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         /* no properties */
 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         /* no properties */
 316         return NULL;
 317 }
 318 
 319 static union _zend_function *saproxy_method_get(zend_object **object, zend_string *name, const zval *key)
 320 {
 321         /* no methods */
 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         /* user cannot instantiate */
 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 //???   int i;
 372 //???
 373 //???   for (i = 0; i < proxy->dimensions; i++) {
 374 //???           if (proxy->indices) {
 375 //???                           FREE_ZVAL(proxy->indices[i]);
 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, /* saproxy_object_get, */
 409         NULL, /* saproxy_object_set, */
 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 /* iterator */
 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 

/* [<][>][^][v][top][bottom][index][help] */