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