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