com_variant.c 27 KB

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