Back to index

php5  5.3.10
com_variant.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Author: Wez Furlong <wez@thebrainroom.com>                           |
00016    +----------------------------------------------------------------------+
00017  */
00018 
00019 /* $Id: com_variant.c 321634 2012-01-01 13:15:04Z felipe $ */
00020 
00021 #ifdef HAVE_CONFIG_H
00022 #include "config.h"
00023 #endif
00024 
00025 #include "php.h"
00026 #include "php_ini.h"
00027 #include "ext/standard/info.h"
00028 #include "php_com_dotnet.h"
00029 #include "php_com_dotnet_internal.h"
00030 
00031 /* create an automation SafeArray from a PHP array.
00032  * Only creates a single-dimensional array of variants.
00033  * The keys of the PHP hash MUST be numeric.  If the array
00034  * is sparse, then the gaps will be filled with NULL variants */
00035 static void safe_array_from_zval(VARIANT *v, zval *z, int codepage TSRMLS_DC)
00036 {
00037        SAFEARRAY *sa = NULL;
00038        SAFEARRAYBOUND bound;
00039        HashPosition pos;
00040        int keytype;
00041        char *strindex;
00042        int strindexlen;
00043        long intindex = -1;
00044        long max_index = 0;
00045        VARIANT *va;
00046        zval **item;
00047               
00048        /* find the largest array index, and assert that all keys are integers */
00049        zend_hash_internal_pointer_reset_ex(HASH_OF(z), &pos);
00050        for (;; zend_hash_move_forward_ex(HASH_OF(z), &pos)) {
00051 
00052               keytype = zend_hash_get_current_key_ex(HASH_OF(z), &strindex, &strindexlen, &intindex, 0, &pos);
00053 
00054               if (HASH_KEY_IS_STRING == keytype) {
00055                      goto bogus;
00056               } else if (HASH_KEY_NON_EXISTANT == keytype) {
00057                      break;
00058               }
00059               if (intindex > max_index) {
00060                      max_index = intindex;
00061               }
00062        }
00063 
00064        /* allocate the structure */       
00065        bound.lLbound = 0;
00066        bound.cElements = intindex + 1;
00067        sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
00068 
00069        /* get a lock on the array itself */
00070        SafeArrayAccessData(sa, &va);
00071        va = (VARIANT*)sa->pvData;
00072        
00073        /* now fill it in */
00074        zend_hash_internal_pointer_reset_ex(HASH_OF(z), &pos);
00075        for (;; zend_hash_move_forward_ex(HASH_OF(z), &pos)) {
00076               if (FAILURE == zend_hash_get_current_data_ex(HASH_OF(z), (void**)&item, &pos)) {
00077                      break;
00078               }
00079               zend_hash_get_current_key_ex(HASH_OF(z), &strindex, &strindexlen, &intindex, 0, &pos);
00080               php_com_variant_from_zval(&va[intindex], *item, codepage TSRMLS_CC);         
00081        }
00082 
00083        /* Unlock it and stuff it into our variant */
00084        SafeArrayUnaccessData(sa);
00085        V_VT(v) = VT_ARRAY|VT_VARIANT;
00086        V_ARRAY(v) = sa;
00087 
00088        return;
00089 
00090 bogus:
00091        php_error_docref(NULL TSRMLS_CC, E_WARNING, "COM: converting from PHP array to VARIANT array; only arrays with numeric keys are allowed");
00092 
00093        V_VT(v) = VT_NULL;
00094 
00095        if (sa) {
00096               SafeArrayUnlock(sa);
00097               SafeArrayDestroy(sa);
00098        }
00099 }
00100 
00101 PHPAPI void php_com_variant_from_zval(VARIANT *v, zval *z, int codepage TSRMLS_DC)
00102 {
00103        OLECHAR *olestring;
00104        php_com_dotnet_object *obj;
00105        
00106        switch (Z_TYPE_P(z)) {
00107               case IS_NULL:
00108                      V_VT(v) = VT_NULL;
00109                      break;
00110 
00111               case IS_BOOL:
00112                      V_VT(v) = VT_BOOL;
00113                      V_BOOL(v) = Z_BVAL_P(z) ? VARIANT_TRUE : VARIANT_FALSE;
00114                      break;
00115 
00116               case IS_OBJECT:
00117                      if (php_com_is_valid_object(z TSRMLS_CC)) {
00118                             obj = CDNO_FETCH(z);
00119                             if (V_VT(&obj->v) == VT_DISPATCH) {
00120                                    /* pass the underlying object */
00121                                    V_VT(v) = VT_DISPATCH;
00122                                    if (V_DISPATCH(&obj->v)) {
00123                                           IDispatch_AddRef(V_DISPATCH(&obj->v));
00124                                    }
00125                                    V_DISPATCH(v) = V_DISPATCH(&obj->v);
00126                             } else {
00127                                    /* pass the variant by reference */
00128                                    V_VT(v) = VT_VARIANT | VT_BYREF;
00129                                    V_VARIANTREF(v) = &obj->v;
00130                             }
00131                      } else {
00132                             /* export the PHP object using our COM wrapper */
00133                             V_VT(v) = VT_DISPATCH;
00134                             V_DISPATCH(v) = php_com_wrapper_export(z TSRMLS_CC);
00135                      }
00136                      break;
00137                      
00138               case IS_ARRAY:
00139                      /* map as safe array */
00140                      safe_array_from_zval(v, z, codepage TSRMLS_CC);
00141                      break;
00142 
00143               case IS_LONG:
00144                      V_VT(v) = VT_I4;
00145                      V_I4(v) = Z_LVAL_P(z);
00146                      break;
00147 
00148               case IS_DOUBLE:
00149                      V_VT(v) = VT_R8;
00150                      V_R8(v) = Z_DVAL_P(z);
00151                      break;
00152 
00153               case IS_STRING:
00154                      V_VT(v) = VT_BSTR;
00155                      olestring = php_com_string_to_olestring(Z_STRVAL_P(z), Z_STRLEN_P(z), codepage TSRMLS_CC);
00156                      V_BSTR(v) = SysAllocStringByteLen((char*)olestring, Z_STRLEN_P(z) * sizeof(OLECHAR));
00157                      efree(olestring);
00158                      break;
00159 
00160               case IS_RESOURCE:
00161               case IS_CONSTANT:
00162               case IS_CONSTANT_ARRAY:
00163               default:
00164                      V_VT(v) = VT_NULL;
00165                      break;
00166        }
00167 }
00168 
00169 PHPAPI int php_com_zval_from_variant(zval *z, VARIANT *v, int codepage TSRMLS_DC)
00170 {
00171        OLECHAR *olestring = NULL;
00172        int ret = SUCCESS;
00173 
00174        switch (V_VT(v)) {
00175               case VT_EMPTY:
00176               case VT_NULL:
00177               case VT_VOID:
00178                      ZVAL_NULL(z);
00179                      break;
00180               case VT_UI1:
00181                      ZVAL_LONG(z, (long)V_UI1(v));
00182                      break;
00183               case VT_I1:
00184                      ZVAL_LONG(z, (long)V_I1(v));
00185                      break;
00186               case VT_UI2:
00187                      ZVAL_LONG(z, (long)V_UI2(v));
00188                      break;
00189               case VT_I2:
00190                      ZVAL_LONG(z, (long)V_I2(v));
00191                      break;
00192               case VT_UI4:  /* TODO: promote to double if large? */
00193                      ZVAL_LONG(z, (long)V_UI4(v));
00194                      break;
00195               case VT_I4:
00196                      ZVAL_LONG(z, (long)V_I4(v));
00197                      break;
00198               case VT_INT:
00199                      ZVAL_LONG(z, V_INT(v));
00200                      break;
00201               case VT_UINT: /* TODO: promote to double if large? */
00202                      ZVAL_LONG(z, (long)V_UINT(v));
00203                      break;
00204               case VT_R4:
00205                      ZVAL_DOUBLE(z, (double)V_R4(v));
00206                      break;
00207               case VT_R8:
00208                      ZVAL_DOUBLE(z, V_R8(v));
00209                      break;
00210               case VT_BOOL:
00211                      ZVAL_BOOL(z, V_BOOL(v) ? 1 : 0);
00212                      break;
00213               case VT_BSTR:
00214                      olestring = V_BSTR(v);
00215                      if (olestring) {
00216                             Z_TYPE_P(z) = IS_STRING;
00217                             Z_STRVAL_P(z) = php_com_olestring_to_string(olestring,
00218                                    &Z_STRLEN_P(z), codepage TSRMLS_CC);
00219                             olestring = NULL;
00220                      }
00221                      break;
00222               case VT_UNKNOWN:
00223                      if (V_UNKNOWN(v) != NULL) {
00224                             IDispatch *disp;
00225 
00226                             if (SUCCEEDED(IUnknown_QueryInterface(V_UNKNOWN(v), &IID_IDispatch, &disp))) {
00227                                    php_com_wrap_dispatch(z, disp, codepage TSRMLS_CC);
00228                                    IDispatch_Release(disp);
00229                             } else {
00230                                    ret = FAILURE;
00231                             }
00232                      }
00233                      break;
00234 
00235               case VT_DISPATCH:
00236                      if (V_DISPATCH(v) != NULL) {
00237                             php_com_wrap_dispatch(z, V_DISPATCH(v), codepage TSRMLS_CC);
00238                      }
00239                      break;
00240 
00241               case VT_VARIANT:
00242                      /* points to another variant */
00243                      return php_com_zval_from_variant(z, V_VARIANTREF(v), codepage TSRMLS_CC);
00244                      
00245               default:
00246                      php_com_wrap_variant(z, v, codepage TSRMLS_CC);
00247        }
00248 
00249        if (olestring) {
00250               efree(olestring);
00251        }
00252 
00253        if (ret == FAILURE) {
00254               php_error_docref(NULL TSRMLS_CC, E_WARNING, "variant->zval: conversion from 0x%x ret=%d", V_VT(v), ret);
00255        }
00256 
00257        return ret;
00258 }
00259 
00260 
00261 PHPAPI int php_com_copy_variant(VARIANT *dstvar, VARIANT *srcvar TSRMLS_DC)
00262 {
00263        int ret = SUCCESS;
00264        
00265        switch (V_VT(dstvar) & ~VT_BYREF) {
00266        case VT_EMPTY:
00267        case VT_NULL:
00268        case VT_VOID:
00269               /* should not be possible */
00270               break;
00271 
00272        case VT_UI1:
00273               if (V_VT(dstvar) & VT_BYREF) {
00274                      *V_UI1REF(dstvar) = V_UI1(srcvar);
00275               } else {
00276                       V_UI1(dstvar) = V_UI1(srcvar);
00277               }
00278               break;
00279 
00280        case VT_I1:
00281               if (V_VT(dstvar) & VT_BYREF) {
00282                      *V_I1REF(dstvar) = V_I1(srcvar);
00283               } else {
00284                      V_I1(dstvar) = V_I1(srcvar);
00285               }
00286               break;
00287 
00288        case VT_UI2:
00289               if (V_VT(dstvar) & VT_BYREF) {
00290                      *V_UI2REF(dstvar) = V_UI2(srcvar);
00291               } else {
00292                      V_UI2(dstvar) = V_UI2(srcvar); 
00293               }
00294               break;
00295 
00296        case VT_I2:
00297               if (V_VT(dstvar) & VT_BYREF) {
00298                      *V_I2REF(dstvar) = V_I2(srcvar);
00299               } else {
00300                      V_I2(dstvar) = V_I2(srcvar);
00301               }
00302               break;
00303 
00304        case VT_UI4: 
00305               if (V_VT(dstvar) & VT_BYREF) {
00306                      *V_UI4REF(dstvar) = V_UI4(srcvar);
00307               } else {
00308                      V_UI4(dstvar) = V_UI4(srcvar);
00309               }
00310               break;
00311 
00312        case VT_I4:
00313               if (V_VT(dstvar) & VT_BYREF) {
00314                      *V_I4REF(dstvar) = V_I4(srcvar);
00315               } else {
00316                      V_I4(dstvar) = V_I4(srcvar);
00317               }
00318               break;
00319 
00320        case VT_INT:
00321               if (V_VT(dstvar) & VT_BYREF) {
00322                      *V_INTREF(dstvar) = V_INT(srcvar);
00323               } else {
00324                      V_INT(dstvar) = V_INT(srcvar);
00325               }
00326               break;
00327 
00328        case VT_UINT:
00329               if (V_VT(dstvar) & VT_BYREF) {
00330                      *V_UINTREF(dstvar) = V_UINT(srcvar);
00331               } else {
00332                      V_UINT(dstvar) = V_UINT(srcvar);       
00333               }
00334               break;
00335 
00336        case VT_R4:
00337               if (V_VT(dstvar) & VT_BYREF) {
00338                      *V_R4REF(dstvar) = V_R4(srcvar);
00339               } else {
00340                      V_R4(dstvar) = V_R4(srcvar);
00341               }
00342               break;
00343 
00344        case VT_R8:
00345               if (V_VT(dstvar) & VT_BYREF) {
00346                      *V_R8REF(dstvar) = V_R8(srcvar);
00347               } else {
00348                      V_R8(dstvar) = V_R8(srcvar);
00349               }
00350               break;
00351 
00352        case VT_BOOL:
00353               if (V_VT(dstvar) & VT_BYREF) {
00354                      *V_BOOLREF(dstvar) = V_BOOL(srcvar);
00355               } else {
00356                      V_BOOL(dstvar) = V_BOOL(srcvar);
00357               }
00358         break;
00359 
00360        case VT_BSTR:
00361               if (V_VT(dstvar) & VT_BYREF) {
00362                      *V_BSTRREF(dstvar) = V_BSTR(srcvar);
00363               } else {
00364                      V_BSTR(dstvar) = V_BSTR(srcvar);
00365         }
00366               break;
00367 
00368        case VT_UNKNOWN:
00369               if (V_VT(dstvar) & VT_BYREF) {
00370                      *V_UNKNOWNREF(dstvar) = V_UNKNOWN(srcvar);
00371               } else {
00372                      V_UNKNOWN(dstvar) = V_UNKNOWN(srcvar);
00373               }
00374               break;
00375 
00376        case VT_DISPATCH:
00377               if (V_VT(dstvar) & VT_BYREF) {
00378                      *V_DISPATCHREF(dstvar) = V_DISPATCH(srcvar);
00379               } else {
00380                      V_DISPATCH(dstvar) = V_DISPATCH(srcvar);
00381               }
00382               break;
00383 
00384        case VT_VARIANT:
00385               return php_com_copy_variant(V_VARIANTREF(dstvar), srcvar TSRMLS_CC);
00386               
00387        default:
00388               php_error_docref(NULL TSRMLS_CC, E_WARNING, "variant->variant: failed to copy from 0x%x to 0x%x", V_VT(dstvar), V_VT(srcvar));
00389               ret = FAILURE;
00390        }
00391        return ret;
00392 }
00393 
00394 /* {{{ com_variant_create_instance - ctor for new VARIANT() */
00395 PHP_FUNCTION(com_variant_create_instance)
00396 {
00397        /* VARTYPE == unsigned short */ long vt = VT_EMPTY;
00398        long codepage = CP_ACP;
00399        zval *object = getThis();
00400        php_com_dotnet_object *obj;
00401        zval *zvalue = NULL;
00402        HRESULT res;
00403 
00404        if (ZEND_NUM_ARGS() == 0) {
00405               /* just leave things as-is - an empty variant */
00406               return;
00407        }
00408        
00409        obj = CDNO_FETCH(object);
00410        
00411        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
00412               "z!|ll", &zvalue, &vt, &codepage)) {
00413                      php_com_throw_exception(E_INVALIDARG, "Invalid arguments" TSRMLS_CC);
00414                      return;
00415        }
00416 
00417        php_com_initialize(TSRMLS_C);
00418        if (ZEND_NUM_ARGS() == 3) {
00419               obj->code_page = codepage;
00420        }
00421 
00422        if (zvalue) {
00423               php_com_variant_from_zval(&obj->v, zvalue, obj->code_page TSRMLS_CC);
00424        }
00425 
00426        /* Only perform conversion if variant not already of type passed */
00427        if ((ZEND_NUM_ARGS() >= 2) && (vt != V_VT(&obj->v))) {
00428 
00429               /* If already an array and VT_ARRAY is passed then:
00430                      - if only VT_ARRAY passed then do not perform a conversion
00431                      - if VT_ARRAY plus other type passed then perform conversion 
00432                        but will probably fail (origional behavior)
00433               */
00434               if ((vt & VT_ARRAY) && (V_VT(&obj->v) & VT_ARRAY)) {
00435                      long orig_vt = vt;
00436 
00437                      vt &= ~VT_ARRAY;
00438                      if (vt) {
00439                             vt = orig_vt;
00440                      }
00441               }
00442 
00443               if (vt) {
00444                      res = VariantChangeType(&obj->v, &obj->v, 0, (VARTYPE)vt);
00445 
00446                      if (FAILED(res)) {
00447                             char *werr, *msg;
00448 
00449                             werr = php_win_err(res);
00450                             spprintf(&msg, 0, "Variant type conversion failed: %s", werr);
00451                             LocalFree(werr);
00452 
00453                             php_com_throw_exception(res, msg TSRMLS_CC);
00454                             efree(msg);
00455                      }
00456               }
00457        }
00458 
00459        if (V_VT(&obj->v) != VT_DISPATCH && obj->typeinfo) {
00460               ITypeInfo_Release(obj->typeinfo);
00461               obj->typeinfo = NULL;
00462        }
00463 }
00464 /* }}} */
00465 
00466 /* {{{ proto void variant_set(object variant, mixed value)
00467    Assigns a new value for a variant object */
00468 PHP_FUNCTION(variant_set)
00469 {
00470        zval *zobj, *zvalue = NULL;
00471        php_com_dotnet_object *obj;
00472 
00473        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
00474                      "Oz!", &zobj, php_com_variant_class_entry, &zvalue)) {
00475               return;
00476        }
00477 
00478        obj = CDNO_FETCH(zobj);
00479 
00480        /* dtor the old value */
00481        if (obj->typeinfo) {
00482               ITypeInfo_Release(obj->typeinfo);
00483               obj->typeinfo = NULL;
00484        }
00485        if (obj->sink_dispatch) {
00486               php_com_object_enable_event_sink(obj, FALSE TSRMLS_CC);
00487               IDispatch_Release(obj->sink_dispatch);
00488               obj->sink_dispatch = NULL;
00489        }
00490 
00491        VariantClear(&obj->v);
00492 
00493        php_com_variant_from_zval(&obj->v, zvalue, obj->code_page TSRMLS_CC);
00494        /* remember we modified this variant */
00495        obj->modified = 1;
00496 }
00497 /* }}} */
00498 
00499 enum variant_binary_opcode {
00500        VOP_ADD, VOP_CAT, VOP_SUB, VOP_MUL, VOP_AND, VOP_DIV,
00501        VOP_EQV, VOP_IDIV, VOP_IMP, VOP_MOD, VOP_OR, VOP_POW,
00502        VOP_XOR
00503 };
00504 
00505 enum variant_unary_opcode {
00506        VOP_ABS, VOP_FIX, VOP_INT, VOP_NEG, VOP_NOT
00507 };
00508 
00509 static void variant_binary_operation(enum variant_binary_opcode op, INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
00510 {
00511        VARIANT vres;
00512        VARIANT left_val, right_val;
00513        VARIANT *vleft = NULL, *vright = NULL;
00514        zval *zleft = NULL, *zright = NULL;
00515        php_com_dotnet_object *obj;
00516        HRESULT result;
00517        int codepage = CP_ACP;
00518 
00519        VariantInit(&left_val);
00520        VariantInit(&right_val);
00521        VariantInit(&vres);
00522 
00523        if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
00524                      ZEND_NUM_ARGS() TSRMLS_CC, "OO", &zleft, php_com_variant_class_entry,
00525                      &zright, php_com_variant_class_entry)) {
00526               obj = CDNO_FETCH(zleft);
00527               vleft = &obj->v;
00528               obj = CDNO_FETCH(zright);
00529               vright = &obj->v;
00530        } else if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
00531                      ZEND_NUM_ARGS() TSRMLS_CC, "Oz!", &zleft, php_com_variant_class_entry,
00532                      &zright)) {
00533               obj = CDNO_FETCH(zleft);
00534               vleft = &obj->v;
00535               vright = &right_val;
00536               php_com_variant_from_zval(vright, zright, codepage TSRMLS_CC);
00537        } else if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
00538                      ZEND_NUM_ARGS() TSRMLS_CC, "z!O", &zleft, &zright, php_com_variant_class_entry)) {
00539               obj = CDNO_FETCH(zright);
00540               vright = &obj->v;
00541               vleft = &left_val;
00542               php_com_variant_from_zval(vleft, zleft, codepage TSRMLS_CC);
00543        } else if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
00544                      "z!z!", &zleft, &zright)) {
00545 
00546               vleft = &left_val;
00547               php_com_variant_from_zval(vleft, zleft, codepage TSRMLS_CC);
00548 
00549               vright = &right_val;
00550               php_com_variant_from_zval(vright, zright, codepage TSRMLS_CC);
00551 
00552        } else {
00553               return;
00554        }
00555 
00556        switch (op) {
00557               case VOP_ADD:
00558                      result = VarAdd(vleft, vright, &vres);
00559                      break;
00560               case VOP_CAT:
00561                      result = VarCat(vleft, vright, &vres);
00562                      break;
00563               case VOP_SUB:
00564                      result = VarSub(vleft, vright, &vres);
00565                      break;
00566               case VOP_MUL:
00567                      result = VarMul(vleft, vright, &vres);
00568                      break;
00569               case VOP_AND:
00570                      result = VarAnd(vleft, vright, &vres);
00571                      break;
00572               case VOP_DIV:
00573                      result = VarDiv(vleft, vright, &vres);
00574                      break;
00575               case VOP_EQV:
00576                      result = VarEqv(vleft, vright, &vres);
00577                      break;
00578               case VOP_IDIV:
00579                      result = VarIdiv(vleft, vright, &vres);
00580                      break;
00581               case VOP_IMP:
00582                      result = VarImp(vleft, vright, &vres);
00583                      break;
00584               case VOP_MOD:
00585                      result = VarMod(vleft, vright, &vres);
00586                      break;
00587               case VOP_OR:
00588                      result = VarOr(vleft, vright, &vres);
00589                      break;
00590               case VOP_POW:
00591                      result = VarPow(vleft, vright, &vres);
00592                      break;
00593               case VOP_XOR:
00594                      result = VarXor(vleft, vright, &vres);
00595                      break;
00596               /*Let say it fails as no valid op has been given */
00597               default:
00598                      result = E_INVALIDARG;
00599        }
00600 
00601        if (SUCCEEDED(result)) {
00602               php_com_wrap_variant(return_value, &vres, codepage TSRMLS_CC);
00603        } else {
00604               php_com_throw_exception(result, NULL TSRMLS_CC);
00605        }
00606 
00607        VariantClear(&vres);
00608        VariantClear(&left_val);
00609        VariantClear(&right_val);
00610 }
00611 /* }}} */
00612 
00613 /* {{{ proto mixed variant_add(mixed left, mixed right)
00614    "Adds" two variant values together and returns the result */
00615 PHP_FUNCTION(variant_add)
00616 {
00617        variant_binary_operation(VOP_ADD, INTERNAL_FUNCTION_PARAM_PASSTHRU);
00618 }
00619 /* }}} */
00620 
00621 /* {{{ proto mixed variant_cat(mixed left, mixed right)
00622    concatenates two variant values together and returns the result */
00623 PHP_FUNCTION(variant_cat)
00624 {
00625        variant_binary_operation(VOP_CAT, INTERNAL_FUNCTION_PARAM_PASSTHRU);
00626 }
00627 /* }}} */
00628 
00629 /* {{{ proto mixed variant_sub(mixed left, mixed right)
00630    subtracts the value of the right variant from the left variant value and returns the result */
00631 PHP_FUNCTION(variant_sub)
00632 {
00633        variant_binary_operation(VOP_SUB, INTERNAL_FUNCTION_PARAM_PASSTHRU);
00634 }
00635 /* }}} */
00636 
00637 /* {{{ proto mixed variant_mul(mixed left, mixed right)
00638    multiplies the values of the two variants and returns the result */
00639 PHP_FUNCTION(variant_mul)
00640 {
00641        variant_binary_operation(VOP_MUL, INTERNAL_FUNCTION_PARAM_PASSTHRU);
00642 }
00643 /* }}} */
00644 
00645 /* {{{ proto mixed variant_and(mixed left, mixed right)
00646    performs a bitwise AND operation between two variants and returns the result */
00647 PHP_FUNCTION(variant_and)
00648 {
00649        variant_binary_operation(VOP_AND, INTERNAL_FUNCTION_PARAM_PASSTHRU);
00650 }
00651 /* }}} */
00652 
00653 /* {{{ proto mixed variant_div(mixed left, mixed right)
00654    Returns the result from dividing two variants */
00655 PHP_FUNCTION(variant_div)
00656 {
00657        variant_binary_operation(VOP_DIV, INTERNAL_FUNCTION_PARAM_PASSTHRU);
00658 }
00659 /* }}} */
00660 
00661 /* {{{ proto mixed variant_eqv(mixed left, mixed right)
00662    Performs a bitwise equivalence on two variants */
00663 PHP_FUNCTION(variant_eqv)
00664 {
00665        variant_binary_operation(VOP_EQV, INTERNAL_FUNCTION_PARAM_PASSTHRU);
00666 }
00667 /* }}} */
00668 
00669 /* {{{ proto mixed variant_idiv(mixed left, mixed right)
00670    Converts variants to integers and then returns the result from dividing them */
00671 PHP_FUNCTION(variant_idiv)
00672 {
00673        variant_binary_operation(VOP_IDIV, INTERNAL_FUNCTION_PARAM_PASSTHRU);
00674 }
00675 /* }}} */
00676 
00677 /* {{{ proto mixed variant_imp(mixed left, mixed right)
00678    Performs a bitwise implication on two variants */
00679 PHP_FUNCTION(variant_imp)
00680 {
00681        variant_binary_operation(VOP_IMP, INTERNAL_FUNCTION_PARAM_PASSTHRU);
00682 }
00683 /* }}} */
00684 
00685 /* {{{ proto mixed variant_mod(mixed left, mixed right)
00686    Divides two variants and returns only the remainder */
00687 PHP_FUNCTION(variant_mod)
00688 {
00689        variant_binary_operation(VOP_MOD, INTERNAL_FUNCTION_PARAM_PASSTHRU);
00690 }
00691 /* }}} */
00692 
00693 /* {{{ proto mixed variant_or(mixed left, mixed right)
00694    Performs a logical disjunction on two variants */
00695 PHP_FUNCTION(variant_or)
00696 {
00697        variant_binary_operation(VOP_OR, INTERNAL_FUNCTION_PARAM_PASSTHRU);
00698 }
00699 /* }}} */
00700 
00701 /* {{{ proto mixed variant_pow(mixed left, mixed right)
00702    Returns the result of performing the power function with two variants */
00703 PHP_FUNCTION(variant_pow)
00704 {
00705        variant_binary_operation(VOP_POW, INTERNAL_FUNCTION_PARAM_PASSTHRU);
00706 }
00707 /* }}} */
00708 
00709 /* {{{ proto mixed variant_xor(mixed left, mixed right)
00710    Performs a logical exclusion on two variants */
00711 PHP_FUNCTION(variant_xor)
00712 {
00713        variant_binary_operation(VOP_XOR, INTERNAL_FUNCTION_PARAM_PASSTHRU);
00714 }
00715 /* }}} */
00716 
00717 static void variant_unary_operation(enum variant_unary_opcode op, INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
00718 {
00719        VARIANT vres;
00720        VARIANT left_val;
00721        VARIANT *vleft = NULL;
00722        zval *zleft = NULL;
00723        php_com_dotnet_object *obj;
00724        HRESULT result;
00725        int codepage = CP_ACP;
00726 
00727        VariantInit(&left_val);
00728        VariantInit(&vres);
00729 
00730        if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
00731                      ZEND_NUM_ARGS() TSRMLS_CC, "O", &zleft, php_com_variant_class_entry)) {
00732               obj = CDNO_FETCH(zleft);
00733               vleft = &obj->v;
00734        } else if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
00735                      "z!", &zleft)) {
00736               vleft = &left_val;
00737               php_com_variant_from_zval(vleft, zleft, codepage TSRMLS_CC);
00738        } else {
00739               return;
00740        }
00741 
00742        switch (op) {
00743               case VOP_ABS:
00744                      result = VarAbs(vleft, &vres);
00745                      break;
00746               case VOP_FIX:
00747                      result = VarFix(vleft, &vres);
00748                      break;
00749               case VOP_INT:
00750                      result = VarInt(vleft, &vres);
00751                      break;
00752               case VOP_NEG:
00753                      result = VarNeg(vleft, &vres);
00754                      break;
00755               case VOP_NOT:
00756                      result = VarNot(vleft, &vres);
00757                      break;
00758               default:
00759                      result = E_INVALIDARG;
00760        }
00761 
00762        if (SUCCEEDED(result)) {
00763               php_com_wrap_variant(return_value, &vres, codepage TSRMLS_CC);
00764        } else {
00765               php_com_throw_exception(result, NULL TSRMLS_CC);
00766        }
00767 
00768        VariantClear(&vres);
00769        VariantClear(&left_val);
00770 }
00771 /* }}} */
00772 
00773 /* {{{ proto mixed variant_abs(mixed left)
00774    Returns the absolute value of a variant */
00775 PHP_FUNCTION(variant_abs)
00776 {
00777        variant_unary_operation(VOP_ABS, INTERNAL_FUNCTION_PARAM_PASSTHRU);
00778 }
00779 /* }}} */
00780 
00781 /* {{{ proto mixed variant_fix(mixed left)
00782    Returns the integer part ? of a variant */
00783 PHP_FUNCTION(variant_fix)
00784 {
00785        variant_unary_operation(VOP_FIX, INTERNAL_FUNCTION_PARAM_PASSTHRU);
00786 }
00787 /* }}} */
00788 
00789 /* {{{ proto mixed variant_int(mixed left)
00790    Returns the integer portion of a variant */
00791 PHP_FUNCTION(variant_int)
00792 {
00793        variant_unary_operation(VOP_INT, INTERNAL_FUNCTION_PARAM_PASSTHRU);
00794 }
00795 /* }}} */
00796 
00797 /* {{{ proto mixed variant_neg(mixed left)
00798    Performs logical negation on a variant */
00799 PHP_FUNCTION(variant_neg)
00800 {
00801        variant_unary_operation(VOP_NEG, INTERNAL_FUNCTION_PARAM_PASSTHRU);
00802 }
00803 /* }}} */
00804 
00805 /* {{{ proto mixed variant_not(mixed left)
00806    Performs bitwise not negation on a variant */
00807 PHP_FUNCTION(variant_not)
00808 {
00809        variant_unary_operation(VOP_NOT, INTERNAL_FUNCTION_PARAM_PASSTHRU);
00810 }
00811 /* }}} */
00812 
00813 /* {{{ proto mixed variant_round(mixed left, int decimals)
00814    Rounds a variant to the specified number of decimal places */
00815 PHP_FUNCTION(variant_round)
00816 {
00817        VARIANT vres;
00818        VARIANT left_val;
00819        VARIANT *vleft = NULL;
00820        zval *zleft = NULL;
00821        php_com_dotnet_object *obj;
00822        int codepage = CP_ACP;
00823        long decimals = 0;
00824 
00825        VariantInit(&left_val);
00826        VariantInit(&vres);
00827 
00828        if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
00829                      ZEND_NUM_ARGS() TSRMLS_CC, "Ol", &zleft, php_com_variant_class_entry, &decimals)) {
00830               obj = CDNO_FETCH(zleft);
00831               vleft = &obj->v;
00832        } else if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
00833                      "z!l", &zleft, &decimals)) {
00834               vleft = &left_val;
00835               php_com_variant_from_zval(vleft, zleft, codepage TSRMLS_CC);
00836        } else {
00837               return;
00838        }
00839 
00840        if (SUCCEEDED(VarRound(vleft, decimals, &vres))) {
00841               php_com_wrap_variant(return_value, &vres, codepage TSRMLS_CC);
00842        }
00843 
00844        VariantClear(&vres);
00845        VariantClear(&left_val);
00846 }
00847 /* }}} */
00848 
00849 /* {{{ proto int variant_cmp(mixed left, mixed right [, int lcid [, int flags]])
00850    Compares two variants */
00851 PHP_FUNCTION(variant_cmp)
00852 {
00853        VARIANT left_val, right_val;
00854        VARIANT *vleft = NULL, *vright = NULL;
00855        zval *zleft = NULL, *zright = NULL;
00856        php_com_dotnet_object *obj;
00857        int codepage = CP_ACP;
00858        long lcid = LOCALE_SYSTEM_DEFAULT;
00859        long flags = 0;
00860        /* it is safe to ignore the warning for this line; see the comments in com_handlers.c */
00861        STDAPI VarCmp(LPVARIANT pvarLeft, LPVARIANT pvarRight, LCID lcid, DWORD flags);
00862 
00863        VariantInit(&left_val);
00864        VariantInit(&right_val);
00865 
00866        if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
00867                      ZEND_NUM_ARGS() TSRMLS_CC, "OO|ll", &zleft, php_com_variant_class_entry,
00868                      &zright, php_com_variant_class_entry, &lcid, &flags)) {
00869               obj = CDNO_FETCH(zleft);
00870               vleft = &obj->v;
00871               obj = CDNO_FETCH(zright);
00872               vright = &obj->v;
00873        } else if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
00874                      ZEND_NUM_ARGS() TSRMLS_CC, "Oz!|ll", &zleft, php_com_variant_class_entry,
00875                      &zright, &lcid, &flags)) {
00876               obj = CDNO_FETCH(zleft);
00877               vleft = &obj->v;
00878               vright = &right_val;
00879               php_com_variant_from_zval(vright, zright, codepage TSRMLS_CC);
00880        } else if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
00881                      ZEND_NUM_ARGS() TSRMLS_CC, "z!O|ll", &zleft, &zright, php_com_variant_class_entry,
00882                      &lcid, &flags)) {
00883               obj = CDNO_FETCH(zright);
00884               vright = &obj->v;
00885               vleft = &left_val;
00886               php_com_variant_from_zval(vleft, zleft, codepage TSRMLS_CC);
00887        } else if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
00888                      "z!z!|ll", &zleft, &zright, &lcid, &flags)) {
00889 
00890               vleft = &left_val;
00891               php_com_variant_from_zval(vleft, zleft, codepage TSRMLS_CC);
00892 
00893               vright = &right_val;
00894               php_com_variant_from_zval(vright, zright, codepage TSRMLS_CC);
00895 
00896        } else {
00897               return;
00898        }
00899 
00900        ZVAL_LONG(return_value, VarCmp(vleft, vright, lcid, flags));
00901 
00902        VariantClear(&left_val);
00903        VariantClear(&right_val);
00904 }
00905 /* }}} */
00906 
00907 /* {{{ proto int variant_date_to_timestamp(object variant)
00908    Converts a variant date/time value to unix timestamp */
00909 PHP_FUNCTION(variant_date_to_timestamp)
00910 {
00911        VARIANT vres;
00912        zval *zleft = NULL;
00913        php_com_dotnet_object *obj;
00914 
00915        VariantInit(&vres);
00916 
00917        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
00918               "O", &zleft, php_com_variant_class_entry)) {
00919               return;
00920        }
00921        obj = CDNO_FETCH(zleft);
00922 
00923        if (SUCCEEDED(VariantChangeType(&vres, &obj->v, 0, VT_DATE))) {
00924               SYSTEMTIME systime;
00925               struct tm tmv;
00926 
00927               VariantTimeToSystemTime(V_DATE(&vres), &systime);
00928 
00929               memset(&tmv, 0, sizeof(tmv));
00930               tmv.tm_year = systime.wYear - 1900;
00931               tmv.tm_mon = systime.wMonth - 1;
00932               tmv.tm_mday = systime.wDay;
00933               tmv.tm_hour = systime.wHour;
00934               tmv.tm_min = systime.wMinute;
00935               tmv.tm_sec = systime.wSecond;
00936               tmv.tm_isdst = -1;
00937 
00938               tzset();
00939               RETVAL_LONG(mktime(&tmv));
00940        }
00941 
00942        VariantClear(&vres);
00943 }
00944 /* }}} */
00945 
00946 /* {{{ proto object variant_date_from_timestamp(int timestamp)
00947    Returns a variant date representation of a unix timestamp */
00948 PHP_FUNCTION(variant_date_from_timestamp)
00949 {
00950        long timestamp;
00951        time_t ttstamp;
00952        SYSTEMTIME systime;
00953        struct tm *tmv;
00954        VARIANT res;
00955 
00956        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l",
00957                      &timestamp)) {
00958               return;
00959        }
00960 
00961        if (timestamp < 0) {
00962               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Timestamp value must be a positive value.");
00963               RETURN_FALSE;
00964        }
00965 
00966        VariantInit(&res);
00967        tzset();
00968        ttstamp = timestamp;
00969        tmv = localtime(&ttstamp);
00970        memset(&systime, 0, sizeof(systime));
00971 
00972        systime.wDay = tmv->tm_mday;
00973        systime.wHour = tmv->tm_hour;
00974        systime.wMinute = tmv->tm_min;
00975        systime.wMonth = tmv->tm_mon + 1;
00976        systime.wSecond = tmv->tm_sec;
00977        systime.wYear = tmv->tm_year + 1900;
00978 
00979        V_VT(&res) = VT_DATE;
00980        SystemTimeToVariantTime(&systime, &V_DATE(&res));
00981 
00982        php_com_wrap_variant(return_value, &res, CP_ACP TSRMLS_CC);
00983 
00984        VariantClear(&res);
00985 }
00986 /* }}} */
00987 
00988 /* {{{ proto int variant_get_type(object variant)
00989    Returns the VT_XXX type code for a variant */
00990 PHP_FUNCTION(variant_get_type)
00991 {
00992        zval *zobj;
00993        php_com_dotnet_object *obj;
00994 
00995        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
00996               "O", &zobj, php_com_variant_class_entry)) {
00997               return;
00998        }
00999        obj = CDNO_FETCH(zobj);
01000               
01001        RETURN_LONG(V_VT(&obj->v));
01002 }
01003 /* }}} */
01004 
01005 /* {{{ proto void variant_set_type(object variant, int type)
01006    Convert a variant into another type.  Variant is modified "in-place" */
01007 PHP_FUNCTION(variant_set_type)
01008 {
01009        zval *zobj;
01010        php_com_dotnet_object *obj;
01011        /* VARTYPE == unsigned short */ long vt;
01012        HRESULT res;
01013 
01014        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
01015               "Ol", &zobj, php_com_variant_class_entry, &vt)) {
01016               return;
01017        }
01018        obj = CDNO_FETCH(zobj);
01019 
01020        res = VariantChangeType(&obj->v, &obj->v, 0, (VARTYPE)vt);
01021 
01022        if (SUCCEEDED(res)) {
01023               if (vt != VT_DISPATCH && obj->typeinfo) {
01024                      ITypeInfo_Release(obj->typeinfo);
01025                      obj->typeinfo = NULL;
01026               }
01027        } else {
01028               char *werr, *msg;
01029 
01030               werr = php_win_err(res);
01031               spprintf(&msg, 0, "Variant type conversion failed: %s", werr);
01032               LocalFree(werr);
01033 
01034               php_com_throw_exception(res, msg TSRMLS_CC);
01035               efree(msg);
01036        }
01037 }
01038 /* }}} */
01039 
01040 /* {{{ proto object variant_cast(object variant, int type)
01041    Convert a variant into a new variant object of another type */
01042 PHP_FUNCTION(variant_cast)
01043 {
01044        zval *zobj;
01045        php_com_dotnet_object *obj;
01046        /* VARTYPE == unsigned short */ long vt;
01047        VARIANT vres;
01048        HRESULT res;
01049 
01050        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
01051               "Ol", &zobj, php_com_variant_class_entry, &vt)) {
01052               return;
01053        }
01054        obj = CDNO_FETCH(zobj);
01055 
01056        VariantInit(&vres);
01057        res = VariantChangeType(&vres, &obj->v, 0, (VARTYPE)vt);
01058 
01059        if (SUCCEEDED(res)) {
01060               php_com_wrap_variant(return_value, &vres, obj->code_page TSRMLS_CC);
01061        } else {
01062               char *werr, *msg;
01063 
01064               werr = php_win_err(res);
01065               spprintf(&msg, 0, "Variant type conversion failed: %s", werr);
01066               LocalFree(werr);
01067 
01068               php_com_throw_exception(res, msg TSRMLS_CC);
01069               efree(msg);
01070        }
01071 
01072        VariantClear(&vres);
01073 }
01074 /* }}} */
01075