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

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

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