1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2014 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
19 /* $Id$ */
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 */
safe_array_from_zval(VARIANT * v,zval * z,int codepage TSRMLS_DC)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
php_com_variant_from_zval(VARIANT * v,zval * z,int codepage TSRMLS_DC)101 PHP_COM_DOTNET_API 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 zend_uchar ztype = (z == NULL ? IS_NULL : Z_TYPE_P(z));
106
107 switch (ztype) {
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 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 }
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
php_com_zval_from_variant(zval * z,VARIANT * v,int codepage TSRMLS_DC)174 PHP_COM_DOTNET_API int php_com_zval_from_variant(zval *z, VARIANT *v, int codepage TSRMLS_DC)
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
php_com_copy_variant(VARIANT * dstvar,VARIANT * srcvar TSRMLS_DC)266 PHP_COM_DOTNET_API int php_com_copy_variant(VARIANT *dstvar, VARIANT *srcvar TSRMLS_DC)
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() */
PHP_FUNCTION(com_variant_create_instance)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
437 but will probably fail (original behavior)
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
454 werr = php_win32_error_to_msg(res);
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 */
PHP_FUNCTION(variant_set)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
variant_binary_operation(enum variant_binary_opcode op,INTERNAL_FUNCTION_PARAMETERS)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 */
PHP_FUNCTION(variant_add)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 */
PHP_FUNCTION(variant_cat)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 */
PHP_FUNCTION(variant_sub)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 */
PHP_FUNCTION(variant_mul)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 */
PHP_FUNCTION(variant_and)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 */
PHP_FUNCTION(variant_div)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 */
PHP_FUNCTION(variant_eqv)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 */
PHP_FUNCTION(variant_idiv)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 */
PHP_FUNCTION(variant_imp)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 */
PHP_FUNCTION(variant_mod)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 */
PHP_FUNCTION(variant_or)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 */
PHP_FUNCTION(variant_pow)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 */
PHP_FUNCTION(variant_xor)716 PHP_FUNCTION(variant_xor)
717 {
718 variant_binary_operation(VOP_XOR, INTERNAL_FUNCTION_PARAM_PASSTHRU);
719 }
720 /* }}} */
721
variant_unary_operation(enum variant_unary_opcode op,INTERNAL_FUNCTION_PARAMETERS)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 */
PHP_FUNCTION(variant_abs)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 */
PHP_FUNCTION(variant_fix)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 */
PHP_FUNCTION(variant_int)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 */
PHP_FUNCTION(variant_neg)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 */
PHP_FUNCTION(variant_not)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 */
PHP_FUNCTION(variant_round)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 */
PHP_FUNCTION(variant_cmp)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 */
PHP_FUNCTION(variant_date_to_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 */
PHP_FUNCTION(variant_date_from_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 */
PHP_FUNCTION(variant_get_type)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" */
PHP_FUNCTION(variant_set_type)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
1035 werr = php_win32_error_to_msg(res);
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 */
PHP_FUNCTION(variant_cast)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
1069 werr = php_win32_error_to_msg(res);
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
1081