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