You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1077 lines
26 KiB

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