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