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

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

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