com_persist.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777
  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. /* Infrastructure for working with persistent COM objects.
  20. * Implements: IStream* wrapper for PHP streams.
  21. * TODO: Magic __wakeup and __sleep handlers for serialization
  22. * (can wait till 5.1) */
  23. #ifdef HAVE_CONFIG_H
  24. #include "config.h"
  25. #endif
  26. #include "php.h"
  27. #include "php_ini.h"
  28. #include "ext/standard/info.h"
  29. #include "php_com_dotnet.h"
  30. #include "php_com_dotnet_internal.h"
  31. #include "Zend/zend_exceptions.h"
  32. /* {{{ expose php_stream as a COM IStream */
  33. typedef struct {
  34. CONST_VTBL struct IStreamVtbl *lpVtbl;
  35. DWORD engine_thread;
  36. LONG refcount;
  37. php_stream *stream;
  38. int id;
  39. } php_istream;
  40. static int le_istream;
  41. static void istream_destructor(php_istream *stm TSRMLS_DC);
  42. static void istream_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
  43. {
  44. php_istream *stm = (php_istream *)rsrc->ptr;
  45. istream_destructor(stm TSRMLS_CC);
  46. }
  47. #define FETCH_STM() \
  48. php_istream *stm = (php_istream*)This; \
  49. TSRMLS_FETCH(); \
  50. if (GetCurrentThreadId() != stm->engine_thread) \
  51. return RPC_E_WRONG_THREAD;
  52. #define FETCH_STM_EX() \
  53. php_istream *stm = (php_istream*)This; \
  54. if (GetCurrentThreadId() != stm->engine_thread) \
  55. return RPC_E_WRONG_THREAD;
  56. static HRESULT STDMETHODCALLTYPE stm_queryinterface(
  57. IStream *This,
  58. /* [in] */ REFIID riid,
  59. /* [iid_is][out] */ void **ppvObject)
  60. {
  61. FETCH_STM_EX();
  62. if (IsEqualGUID(&IID_IUnknown, riid) ||
  63. IsEqualGUID(&IID_IStream, riid)) {
  64. *ppvObject = This;
  65. InterlockedIncrement(&stm->refcount);
  66. return S_OK;
  67. }
  68. *ppvObject = NULL;
  69. return E_NOINTERFACE;
  70. }
  71. static ULONG STDMETHODCALLTYPE stm_addref(IStream *This)
  72. {
  73. FETCH_STM_EX();
  74. return InterlockedIncrement(&stm->refcount);
  75. }
  76. static ULONG STDMETHODCALLTYPE stm_release(IStream *This)
  77. {
  78. ULONG ret;
  79. FETCH_STM();
  80. ret = InterlockedDecrement(&stm->refcount);
  81. if (ret == 0) {
  82. /* destroy it */
  83. if (stm->id)
  84. zend_list_delete(stm->id);
  85. }
  86. return ret;
  87. }
  88. static HRESULT STDMETHODCALLTYPE stm_read(IStream *This, void *pv, ULONG cb, ULONG *pcbRead)
  89. {
  90. int nread;
  91. FETCH_STM();
  92. nread = php_stream_read(stm->stream, pv, cb);
  93. if (pcbRead) {
  94. *pcbRead = nread > 0 ? nread : 0;
  95. }
  96. if (nread > 0) {
  97. return S_OK;
  98. }
  99. return S_FALSE;
  100. }
  101. static HRESULT STDMETHODCALLTYPE stm_write(IStream *This, void const *pv, ULONG cb, ULONG *pcbWritten)
  102. {
  103. int nwrote;
  104. FETCH_STM();
  105. nwrote = php_stream_write(stm->stream, pv, cb);
  106. if (pcbWritten) {
  107. *pcbWritten = nwrote > 0 ? nwrote : 0;
  108. }
  109. if (nwrote > 0) {
  110. return S_OK;
  111. }
  112. return S_FALSE;
  113. }
  114. static HRESULT STDMETHODCALLTYPE stm_seek(IStream *This, LARGE_INTEGER dlibMove,
  115. DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
  116. {
  117. off_t offset;
  118. int whence;
  119. int ret;
  120. FETCH_STM();
  121. switch (dwOrigin) {
  122. case STREAM_SEEK_SET: whence = SEEK_SET; break;
  123. case STREAM_SEEK_CUR: whence = SEEK_CUR; break;
  124. case STREAM_SEEK_END: whence = SEEK_END; break;
  125. default:
  126. return STG_E_INVALIDFUNCTION;
  127. }
  128. if (dlibMove.HighPart) {
  129. /* we don't support 64-bit offsets */
  130. return STG_E_INVALIDFUNCTION;
  131. }
  132. offset = (off_t) dlibMove.QuadPart;
  133. ret = php_stream_seek(stm->stream, offset, whence);
  134. if (plibNewPosition) {
  135. plibNewPosition->QuadPart = (ULONGLONG)(ret >= 0 ? ret : 0);
  136. }
  137. return ret >= 0 ? S_OK : STG_E_INVALIDFUNCTION;
  138. }
  139. static HRESULT STDMETHODCALLTYPE stm_set_size(IStream *This, ULARGE_INTEGER libNewSize)
  140. {
  141. FETCH_STM();
  142. if (libNewSize.HighPart) {
  143. return STG_E_INVALIDFUNCTION;
  144. }
  145. if (php_stream_truncate_supported(stm->stream)) {
  146. int ret = php_stream_truncate_set_size(stm->stream, (size_t)libNewSize.QuadPart);
  147. if (ret == 0) {
  148. return S_OK;
  149. }
  150. }
  151. return STG_E_INVALIDFUNCTION;
  152. }
  153. static HRESULT STDMETHODCALLTYPE stm_copy_to(IStream *This, IStream *pstm, ULARGE_INTEGER cb,
  154. ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
  155. {
  156. FETCH_STM_EX();
  157. return E_NOTIMPL;
  158. }
  159. static HRESULT STDMETHODCALLTYPE stm_commit(IStream *This, DWORD grfCommitFlags)
  160. {
  161. FETCH_STM();
  162. php_stream_flush(stm->stream);
  163. return S_OK;
  164. }
  165. static HRESULT STDMETHODCALLTYPE stm_revert(IStream *This)
  166. {
  167. /* NOP */
  168. return S_OK;
  169. }
  170. static HRESULT STDMETHODCALLTYPE stm_lock_region(IStream *This,
  171. ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD lockType)
  172. {
  173. return STG_E_INVALIDFUNCTION;
  174. }
  175. static HRESULT STDMETHODCALLTYPE stm_unlock_region(IStream *This,
  176. ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD lockType)
  177. {
  178. return STG_E_INVALIDFUNCTION;
  179. }
  180. static HRESULT STDMETHODCALLTYPE stm_stat(IStream *This,
  181. STATSTG *pstatstg, DWORD grfStatFlag)
  182. {
  183. return STG_E_INVALIDFUNCTION;
  184. }
  185. static HRESULT STDMETHODCALLTYPE stm_clone(IStream *This, IStream **ppstm)
  186. {
  187. return STG_E_INVALIDFUNCTION;
  188. }
  189. static struct IStreamVtbl php_istream_vtbl = {
  190. stm_queryinterface,
  191. stm_addref,
  192. stm_release,
  193. stm_read,
  194. stm_write,
  195. stm_seek,
  196. stm_set_size,
  197. stm_copy_to,
  198. stm_commit,
  199. stm_revert,
  200. stm_lock_region,
  201. stm_unlock_region,
  202. stm_stat,
  203. stm_clone
  204. };
  205. static void istream_destructor(php_istream *stm TSRMLS_DC)
  206. {
  207. if (stm->id) {
  208. int id = stm->id;
  209. stm->id = 0;
  210. zend_list_delete(id);
  211. return;
  212. }
  213. if (stm->refcount > 0) {
  214. CoDisconnectObject((IUnknown*)stm, 0);
  215. }
  216. zend_list_delete(stm->stream->rsrc_id);
  217. CoTaskMemFree(stm);
  218. }
  219. /* }}} */
  220. PHP_COM_DOTNET_API IStream *php_com_wrapper_export_stream(php_stream *stream TSRMLS_DC)
  221. {
  222. php_istream *stm = (php_istream*)CoTaskMemAlloc(sizeof(*stm));
  223. if (stm == NULL)
  224. return NULL;
  225. memset(stm, 0, sizeof(*stm));
  226. stm->engine_thread = GetCurrentThreadId();
  227. stm->lpVtbl = &php_istream_vtbl;
  228. stm->refcount = 1;
  229. stm->stream = stream;
  230. zend_list_addref(stream->rsrc_id);
  231. stm->id = zend_list_insert(stm, le_istream TSRMLS_CC);
  232. return (IStream*)stm;
  233. }
  234. #define CPH_ME(fname, arginfo) PHP_ME(com_persist, fname, arginfo, ZEND_ACC_PUBLIC)
  235. #define CPH_SME(fname, arginfo) PHP_ME(com_persist, fname, arginfo, ZEND_ACC_ALLOW_STATIC|ZEND_ACC_PUBLIC)
  236. #define CPH_METHOD(fname) static PHP_METHOD(com_persist, fname)
  237. #define CPH_FETCH() php_com_persist_helper *helper = (php_com_persist_helper*)zend_object_store_get_object(getThis() TSRMLS_CC);
  238. #define CPH_NO_OBJ() if (helper->unk == NULL) { php_com_throw_exception(E_INVALIDARG, "No COM object is associated with this helper instance" TSRMLS_CC); return; }
  239. typedef struct {
  240. zend_object std;
  241. long codepage;
  242. IUnknown *unk;
  243. IPersistStream *ips;
  244. IPersistStreamInit *ipsi;
  245. IPersistFile *ipf;
  246. } php_com_persist_helper;
  247. static zend_object_handlers helper_handlers;
  248. static zend_class_entry *helper_ce;
  249. static inline HRESULT get_persist_stream(php_com_persist_helper *helper)
  250. {
  251. if (!helper->ips && helper->unk) {
  252. return IUnknown_QueryInterface(helper->unk, &IID_IPersistStream, &helper->ips);
  253. }
  254. return helper->ips ? S_OK : E_NOTIMPL;
  255. }
  256. static inline HRESULT get_persist_stream_init(php_com_persist_helper *helper)
  257. {
  258. if (!helper->ipsi && helper->unk) {
  259. return IUnknown_QueryInterface(helper->unk, &IID_IPersistStreamInit, &helper->ipsi);
  260. }
  261. return helper->ipsi ? S_OK : E_NOTIMPL;
  262. }
  263. static inline HRESULT get_persist_file(php_com_persist_helper *helper)
  264. {
  265. if (!helper->ipf && helper->unk) {
  266. return IUnknown_QueryInterface(helper->unk, &IID_IPersistFile, &helper->ipf);
  267. }
  268. return helper->ipf ? S_OK : E_NOTIMPL;
  269. }
  270. /* {{{ proto string COMPersistHelper::GetCurFile()
  271. Determines the filename into which an object will be saved, or false if none is set, via IPersistFile::GetCurFile */
  272. CPH_METHOD(GetCurFileName)
  273. {
  274. HRESULT res;
  275. OLECHAR *olename = NULL;
  276. CPH_FETCH();
  277. CPH_NO_OBJ();
  278. res = get_persist_file(helper);
  279. if (helper->ipf) {
  280. res = IPersistFile_GetCurFile(helper->ipf, &olename);
  281. if (res == S_OK) {
  282. Z_TYPE_P(return_value) = IS_STRING;
  283. Z_STRVAL_P(return_value) = php_com_olestring_to_string(olename,
  284. &Z_STRLEN_P(return_value), helper->codepage TSRMLS_CC);
  285. CoTaskMemFree(olename);
  286. return;
  287. } else if (res == S_FALSE) {
  288. CoTaskMemFree(olename);
  289. RETURN_FALSE;
  290. }
  291. php_com_throw_exception(res, NULL TSRMLS_CC);
  292. } else {
  293. php_com_throw_exception(res, NULL TSRMLS_CC);
  294. }
  295. }
  296. /* }}} */
  297. /* {{{ proto bool COMPersistHelper::SaveToFile(string filename [, bool remember])
  298. Persist object data to file, via IPersistFile::Save */
  299. CPH_METHOD(SaveToFile)
  300. {
  301. HRESULT res;
  302. char *filename, *fullpath = NULL;
  303. int filename_len;
  304. zend_bool remember = TRUE;
  305. OLECHAR *olefilename = NULL;
  306. CPH_FETCH();
  307. CPH_NO_OBJ();
  308. res = get_persist_file(helper);
  309. if (helper->ipf) {
  310. if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p!|b",
  311. &filename, &filename_len, &remember)) {
  312. php_com_throw_exception(E_INVALIDARG, "Invalid arguments" TSRMLS_CC);
  313. return;
  314. }
  315. if (filename) {
  316. fullpath = expand_filepath(filename, NULL TSRMLS_CC);
  317. if (!fullpath) {
  318. RETURN_FALSE;
  319. }
  320. if (php_check_open_basedir(fullpath TSRMLS_CC)) {
  321. efree(fullpath);
  322. RETURN_FALSE;
  323. }
  324. olefilename = php_com_string_to_olestring(filename, strlen(fullpath), helper->codepage TSRMLS_CC);
  325. efree(fullpath);
  326. }
  327. res = IPersistFile_Save(helper->ipf, olefilename, remember);
  328. if (SUCCEEDED(res)) {
  329. if (!olefilename) {
  330. res = IPersistFile_GetCurFile(helper->ipf, &olefilename);
  331. if (S_OK == res) {
  332. IPersistFile_SaveCompleted(helper->ipf, olefilename);
  333. CoTaskMemFree(olefilename);
  334. olefilename = NULL;
  335. }
  336. } else if (remember) {
  337. IPersistFile_SaveCompleted(helper->ipf, olefilename);
  338. }
  339. }
  340. if (olefilename) {
  341. efree(olefilename);
  342. }
  343. if (FAILED(res)) {
  344. php_com_throw_exception(res, NULL TSRMLS_CC);
  345. }
  346. } else {
  347. php_com_throw_exception(res, NULL TSRMLS_CC);
  348. }
  349. }
  350. /* }}} */
  351. /* {{{ proto bool COMPersistHelper::LoadFromFile(string filename [, int flags])
  352. Load object data from file, via IPersistFile::Load */
  353. CPH_METHOD(LoadFromFile)
  354. {
  355. HRESULT res;
  356. char *filename, *fullpath;
  357. int filename_len;
  358. long flags = 0;
  359. OLECHAR *olefilename;
  360. CPH_FETCH();
  361. CPH_NO_OBJ();
  362. res = get_persist_file(helper);
  363. if (helper->ipf) {
  364. if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p|l",
  365. &filename, &filename_len, &flags)) {
  366. php_com_throw_exception(E_INVALIDARG, "Invalid arguments" TSRMLS_CC);
  367. return;
  368. }
  369. if (!(fullpath = expand_filepath(filename, NULL TSRMLS_CC))) {
  370. RETURN_FALSE;
  371. }
  372. if (php_check_open_basedir(fullpath TSRMLS_CC)) {
  373. efree(fullpath);
  374. RETURN_FALSE;
  375. }
  376. olefilename = php_com_string_to_olestring(fullpath, strlen(fullpath), helper->codepage TSRMLS_CC);
  377. efree(fullpath);
  378. res = IPersistFile_Load(helper->ipf, olefilename, flags);
  379. efree(olefilename);
  380. if (FAILED(res)) {
  381. php_com_throw_exception(res, NULL TSRMLS_CC);
  382. }
  383. } else {
  384. php_com_throw_exception(res, NULL TSRMLS_CC);
  385. }
  386. }
  387. /* }}} */
  388. /* {{{ proto int COMPersistHelper::GetMaxStreamSize()
  389. Gets maximum stream size required to store the object data, via IPersistStream::GetSizeMax (or IPersistStreamInit::GetSizeMax) */
  390. CPH_METHOD(GetMaxStreamSize)
  391. {
  392. HRESULT res;
  393. ULARGE_INTEGER size;
  394. CPH_FETCH();
  395. CPH_NO_OBJ();
  396. res = get_persist_stream_init(helper);
  397. if (helper->ipsi) {
  398. res = IPersistStreamInit_GetSizeMax(helper->ipsi, &size);
  399. } else {
  400. res = get_persist_stream(helper);
  401. if (helper->ips) {
  402. res = IPersistStream_GetSizeMax(helper->ips, &size);
  403. } else {
  404. php_com_throw_exception(res, NULL TSRMLS_CC);
  405. return;
  406. }
  407. }
  408. if (res != S_OK) {
  409. php_com_throw_exception(res, NULL TSRMLS_CC);
  410. } else {
  411. /* TODO: handle 64 bit properly */
  412. RETURN_LONG((LONG)size.QuadPart);
  413. }
  414. }
  415. /* }}} */
  416. /* {{{ proto int COMPersistHelper::InitNew()
  417. Initializes the object to a default state, via IPersistStreamInit::InitNew */
  418. CPH_METHOD(InitNew)
  419. {
  420. HRESULT res;
  421. CPH_FETCH();
  422. CPH_NO_OBJ();
  423. res = get_persist_stream_init(helper);
  424. if (helper->ipsi) {
  425. res = IPersistStreamInit_InitNew(helper->ipsi);
  426. if (res != S_OK) {
  427. php_com_throw_exception(res, NULL TSRMLS_CC);
  428. } else {
  429. RETURN_TRUE;
  430. }
  431. } else {
  432. php_com_throw_exception(res, NULL TSRMLS_CC);
  433. }
  434. }
  435. /* }}} */
  436. /* {{{ proto mixed COMPersistHelper::LoadFromStream(resource stream)
  437. Initializes an object from the stream where it was previously saved, via IPersistStream::Load or OleLoadFromStream */
  438. CPH_METHOD(LoadFromStream)
  439. {
  440. zval *zstm;
  441. php_stream *stream;
  442. IStream *stm = NULL;
  443. HRESULT res;
  444. CPH_FETCH();
  445. if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zstm)) {
  446. php_com_throw_exception(E_INVALIDARG, "invalid arguments" TSRMLS_CC);
  447. return;
  448. }
  449. php_stream_from_zval_no_verify(stream, &zstm);
  450. if (stream == NULL) {
  451. php_com_throw_exception(E_INVALIDARG, "expected a stream" TSRMLS_CC);
  452. return;
  453. }
  454. stm = php_com_wrapper_export_stream(stream TSRMLS_CC);
  455. if (stm == NULL) {
  456. php_com_throw_exception(E_UNEXPECTED, "failed to wrap stream" TSRMLS_CC);
  457. return;
  458. }
  459. res = S_OK;
  460. RETVAL_TRUE;
  461. if (helper->unk == NULL) {
  462. IDispatch *disp = NULL;
  463. /* we need to create an object and load using OleLoadFromStream */
  464. res = OleLoadFromStream(stm, &IID_IDispatch, &disp);
  465. if (SUCCEEDED(res)) {
  466. php_com_wrap_dispatch(return_value, disp, COMG(code_page) TSRMLS_CC);
  467. }
  468. } else {
  469. res = get_persist_stream_init(helper);
  470. if (helper->ipsi) {
  471. res = IPersistStreamInit_Load(helper->ipsi, stm);
  472. } else {
  473. res = get_persist_stream(helper);
  474. if (helper->ips) {
  475. res = IPersistStreamInit_Load(helper->ipsi, stm);
  476. }
  477. }
  478. }
  479. IStream_Release(stm);
  480. if (FAILED(res)) {
  481. php_com_throw_exception(res, NULL TSRMLS_CC);
  482. RETURN_NULL();
  483. }
  484. }
  485. /* }}} */
  486. /* {{{ proto int COMPersistHelper::SaveToStream(resource stream)
  487. Saves the object to a stream, via IPersistStream::Save */
  488. CPH_METHOD(SaveToStream)
  489. {
  490. zval *zstm;
  491. php_stream *stream;
  492. IStream *stm = NULL;
  493. HRESULT res;
  494. CPH_FETCH();
  495. CPH_NO_OBJ();
  496. if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zstm)) {
  497. php_com_throw_exception(E_INVALIDARG, "invalid arguments" TSRMLS_CC);
  498. return;
  499. }
  500. php_stream_from_zval_no_verify(stream, &zstm);
  501. if (stream == NULL) {
  502. php_com_throw_exception(E_INVALIDARG, "expected a stream" TSRMLS_CC);
  503. return;
  504. }
  505. stm = php_com_wrapper_export_stream(stream TSRMLS_CC);
  506. if (stm == NULL) {
  507. php_com_throw_exception(E_UNEXPECTED, "failed to wrap stream" TSRMLS_CC);
  508. return;
  509. }
  510. res = get_persist_stream_init(helper);
  511. if (helper->ipsi) {
  512. res = IPersistStreamInit_Save(helper->ipsi, stm, TRUE);
  513. } else {
  514. res = get_persist_stream(helper);
  515. if (helper->ips) {
  516. res = IPersistStream_Save(helper->ips, stm, TRUE);
  517. }
  518. }
  519. IStream_Release(stm);
  520. if (FAILED(res)) {
  521. php_com_throw_exception(res, NULL TSRMLS_CC);
  522. return;
  523. }
  524. RETURN_TRUE;
  525. }
  526. /* }}} */
  527. /* {{{ proto int COMPersistHelper::__construct([object com_object])
  528. Creates a persistence helper object, usually associated with a com_object */
  529. CPH_METHOD(__construct)
  530. {
  531. php_com_dotnet_object *obj = NULL;
  532. zval *zobj = NULL;
  533. CPH_FETCH();
  534. if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|O!",
  535. &zobj, php_com_variant_class_entry)) {
  536. php_com_throw_exception(E_INVALIDARG, "invalid arguments" TSRMLS_CC);
  537. return;
  538. }
  539. if (!zobj) {
  540. return;
  541. }
  542. obj = CDNO_FETCH(zobj);
  543. if (V_VT(&obj->v) != VT_DISPATCH || V_DISPATCH(&obj->v) == NULL) {
  544. php_com_throw_exception(E_INVALIDARG, "parameter must represent an IDispatch COM object" TSRMLS_CC);
  545. return;
  546. }
  547. /* it is always safe to cast an interface to IUnknown */
  548. helper->unk = (IUnknown*)V_DISPATCH(&obj->v);
  549. IUnknown_AddRef(helper->unk);
  550. helper->codepage = obj->code_page;
  551. }
  552. /* }}} */
  553. static const zend_function_entry com_persist_helper_methods[] = {
  554. CPH_ME(__construct, NULL)
  555. CPH_ME(GetCurFileName, NULL)
  556. CPH_ME(SaveToFile, NULL)
  557. CPH_ME(LoadFromFile, NULL)
  558. CPH_ME(GetMaxStreamSize, NULL)
  559. CPH_ME(InitNew, NULL)
  560. CPH_ME(LoadFromStream, NULL)
  561. CPH_ME(SaveToStream, NULL)
  562. PHP_FE_END
  563. };
  564. static void helper_free_storage(void *obj TSRMLS_DC)
  565. {
  566. php_com_persist_helper *object = (php_com_persist_helper*)obj;
  567. if (object->ipf) {
  568. IPersistFile_Release(object->ipf);
  569. }
  570. if (object->ips) {
  571. IPersistStream_Release(object->ips);
  572. }
  573. if (object->ipsi) {
  574. IPersistStreamInit_Release(object->ipsi);
  575. }
  576. if (object->unk) {
  577. IUnknown_Release(object->unk);
  578. }
  579. zend_object_std_dtor(&object->std TSRMLS_CC);
  580. efree(object);
  581. }
  582. static void helper_clone(void *obj, void **clone_ptr TSRMLS_DC)
  583. {
  584. php_com_persist_helper *clone, *object = (php_com_persist_helper*)obj;
  585. clone = emalloc(sizeof(*object));
  586. memcpy(clone, object, sizeof(*object));
  587. *clone_ptr = clone;
  588. zend_object_std_init(&clone->std, object->std.ce TSRMLS_CC);
  589. if (clone->ipf) {
  590. IPersistFile_AddRef(clone->ipf);
  591. }
  592. if (clone->ips) {
  593. IPersistStream_AddRef(clone->ips);
  594. }
  595. if (clone->ipsi) {
  596. IPersistStreamInit_AddRef(clone->ipsi);
  597. }
  598. if (clone->unk) {
  599. IUnknown_AddRef(clone->unk);
  600. }
  601. }
  602. static zend_object_value helper_new(zend_class_entry *ce TSRMLS_DC)
  603. {
  604. php_com_persist_helper *helper;
  605. zend_object_value retval;
  606. helper = emalloc(sizeof(*helper));
  607. memset(helper, 0, sizeof(*helper));
  608. zend_object_std_init(&helper->std, helper_ce TSRMLS_CC);
  609. retval.handle = zend_objects_store_put(helper, NULL, helper_free_storage, helper_clone TSRMLS_CC);
  610. retval.handlers = &helper_handlers;
  611. return retval;
  612. }
  613. int php_com_persist_minit(INIT_FUNC_ARGS)
  614. {
  615. zend_class_entry ce;
  616. memcpy(&helper_handlers, zend_get_std_object_handlers(), sizeof(helper_handlers));
  617. helper_handlers.clone_obj = NULL;
  618. INIT_CLASS_ENTRY(ce, "COMPersistHelper", com_persist_helper_methods);
  619. ce.create_object = helper_new;
  620. helper_ce = zend_register_internal_class(&ce TSRMLS_CC);
  621. helper_ce->ce_flags |= ZEND_ACC_FINAL;
  622. le_istream = zend_register_list_destructors_ex(istream_dtor,
  623. NULL, "com_dotnet_istream_wrapper", module_number);
  624. return SUCCESS;
  625. }
  626. /*
  627. * Local variables:
  628. * tab-width: 4
  629. * c-basic-offset: 4
  630. * End:
  631. * vim600: noet sw=4 ts=4 fdm=marker
  632. * vim<600: noet sw=4 ts=4
  633. */