root/ext/com_dotnet/com_variant.c

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

DEFINITIONS

This source file includes following definitions.
  1. safe_array_from_zval
  2. php_com_variant_from_zval
  3. php_com_zval_from_variant
  4. php_com_copy_variant
  5. PHP_FUNCTION
  6. PHP_FUNCTION
  7. variant_binary_operation
  8. PHP_FUNCTION
  9. PHP_FUNCTION
  10. PHP_FUNCTION
  11. PHP_FUNCTION
  12. PHP_FUNCTION
  13. PHP_FUNCTION
  14. PHP_FUNCTION
  15. PHP_FUNCTION
  16. PHP_FUNCTION
  17. PHP_FUNCTION
  18. PHP_FUNCTION
  19. PHP_FUNCTION
  20. PHP_FUNCTION
  21. variant_unary_operation
  22. PHP_FUNCTION
  23. PHP_FUNCTION
  24. PHP_FUNCTION
  25. PHP_FUNCTION
  26. PHP_FUNCTION
  27. PHP_FUNCTION
  28. PHP_FUNCTION
  29. PHP_FUNCTION
  30. PHP_FUNCTION
  31. PHP_FUNCTION
  32. PHP_FUNCTION
  33. PHP_FUNCTION

   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 #ifdef HAVE_CONFIG_H
  22 #include "config.h"
  23 #endif
  24 
  25 #include "php.h"
  26 #include "php_ini.h"
  27 #include "ext/standard/info.h"
  28 #include "php_com_dotnet.h"
  29 #include "php_com_dotnet_internal.h"
  30 
  31 /* create an automation SafeArray from a PHP array.
  32  * Only creates a single-dimensional array of variants.
  33  * The keys of the PHP hash MUST be numeric.  If the array
  34  * is sparse, then the gaps will be filled with NULL variants */
  35 static void safe_array_from_zval(VARIANT *v, zval *z, int codepage)
  36 {
  37         SAFEARRAY *sa = NULL;
  38         SAFEARRAYBOUND bound;
  39         HashPosition pos;
  40         int keytype;
  41         zend_string *strindex;
  42         zend_ulong intindex = 0;
  43         VARIANT *va;
  44         zval *item;
  45 
  46         /* find the largest array index, and assert that all keys are integers */
  47         zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(z), &pos);
  48         for (;; zend_hash_move_forward_ex(Z_ARRVAL_P(z), &pos)) {
  49 
  50                 keytype = zend_hash_get_current_key_ex(Z_ARRVAL_P(z), &strindex, &intindex, &pos);
  51 
  52                 if (HASH_KEY_IS_STRING == keytype) {
  53                         goto bogus;
  54                 } else if (HASH_KEY_NON_EXISTENT == keytype) {
  55                         break;
  56                 } else if (intindex > UINT_MAX) {
  57                         php_error_docref(NULL, E_WARNING, "COM: max number %u of elements in safe array exceeded", UINT_MAX);
  58                         break;
  59                 }
  60         }
  61 
  62         /* allocate the structure */
  63         bound.lLbound = 0;
  64         bound.cElements = zend_hash_num_elements(Z_ARRVAL_P(z));
  65         sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
  66 
  67         /* get a lock on the array itself */
  68         SafeArrayAccessData(sa, &va);
  69         va = (VARIANT*)sa->pvData;
  70 
  71         /* now fill it in */
  72         zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(z), &pos);
  73         for (;; zend_hash_move_forward_ex(Z_ARRVAL_P(z), &pos)) {
  74                 if (NULL == (item = zend_hash_get_current_data_ex(Z_ARRVAL_P(z), &pos))) {
  75                         break;
  76                 }
  77                 zend_hash_get_current_key_ex(Z_ARRVAL_P(z), &strindex, &intindex, &pos);
  78                 php_com_variant_from_zval(&va[intindex], item, codepage);
  79         }
  80 
  81         /* Unlock it and stuff it into our variant */
  82         SafeArrayUnaccessData(sa);
  83         V_VT(v) = VT_ARRAY|VT_VARIANT;
  84         V_ARRAY(v) = sa;
  85 
  86         return;
  87 
  88 bogus:
  89         php_error_docref(NULL, E_WARNING, "COM: converting from PHP array to VARIANT array; only arrays with numeric keys are allowed");
  90 
  91         V_VT(v) = VT_NULL;
  92 
  93         if (sa) {
  94                 SafeArrayUnlock(sa);
  95                 SafeArrayDestroy(sa);
  96         }
  97 }
  98 
  99 PHP_COM_DOTNET_API void php_com_variant_from_zval(VARIANT *v, zval *z, int codepage)
 100 {
 101         OLECHAR *olestring;
 102         php_com_dotnet_object *obj;
 103         zend_uchar ztype = (z == NULL ? IS_NULL : Z_TYPE_P(z));
 104 
 105         switch (ztype) {
 106                 case IS_NULL:
 107                         V_VT(v) = VT_NULL;
 108                         break;
 109 
 110                 case IS_FALSE:
 111                         V_VT(v) = VT_BOOL;
 112                         V_BOOL(v) = VARIANT_FALSE;
 113                         break;
 114 
 115                 case IS_TRUE:
 116                         V_VT(v) = VT_BOOL;
 117                         V_BOOL(v) = VARIANT_TRUE;
 118                         break;
 119 
 120                 case IS_OBJECT:
 121                         if (php_com_is_valid_object(z)) {
 122                                 obj = CDNO_FETCH(z);
 123                                 if (V_VT(&obj->v) == VT_DISPATCH) {
 124                                         /* pass the underlying object */
 125                                         V_VT(v) = VT_DISPATCH;
 126                                         if (V_DISPATCH(&obj->v)) {
 127                                                 IDispatch_AddRef(V_DISPATCH(&obj->v));
 128                                         }
 129                                         V_DISPATCH(v) = V_DISPATCH(&obj->v);
 130                                 } else {
 131                                         /* pass the variant by reference */
 132                                         V_VT(v) = VT_VARIANT | VT_BYREF;
 133                                         V_VARIANTREF(v) = &obj->v;
 134                                 }
 135                         } else {
 136                                 /* export the PHP object using our COM wrapper */
 137                                 V_VT(v) = VT_DISPATCH;
 138                                 V_DISPATCH(v) = php_com_wrapper_export(z);
 139                         }
 140                         break;
 141 
 142                 case IS_ARRAY:
 143                         /* map as safe array */
 144                         safe_array_from_zval(v, z, codepage);
 145                         break;
 146 
 147                 case IS_LONG:
 148 #if SIZEOF_ZEND_LONG == 4
 149                         V_VT(v) = VT_I4;
 150                         V_I4(v) = Z_LVAL_P(z);
 151 #else
 152                         V_VT(v) = VT_I8;
 153                         V_I8(v) = Z_LVAL_P(z);
 154 #endif
 155                         break;
 156 
 157                 case IS_DOUBLE:
 158                         V_VT(v) = VT_R8;
 159                         V_R8(v) = Z_DVAL_P(z);
 160                         break;
 161 
 162                 case IS_STRING:
 163                         V_VT(v) = VT_BSTR;
 164                         olestring = php_com_string_to_olestring(Z_STRVAL_P(z), Z_STRLEN_P(z), codepage);
 165                         if (CP_UTF8 == codepage) {
 166                                 V_BSTR(v) = SysAllocStringByteLen((char*)olestring, (UINT)(wcslen(olestring) * sizeof(OLECHAR)));
 167                         } else {
 168                                 V_BSTR(v) = SysAllocStringByteLen((char*)olestring, (UINT)(Z_STRLEN_P(z) * sizeof(OLECHAR)));
 169                         }
 170                         efree(olestring);
 171                         break;
 172 
 173                 case IS_RESOURCE:
 174                 case IS_CONSTANT:
 175                 case IS_CONSTANT_AST:
 176                 default:
 177                         V_VT(v) = VT_NULL;
 178                         break;
 179         }
 180 }
 181 
 182 PHP_COM_DOTNET_API int php_com_zval_from_variant(zval *z, VARIANT *v, int codepage)
 183 {
 184         OLECHAR *olestring = NULL;
 185         int ret = SUCCESS;
 186 
 187         switch (V_VT(v)) {
 188                 case VT_EMPTY:
 189                 case VT_NULL:
 190                 case VT_VOID:
 191                         ZVAL_NULL(z);
 192                         break;
 193                 case VT_UI1:
 194                         ZVAL_LONG(z, (zend_long)V_UI1(v));
 195                         break;
 196                 case VT_I1:
 197                         ZVAL_LONG(z, (zend_long)V_I1(v));
 198                         break;
 199                 case VT_UI2:
 200                         ZVAL_LONG(z, (zend_long)V_UI2(v));
 201                         break;
 202                 case VT_I2:
 203                         ZVAL_LONG(z, (zend_long)V_I2(v));
 204                         break;
 205                 case VT_UI4:  /* TODO: promote to double if large? */
 206                         ZVAL_LONG(z, (long)V_UI4(v));
 207                         break;
 208                 case VT_I4:
 209                         ZVAL_LONG(z, (long)V_I4(v));
 210                         break;
 211 #if SIZEOF_ZEND_LONG == 8
 212                 case VT_UI8:
 213                         ZVAL_LONG(z, (zend_long)V_UI8(v));
 214                         break;
 215                 case VT_I8:
 216                         ZVAL_LONG(z, (zend_long)V_I8(v));
 217                         break;
 218 #endif
 219                 case VT_INT:
 220                         ZVAL_LONG(z, V_INT(v));
 221                         break;
 222                 case VT_UINT: /* TODO: promote to double if large? */
 223                         ZVAL_LONG(z, (zend_long)V_UINT(v));
 224                         break;
 225                 case VT_R4:
 226                         ZVAL_DOUBLE(z, (double)V_R4(v));
 227                         break;
 228                 case VT_R8:
 229                         ZVAL_DOUBLE(z, V_R8(v));
 230                         break;
 231                 case VT_BOOL:
 232                         ZVAL_BOOL(z, V_BOOL(v) ? 1 : 0);
 233                         break;
 234                 case VT_BSTR:
 235                         olestring = V_BSTR(v);
 236                         if (olestring) {
 237                                 size_t len;
 238                                 char *str = php_com_olestring_to_string(olestring,
 239                                         &len, codepage);
 240                                 ZVAL_STRINGL(z, str, len);
 241                                 // TODO: avoid reallocation???
 242                                 efree(str);
 243                                 olestring = NULL;
 244                         }
 245                         break;
 246                 case VT_UNKNOWN:
 247                         if (V_UNKNOWN(v) != NULL) {
 248                                 IDispatch *disp;
 249 
 250                                 if (SUCCEEDED(IUnknown_QueryInterface(V_UNKNOWN(v), &IID_IDispatch, &disp))) {
 251                                         php_com_wrap_dispatch(z, disp, codepage);
 252                                         IDispatch_Release(disp);
 253                                 } else {
 254                                         ret = FAILURE;
 255                                 }
 256                         }
 257                         break;
 258 
 259                 case VT_DISPATCH:
 260                         if (V_DISPATCH(v) != NULL) {
 261                                 php_com_wrap_dispatch(z, V_DISPATCH(v), codepage);
 262                         }
 263                         break;
 264 
 265                 case VT_VARIANT:
 266                         /* points to another variant */
 267                         return php_com_zval_from_variant(z, V_VARIANTREF(v), codepage);
 268 
 269                 default:
 270                         php_com_wrap_variant(z, v, codepage);
 271         }
 272 
 273         if (olestring) {
 274                 efree(olestring);
 275         }
 276 
 277         if (ret == FAILURE) {
 278                 php_error_docref(NULL, E_WARNING, "variant->zval: conversion from 0x%x ret=%d", V_VT(v), ret);
 279         }
 280 
 281         return ret;
 282 }
 283 
 284 
 285 PHP_COM_DOTNET_API int php_com_copy_variant(VARIANT *dstvar, VARIANT *srcvar)
 286 {
 287         int ret = SUCCESS;
 288 
 289         switch (V_VT(dstvar) & ~VT_BYREF) {
 290         case VT_EMPTY:
 291         case VT_NULL:
 292         case VT_VOID:
 293                 /* should not be possible */
 294                 break;
 295 
 296         case VT_UI1:
 297                 if (V_VT(dstvar) & VT_BYREF) {
 298                         *V_UI1REF(dstvar) = V_UI1(srcvar);
 299                 } else {
 300                          V_UI1(dstvar) = V_UI1(srcvar);
 301                 }
 302                 break;
 303 
 304         case VT_I1:
 305                 if (V_VT(dstvar) & VT_BYREF) {
 306                         *V_I1REF(dstvar) = V_I1(srcvar);
 307                 } else {
 308                         V_I1(dstvar) = V_I1(srcvar);
 309                 }
 310                 break;
 311 
 312         case VT_UI2:
 313                 if (V_VT(dstvar) & VT_BYREF) {
 314                         *V_UI2REF(dstvar) = V_UI2(srcvar);
 315                 } else {
 316                         V_UI2(dstvar) = V_UI2(srcvar);
 317                 }
 318                 break;
 319 
 320         case VT_I2:
 321                 if (V_VT(dstvar) & VT_BYREF) {
 322                         *V_I2REF(dstvar) = V_I2(srcvar);
 323                 } else {
 324                         V_I2(dstvar) = V_I2(srcvar);
 325                 }
 326                 break;
 327 
 328         case VT_UI4:
 329                 if (V_VT(dstvar) & VT_BYREF) {
 330                         *V_UI4REF(dstvar) = V_UI4(srcvar);
 331                 } else {
 332                         V_UI4(dstvar) = V_UI4(srcvar);
 333                 }
 334                 break;
 335 
 336         case VT_I4:
 337                 if (V_VT(dstvar) & VT_BYREF) {
 338                         *V_I4REF(dstvar) = V_I4(srcvar);
 339                 } else {
 340                         V_I4(dstvar) = V_I4(srcvar);
 341                 }
 342                 break;
 343 #if SIZEOF_ZEND_LONG == 8
 344         case VT_UI8:
 345                 if (V_VT(dstvar) & VT_BYREF) {
 346                         *V_UI8REF(dstvar) = V_UI8(srcvar);
 347                 } else {
 348                         V_UI8(dstvar) = V_UI8(srcvar);
 349                 }
 350                 break;
 351 
 352         case VT_I8:
 353                 if (V_VT(dstvar) & VT_BYREF) {
 354                         *V_I8REF(dstvar) = V_I8(srcvar);
 355                 } else {
 356                         V_I8(dstvar) = V_I8(srcvar);
 357                 }
 358                 break;
 359 #endif
 360         case VT_INT:
 361                 if (V_VT(dstvar) & VT_BYREF) {
 362                         *V_INTREF(dstvar) = V_INT(srcvar);
 363                 } else {
 364                         V_INT(dstvar) = V_INT(srcvar);
 365                 }
 366                 break;
 367 
 368         case VT_UINT:
 369                 if (V_VT(dstvar) & VT_BYREF) {
 370                         *V_UINTREF(dstvar) = V_UINT(srcvar);
 371                 } else {
 372                         V_UINT(dstvar) = V_UINT(srcvar);
 373                 }
 374                 break;
 375 
 376         case VT_R4:
 377                 if (V_VT(dstvar) & VT_BYREF) {
 378                         *V_R4REF(dstvar) = V_R4(srcvar);
 379                 } else {
 380                         V_R4(dstvar) = V_R4(srcvar);
 381                 }
 382                 break;
 383 
 384         case VT_R8:
 385                 if (V_VT(dstvar) & VT_BYREF) {
 386                         *V_R8REF(dstvar) = V_R8(srcvar);
 387                 } else {
 388                         V_R8(dstvar) = V_R8(srcvar);
 389                 }
 390                 break;
 391 
 392         case VT_BOOL:
 393                 if (V_VT(dstvar) & VT_BYREF) {
 394                         *V_BOOLREF(dstvar) = V_BOOL(srcvar);
 395                 } else {
 396                         V_BOOL(dstvar) = V_BOOL(srcvar);
 397                 }
 398         break;
 399 
 400         case VT_BSTR:
 401                 if (V_VT(dstvar) & VT_BYREF) {
 402                         *V_BSTRREF(dstvar) = V_BSTR(srcvar);
 403                 } else {
 404                         V_BSTR(dstvar) = V_BSTR(srcvar);
 405         }
 406                 break;
 407 
 408         case VT_UNKNOWN:
 409                 if (V_VT(dstvar) & VT_BYREF) {
 410                         *V_UNKNOWNREF(dstvar) = V_UNKNOWN(srcvar);
 411                 } else {
 412                         V_UNKNOWN(dstvar) = V_UNKNOWN(srcvar);
 413                 }
 414                 break;
 415 
 416         case VT_DISPATCH:
 417                 if (V_VT(dstvar) & VT_BYREF) {
 418                         *V_DISPATCHREF(dstvar) = V_DISPATCH(srcvar);
 419                 } else {
 420                         V_DISPATCH(dstvar) = V_DISPATCH(srcvar);
 421                 }
 422                 break;
 423 
 424         case VT_VARIANT:
 425                 return php_com_copy_variant(V_VARIANTREF(dstvar), srcvar);
 426 
 427         default:
 428                 php_error_docref(NULL, E_WARNING, "variant->variant: failed to copy from 0x%x to 0x%x", V_VT(dstvar), V_VT(srcvar));
 429                 ret = FAILURE;
 430         }
 431         return ret;
 432 }
 433 
 434 /* {{{ com_variant_create_instance - ctor for new VARIANT() */
 435 PHP_FUNCTION(com_variant_create_instance)
 436 {
 437         /* VARTYPE == unsigned short */ zend_long vt = VT_EMPTY;
 438         zend_long codepage = CP_ACP;
 439         zval *object = getThis();
 440         php_com_dotnet_object *obj;
 441         zval *zvalue = NULL;
 442         HRESULT res;
 443 
 444         if (ZEND_NUM_ARGS() == 0) {
 445                 /* just leave things as-is - an empty variant */
 446                 return;
 447         }
 448 
 449         obj = CDNO_FETCH(object);
 450 
 451         if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(),
 452                 "z!|ll", &zvalue, &vt, &codepage)) {
 453                         php_com_throw_exception(E_INVALIDARG, "Invalid arguments");
 454                         return;
 455         }
 456 
 457         php_com_initialize();
 458         if (ZEND_NUM_ARGS() == 3) {
 459                 obj->code_page = (int)codepage;
 460         }
 461 
 462         if (zvalue) {
 463                 php_com_variant_from_zval(&obj->v, zvalue, obj->code_page);
 464         }
 465 
 466         /* Only perform conversion if variant not already of type passed */
 467         if ((ZEND_NUM_ARGS() >= 2) && (vt != V_VT(&obj->v))) {
 468 
 469                 /* If already an array and VT_ARRAY is passed then:
 470                         - if only VT_ARRAY passed then do not perform a conversion
 471                         - if VT_ARRAY plus other type passed then perform conversion
 472                           but will probably fail (original behavior)
 473                 */
 474                 if ((vt & VT_ARRAY) && (V_VT(&obj->v) & VT_ARRAY)) {
 475                         zend_long orig_vt = vt;
 476 
 477                         vt &= ~VT_ARRAY;
 478                         if (vt) {
 479                                 vt = orig_vt;
 480                         }
 481                 }
 482 
 483                 if (vt) {
 484                         res = VariantChangeType(&obj->v, &obj->v, 0, (VARTYPE)vt);
 485 
 486                         if (FAILED(res)) {
 487                                 char *werr, *msg;
 488 
 489                                 werr = php_win32_error_to_msg(res);
 490                                 spprintf(&msg, 0, "Variant type conversion failed: %s", werr);
 491                                 LocalFree(werr);
 492 
 493                                 php_com_throw_exception(res, msg);
 494                                 efree(msg);
 495                         }
 496                 }
 497         }
 498 
 499         if (V_VT(&obj->v) != VT_DISPATCH && obj->typeinfo) {
 500                 ITypeInfo_Release(obj->typeinfo);
 501                 obj->typeinfo = NULL;
 502         }
 503 }
 504 /* }}} */
 505 
 506 /* {{{ proto void variant_set(object variant, mixed value)
 507    Assigns a new value for a variant object */
 508 PHP_FUNCTION(variant_set)
 509 {
 510         zval *zobj, *zvalue = NULL;
 511         php_com_dotnet_object *obj;
 512 
 513         if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(),
 514                         "Oz!", &zobj, php_com_variant_class_entry, &zvalue)) {
 515                 return;
 516         }
 517 
 518         obj = CDNO_FETCH(zobj);
 519 
 520         /* dtor the old value */
 521         if (obj->typeinfo) {
 522                 ITypeInfo_Release(obj->typeinfo);
 523                 obj->typeinfo = NULL;
 524         }
 525         if (obj->sink_dispatch) {
 526                 php_com_object_enable_event_sink(obj, FALSE);
 527                 IDispatch_Release(obj->sink_dispatch);
 528                 obj->sink_dispatch = NULL;
 529         }
 530 
 531         VariantClear(&obj->v);
 532 
 533         php_com_variant_from_zval(&obj->v, zvalue, obj->code_page);
 534         /* remember we modified this variant */
 535         obj->modified = 1;
 536 }
 537 /* }}} */
 538 
 539 enum variant_binary_opcode {
 540         VOP_ADD, VOP_CAT, VOP_SUB, VOP_MUL, VOP_AND, VOP_DIV,
 541         VOP_EQV, VOP_IDIV, VOP_IMP, VOP_MOD, VOP_OR, VOP_POW,
 542         VOP_XOR
 543 };
 544 
 545 enum variant_unary_opcode {
 546         VOP_ABS, VOP_FIX, VOP_INT, VOP_NEG, VOP_NOT
 547 };
 548 
 549 static void variant_binary_operation(enum variant_binary_opcode op, INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
 550 {
 551         VARIANT vres;
 552         VARIANT left_val, right_val;
 553         VARIANT *vleft = NULL, *vright = NULL;
 554         zval *zleft = NULL, *zright = NULL;
 555         php_com_dotnet_object *obj;
 556         HRESULT result;
 557         int codepage = CP_ACP;
 558 
 559         VariantInit(&left_val);
 560         VariantInit(&right_val);
 561         VariantInit(&vres);
 562 
 563         if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
 564                         ZEND_NUM_ARGS(), "OO", &zleft, php_com_variant_class_entry,
 565                         &zright, php_com_variant_class_entry)) {
 566                 obj = CDNO_FETCH(zleft);
 567                 vleft = &obj->v;
 568                 obj = CDNO_FETCH(zright);
 569                 vright = &obj->v;
 570         } else if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
 571                         ZEND_NUM_ARGS(), "Oz!", &zleft, php_com_variant_class_entry,
 572                         &zright)) {
 573                 obj = CDNO_FETCH(zleft);
 574                 vleft = &obj->v;
 575                 vright = &right_val;
 576                 php_com_variant_from_zval(vright, zright, codepage);
 577         } else if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
 578                         ZEND_NUM_ARGS(), "z!O", &zleft, &zright, php_com_variant_class_entry)) {
 579                 obj = CDNO_FETCH(zright);
 580                 vright = &obj->v;
 581                 vleft = &left_val;
 582                 php_com_variant_from_zval(vleft, zleft, codepage);
 583         } else if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(),
 584                         "z!z!", &zleft, &zright)) {
 585 
 586                 vleft = &left_val;
 587                 php_com_variant_from_zval(vleft, zleft, codepage);
 588 
 589                 vright = &right_val;
 590                 php_com_variant_from_zval(vright, zright, codepage);
 591 
 592         } else {
 593                 return;
 594         }
 595 
 596         switch (op) {
 597                 case VOP_ADD:
 598                         result = VarAdd(vleft, vright, &vres);
 599                         break;
 600                 case VOP_CAT:
 601                         result = VarCat(vleft, vright, &vres);
 602                         break;
 603                 case VOP_SUB:
 604                         result = VarSub(vleft, vright, &vres);
 605                         break;
 606                 case VOP_MUL:
 607                         result = VarMul(vleft, vright, &vres);
 608                         break;
 609                 case VOP_AND:
 610                         result = VarAnd(vleft, vright, &vres);
 611                         break;
 612                 case VOP_DIV:
 613                         result = VarDiv(vleft, vright, &vres);
 614                         break;
 615                 case VOP_EQV:
 616                         result = VarEqv(vleft, vright, &vres);
 617                         break;
 618                 case VOP_IDIV:
 619                         result = VarIdiv(vleft, vright, &vres);
 620                         break;
 621                 case VOP_IMP:
 622                         result = VarImp(vleft, vright, &vres);
 623                         break;
 624                 case VOP_MOD:
 625                         result = VarMod(vleft, vright, &vres);
 626                         break;
 627                 case VOP_OR:
 628                         result = VarOr(vleft, vright, &vres);
 629                         break;
 630                 case VOP_POW:
 631                         result = VarPow(vleft, vright, &vres);
 632                         break;
 633                 case VOP_XOR:
 634                         result = VarXor(vleft, vright, &vres);
 635                         break;
 636                 /*Let say it fails as no valid op has been given */
 637                 default:
 638                         result = E_INVALIDARG;
 639         }
 640 
 641         if (SUCCEEDED(result)) {
 642                 php_com_wrap_variant(return_value, &vres, codepage);
 643         } else {
 644                 php_com_throw_exception(result, NULL);
 645         }
 646 
 647         VariantClear(&vres);
 648         VariantClear(&left_val);
 649         VariantClear(&right_val);
 650 }
 651 /* }}} */
 652 
 653 /* {{{ proto mixed variant_add(mixed left, mixed right)
 654    "Adds" two variant values together and returns the result */
 655 PHP_FUNCTION(variant_add)
 656 {
 657         variant_binary_operation(VOP_ADD, INTERNAL_FUNCTION_PARAM_PASSTHRU);
 658 }
 659 /* }}} */
 660 
 661 /* {{{ proto mixed variant_cat(mixed left, mixed right)
 662    concatenates two variant values together and returns the result */
 663 PHP_FUNCTION(variant_cat)
 664 {
 665         variant_binary_operation(VOP_CAT, INTERNAL_FUNCTION_PARAM_PASSTHRU);
 666 }
 667 /* }}} */
 668 
 669 /* {{{ proto mixed variant_sub(mixed left, mixed right)
 670    subtracts the value of the right variant from the left variant value and returns the result */
 671 PHP_FUNCTION(variant_sub)
 672 {
 673         variant_binary_operation(VOP_SUB, INTERNAL_FUNCTION_PARAM_PASSTHRU);
 674 }
 675 /* }}} */
 676 
 677 /* {{{ proto mixed variant_mul(mixed left, mixed right)
 678    multiplies the values of the two variants and returns the result */
 679 PHP_FUNCTION(variant_mul)
 680 {
 681         variant_binary_operation(VOP_MUL, INTERNAL_FUNCTION_PARAM_PASSTHRU);
 682 }
 683 /* }}} */
 684 
 685 /* {{{ proto mixed variant_and(mixed left, mixed right)
 686    performs a bitwise AND operation between two variants and returns the result */
 687 PHP_FUNCTION(variant_and)
 688 {
 689         variant_binary_operation(VOP_AND, INTERNAL_FUNCTION_PARAM_PASSTHRU);
 690 }
 691 /* }}} */
 692 
 693 /* {{{ proto mixed variant_div(mixed left, mixed right)
 694    Returns the result from dividing two variants */
 695 PHP_FUNCTION(variant_div)
 696 {
 697         variant_binary_operation(VOP_DIV, INTERNAL_FUNCTION_PARAM_PASSTHRU);
 698 }
 699 /* }}} */
 700 
 701 /* {{{ proto mixed variant_eqv(mixed left, mixed right)
 702    Performs a bitwise equivalence on two variants */
 703 PHP_FUNCTION(variant_eqv)
 704 {
 705         variant_binary_operation(VOP_EQV, INTERNAL_FUNCTION_PARAM_PASSTHRU);
 706 }
 707 /* }}} */
 708 
 709 /* {{{ proto mixed variant_idiv(mixed left, mixed right)
 710    Converts variants to integers and then returns the result from dividing them */
 711 PHP_FUNCTION(variant_idiv)
 712 {
 713         variant_binary_operation(VOP_IDIV, INTERNAL_FUNCTION_PARAM_PASSTHRU);
 714 }
 715 /* }}} */
 716 
 717 /* {{{ proto mixed variant_imp(mixed left, mixed right)
 718    Performs a bitwise implication on two variants */
 719 PHP_FUNCTION(variant_imp)
 720 {
 721         variant_binary_operation(VOP_IMP, INTERNAL_FUNCTION_PARAM_PASSTHRU);
 722 }
 723 /* }}} */
 724 
 725 /* {{{ proto mixed variant_mod(mixed left, mixed right)
 726    Divides two variants and returns only the remainder */
 727 PHP_FUNCTION(variant_mod)
 728 {
 729         variant_binary_operation(VOP_MOD, INTERNAL_FUNCTION_PARAM_PASSTHRU);
 730 }
 731 /* }}} */
 732 
 733 /* {{{ proto mixed variant_or(mixed left, mixed right)
 734    Performs a logical disjunction on two variants */
 735 PHP_FUNCTION(variant_or)
 736 {
 737         variant_binary_operation(VOP_OR, INTERNAL_FUNCTION_PARAM_PASSTHRU);
 738 }
 739 /* }}} */
 740 
 741 /* {{{ proto mixed variant_pow(mixed left, mixed right)
 742    Returns the result of performing the power function with two variants */
 743 PHP_FUNCTION(variant_pow)
 744 {
 745         variant_binary_operation(VOP_POW, INTERNAL_FUNCTION_PARAM_PASSTHRU);
 746 }
 747 /* }}} */
 748 
 749 /* {{{ proto mixed variant_xor(mixed left, mixed right)
 750    Performs a logical exclusion on two variants */
 751 PHP_FUNCTION(variant_xor)
 752 {
 753         variant_binary_operation(VOP_XOR, INTERNAL_FUNCTION_PARAM_PASSTHRU);
 754 }
 755 /* }}} */
 756 
 757 static void variant_unary_operation(enum variant_unary_opcode op, INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
 758 {
 759         VARIANT vres;
 760         VARIANT left_val;
 761         VARIANT *vleft = NULL;
 762         zval *zleft = NULL;
 763         php_com_dotnet_object *obj;
 764         HRESULT result;
 765         int codepage = CP_ACP;
 766 
 767         VariantInit(&left_val);
 768         VariantInit(&vres);
 769 
 770         if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
 771                         ZEND_NUM_ARGS(), "O", &zleft, php_com_variant_class_entry)) {
 772                 obj = CDNO_FETCH(zleft);
 773                 vleft = &obj->v;
 774         } else if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(),
 775                         "z!", &zleft)) {
 776                 vleft = &left_val;
 777                 php_com_variant_from_zval(vleft, zleft, codepage);
 778         } else {
 779                 return;
 780         }
 781 
 782         switch (op) {
 783                 case VOP_ABS:
 784                         result = VarAbs(vleft, &vres);
 785                         break;
 786                 case VOP_FIX:
 787                         result = VarFix(vleft, &vres);
 788                         break;
 789                 case VOP_INT:
 790                         result = VarInt(vleft, &vres);
 791                         break;
 792                 case VOP_NEG:
 793                         result = VarNeg(vleft, &vres);
 794                         break;
 795                 case VOP_NOT:
 796                         result = VarNot(vleft, &vres);
 797                         break;
 798                 default:
 799                         result = E_INVALIDARG;
 800         }
 801 
 802         if (SUCCEEDED(result)) {
 803                 php_com_wrap_variant(return_value, &vres, codepage);
 804         } else {
 805                 php_com_throw_exception(result, NULL);
 806         }
 807 
 808         VariantClear(&vres);
 809         VariantClear(&left_val);
 810 }
 811 /* }}} */
 812 
 813 /* {{{ proto mixed variant_abs(mixed left)
 814    Returns the absolute value of a variant */
 815 PHP_FUNCTION(variant_abs)
 816 {
 817         variant_unary_operation(VOP_ABS, INTERNAL_FUNCTION_PARAM_PASSTHRU);
 818 }
 819 /* }}} */
 820 
 821 /* {{{ proto mixed variant_fix(mixed left)
 822    Returns the integer part ? of a variant */
 823 PHP_FUNCTION(variant_fix)
 824 {
 825         variant_unary_operation(VOP_FIX, INTERNAL_FUNCTION_PARAM_PASSTHRU);
 826 }
 827 /* }}} */
 828 
 829 /* {{{ proto mixed variant_int(mixed left)
 830    Returns the integer portion of a variant */
 831 PHP_FUNCTION(variant_int)
 832 {
 833         variant_unary_operation(VOP_INT, INTERNAL_FUNCTION_PARAM_PASSTHRU);
 834 }
 835 /* }}} */
 836 
 837 /* {{{ proto mixed variant_neg(mixed left)
 838    Performs logical negation on a variant */
 839 PHP_FUNCTION(variant_neg)
 840 {
 841         variant_unary_operation(VOP_NEG, INTERNAL_FUNCTION_PARAM_PASSTHRU);
 842 }
 843 /* }}} */
 844 
 845 /* {{{ proto mixed variant_not(mixed left)
 846    Performs bitwise not negation on a variant */
 847 PHP_FUNCTION(variant_not)
 848 {
 849         variant_unary_operation(VOP_NOT, INTERNAL_FUNCTION_PARAM_PASSTHRU);
 850 }
 851 /* }}} */
 852 
 853 /* {{{ proto mixed variant_round(mixed left, int decimals)
 854    Rounds a variant to the specified number of decimal places */
 855 PHP_FUNCTION(variant_round)
 856 {
 857         VARIANT vres;
 858         VARIANT left_val;
 859         VARIANT *vleft = NULL;
 860         zval *zleft = NULL;
 861         php_com_dotnet_object *obj;
 862         int codepage = CP_ACP;
 863         zend_long decimals = 0;
 864 
 865         VariantInit(&left_val);
 866         VariantInit(&vres);
 867 
 868         if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
 869                         ZEND_NUM_ARGS(), "Ol", &zleft, php_com_variant_class_entry, &decimals)) {
 870                 obj = CDNO_FETCH(zleft);
 871                 vleft = &obj->v;
 872         } else if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(),
 873                         "z!l", &zleft, &decimals)) {
 874                 vleft = &left_val;
 875                 php_com_variant_from_zval(vleft, zleft, codepage);
 876         } else {
 877                 return;
 878         }
 879 
 880         if (SUCCEEDED(VarRound(vleft, (int)decimals, &vres))) {
 881                 php_com_wrap_variant(return_value, &vres, codepage);
 882         }
 883 
 884         VariantClear(&vres);
 885         VariantClear(&left_val);
 886 }
 887 /* }}} */
 888 
 889 /* {{{ proto int variant_cmp(mixed left, mixed right [, int lcid [, int flags]])
 890    Compares two variants */
 891 PHP_FUNCTION(variant_cmp)
 892 {
 893         VARIANT left_val, right_val;
 894         VARIANT *vleft = NULL, *vright = NULL;
 895         zval *zleft = NULL, *zright = NULL;
 896         php_com_dotnet_object *obj;
 897         int codepage = CP_ACP;
 898         zend_long lcid = LOCALE_SYSTEM_DEFAULT;
 899         zend_long flags = 0;
 900         /* it is safe to ignore the warning for this line; see the comments in com_handlers.c */
 901         STDAPI VarCmp(LPVARIANT pvarLeft, LPVARIANT pvarRight, LCID lcid, DWORD flags);
 902 
 903         VariantInit(&left_val);
 904         VariantInit(&right_val);
 905 
 906         if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
 907                         ZEND_NUM_ARGS(), "OO|ll", &zleft, php_com_variant_class_entry,
 908                         &zright, php_com_variant_class_entry, &lcid, &flags)) {
 909                 obj = CDNO_FETCH(zleft);
 910                 vleft = &obj->v;
 911                 obj = CDNO_FETCH(zright);
 912                 vright = &obj->v;
 913         } else if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
 914                         ZEND_NUM_ARGS(), "Oz!|ll", &zleft, php_com_variant_class_entry,
 915                         &zright, &lcid, &flags)) {
 916                 obj = CDNO_FETCH(zleft);
 917                 vleft = &obj->v;
 918                 vright = &right_val;
 919                 php_com_variant_from_zval(vright, zright, codepage);
 920         } else if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
 921                         ZEND_NUM_ARGS(), "z!O|ll", &zleft, &zright, php_com_variant_class_entry,
 922                         &lcid, &flags)) {
 923                 obj = CDNO_FETCH(zright);
 924                 vright = &obj->v;
 925                 vleft = &left_val;
 926                 php_com_variant_from_zval(vleft, zleft, codepage);
 927         } else if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(),
 928                         "z!z!|ll", &zleft, &zright, &lcid, &flags)) {
 929 
 930                 vleft = &left_val;
 931                 php_com_variant_from_zval(vleft, zleft, codepage);
 932 
 933                 vright = &right_val;
 934                 php_com_variant_from_zval(vright, zright, codepage);
 935 
 936         } else {
 937                 return;
 938         }
 939 
 940         ZVAL_LONG(return_value, VarCmp(vleft, vright, (LCID)lcid, (ULONG)flags));
 941 
 942         VariantClear(&left_val);
 943         VariantClear(&right_val);
 944 }
 945 /* }}} */
 946 
 947 /* {{{ proto int variant_date_to_timestamp(object variant)
 948    Converts a variant date/time value to unix timestamp */
 949 PHP_FUNCTION(variant_date_to_timestamp)
 950 {
 951         VARIANT vres;
 952         zval *zleft = NULL;
 953         php_com_dotnet_object *obj;
 954 
 955         VariantInit(&vres);
 956 
 957         if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(),
 958                 "O", &zleft, php_com_variant_class_entry)) {
 959                 return;
 960         }
 961         obj = CDNO_FETCH(zleft);
 962 
 963         if (SUCCEEDED(VariantChangeType(&vres, &obj->v, 0, VT_DATE))) {
 964                 SYSTEMTIME systime;
 965                 struct tm tmv;
 966 
 967                 VariantTimeToSystemTime(V_DATE(&vres), &systime);
 968 
 969                 memset(&tmv, 0, sizeof(tmv));
 970                 tmv.tm_year = systime.wYear - 1900;
 971                 tmv.tm_mon = systime.wMonth - 1;
 972                 tmv.tm_mday = systime.wDay;
 973                 tmv.tm_hour = systime.wHour;
 974                 tmv.tm_min = systime.wMinute;
 975                 tmv.tm_sec = systime.wSecond;
 976                 tmv.tm_isdst = -1;
 977 
 978                 tzset();
 979                 RETVAL_LONG(mktime(&tmv));
 980         }
 981 
 982         VariantClear(&vres);
 983 }
 984 /* }}} */
 985 
 986 /* {{{ proto object variant_date_from_timestamp(int timestamp)
 987    Returns a variant date representation of a unix timestamp */
 988 PHP_FUNCTION(variant_date_from_timestamp)
 989 {
 990         zend_long timestamp;
 991         time_t ttstamp;
 992         SYSTEMTIME systime;
 993         struct tm *tmv;
 994         VARIANT res;
 995 
 996         if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "l",
 997                         &timestamp)) {
 998                 return;
 999         }
