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