Annotation of embedaddon/php/ext/com_dotnet/com_variant.c, revision 1.1.1.2
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | PHP Version 5 |
4: +----------------------------------------------------------------------+
5: | Copyright (c) 1997-2012 The PHP Group |
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:
101: PHPAPI void php_com_variant_from_zval(VARIANT *v, zval *z, int codepage TSRMLS_DC)
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:
169: PHPAPI int php_com_zval_from_variant(zval *z, VARIANT *v, int codepage TSRMLS_DC)
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:
261: PHPAPI int php_com_copy_variant(VARIANT *dstvar, VARIANT *srcvar TSRMLS_DC)
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
432: but will probably fail (origional behavior)
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: ×tamp)) {
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>