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