1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2013 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
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
php_com_zval_from_variant(zval * z,VARIANT * v,int codepage TSRMLS_DC)169 PHP_COM_DOTNET_API 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
php_com_copy_variant(VARIANT * dstvar,VARIANT * srcvar TSRMLS_DC)261 PHP_COM_DOTNET_API 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() */
PHP_FUNCTION(com_variant_create_instance)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
449 werr = php_win_err(res);
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 */
PHP_FUNCTION(variant_set)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
variant_binary_operation(enum variant_binary_opcode op,INTERNAL_FUNCTION_PARAMETERS)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 */
PHP_FUNCTION(variant_add)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 */
PHP_FUNCTION(variant_cat)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 */
PHP_FUNCTION(variant_sub)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 */
PHP_FUNCTION(variant_mul)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 */
PHP_FUNCTION(variant_and)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 */
PHP_FUNCTION(variant_div)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 */
PHP_FUNCTION(variant_eqv)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 */
PHP_FUNCTION(variant_idiv)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 */
PHP_FUNCTION(variant_imp)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 */
PHP_FUNCTION(variant_mod)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 */
PHP_FUNCTION(variant_or)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 */
PHP_FUNCTION(variant_pow)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 */
PHP_FUNCTION(variant_xor)711 PHP_FUNCTION(variant_xor)
712 {
713 variant_binary_operation(VOP_XOR, INTERNAL_FUNCTION_PARAM_PASSTHRU);
714 }
715 /* }}} */
716
variant_unary_operation(enum variant_unary_opcode op,INTERNAL_FUNCTION_PARAMETERS)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 */
PHP_FUNCTION(variant_abs)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 */
PHP_FUNCTION(variant_fix)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 */
PHP_FUNCTION(variant_int)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 */
PHP_FUNCTION(variant_neg)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 */
PHP_FUNCTION(variant_not)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 */
PHP_FUNCTION(variant_round)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 */
PHP_FUNCTION(variant_cmp)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 */
PHP_FUNCTION(variant_date_to_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 */
PHP_FUNCTION(variant_date_from_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 */
PHP_FUNCTION(variant_get_type)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" */
PHP_FUNCTION(variant_set_type)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
1030 werr = php_win_err(res);
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 */
PHP_FUNCTION(variant_cast)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
1064 werr = php_win_err(res);
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
1076