1000 
1001         if (timestamp < 0) {
1002                 php_error_docref(NULL, E_WARNING, "Timestamp value must be a positive value.");
1003                 RETURN_FALSE;
1004         }
1005 
1006         VariantInit(&res);
1007         tzset();
1008         ttstamp = timestamp;
1009         tmv = localtime(&ttstamp);
1010         memset(&systime, 0, sizeof(systime));
1011 
1012         systime.wDay = tmv->tm_mday;
1013         systime.wHour = tmv->tm_hour;
1014         systime.wMinute = tmv->tm_min;
1015         systime.wMonth = tmv->tm_mon + 1;
1016         systime.wSecond = tmv->tm_sec;
1017         systime.wYear = tmv->tm_year + 1900;
1018 
1019         V_VT(&res) = VT_DATE;
1020         SystemTimeToVariantTime(&systime, &V_DATE(&res));
1021 
1022         php_com_wrap_variant(return_value, &res, CP_ACP);
1023 
1024         VariantClear(&res);
1025 }
1026 /* }}} */
1027 
1028 /* {{{ proto int variant_get_type(object variant)
1029    Returns the VT_XXX type code for a variant */
1030 PHP_FUNCTION(variant_get_type)
1031 {
1032         zval *zobj;
1033         php_com_dotnet_object *obj;
1034 
1035         if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(),
1036                 "O", &zobj, php_com_variant_class_entry)) {
1037                 return;
1038         }
1039         obj = CDNO_FETCH(zobj);
1040 
1041         RETURN_LONG(V_VT(&obj->v));
1042 }
1043 /* }}} */
1044 
1045 /* {{{ proto void variant_set_type(object variant, int type)
1046    Convert a variant into another type.  Variant is modified "in-place" */
1047 PHP_FUNCTION(variant_set_type)
1048 {
1049         zval *zobj;
1050         php_com_dotnet_object *obj;
1051         /* VARTYPE == unsigned short */ zend_long vt;
1052         HRESULT res;
1053 
1054         if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(),
1055                 "Ol", &zobj, php_com_variant_class_entry, &vt)) {
1056                 return;
1057         }
1058         obj = CDNO_FETCH(zobj);
1059 
1060         res = VariantChangeType(&obj->v, &obj->v, 0, (VARTYPE)vt);
1061 
1062         if (SUCCEEDED(res)) {
1063                 if (vt != VT_DISPATCH && obj->typeinfo) {
1064                         ITypeInfo_Release(obj->typeinfo);
1065                         obj->typeinfo = NULL;
1066                 }
1067         } else {
1068                 char *werr, *msg;
1069 
1070                 werr = php_win32_error_to_msg(res);
1071                 spprintf(&msg, 0, "Variant type conversion failed: %s", werr);
1072                 LocalFree(werr);
1073 
1074                 php_com_throw_exception(res, msg);
1075                 efree(msg);
1076         }
1077 }
1078 /* }}} */
1079 
1080 /* {{{ proto object variant_cast(object variant, int type)
1081    Convert a variant into a new variant object of another type */
1082 PHP_FUNCTION(variant_cast)
1083 {
1084         zval *zobj;
1085         php_com_dotnet_object *obj;
1086         /* VARTYPE == unsigned short */ zend_long vt;
1087         VARIANT vres;
1088         HRESULT res;
1089 
1090         if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(),
1091                 "Ol", &zobj, php_com_variant_class_entry, &vt)) {
1092                 return;
1093         }
1094         obj = CDNO_FETCH(zobj);
1095 
1096         VariantInit(&vres);
1097         res = VariantChangeType(&vres, &obj->v, 0, (VARTYPE)vt);
1098 
1099         if (SUCCEEDED(res)) {
1100                 php_com_wrap_variant(return_value, &vres, obj->code_page);
1101         } else {
1102                 char *werr, *msg;
1103 
1104                 werr = php_win32_error_to_msg(res);
1105                 spprintf(&msg, 0, "Variant type conversion failed: %s", werr);
1106                 LocalFree(werr);
1107 
1108                 php_com_throw_exception(res, msg);
1109                 efree(msg);
1110         }
1111 
1112         VariantClear(&vres);
1113 }
1114 /* }}} */
1115 

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