Annotation of embedaddon/php/ext/com_dotnet/com_variant.c, revision 1.1.1.4

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>