This source file includes following definitions.
- istream_dtor
- stm_queryinterface
- stm_addref
- stm_release
- stm_read
- stm_write
- stm_seek
- stm_set_size
- stm_copy_to
- stm_commit
- stm_revert
- stm_lock_region
- stm_unlock_region
- stm_stat
- stm_clone
- istream_destructor
- php_com_wrapper_export_stream
- get_persist_stream
- get_persist_stream_init
- get_persist_file
- CPH_METHOD
- CPH_METHOD
- CPH_METHOD
- CPH_METHOD
- CPH_METHOD
- CPH_METHOD
- CPH_METHOD
- CPH_METHOD
- helper_free_storage
- helper_clone
- helper_new
- php_com_persist_minit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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
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
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
67 static HRESULT STDMETHODCALLTYPE stm_queryinterface(
68 IStream *This,
69 REFIID riid,
70 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
85 static ULONG STDMETHODCALLTYPE stm_addref(IStream *This)
86 {
87 FETCH_STM_EX();
88
89 return InterlockedIncrement(&stm->refcount);
90 }
91
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
100 if (stm->id)
101 zend_list_delete(stm->id);
102 }
103 return ret;
104 }
105
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
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
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
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
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
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
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
206 static HRESULT STDMETHODCALLTYPE stm_revert(IStream *This)
207 {
208
209 return S_OK;
210 }
211
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
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
224 static HRESULT STDMETHODCALLTYPE stm_stat(IStream *This,
225 STATSTG *pstatstg, DWORD grfStatFlag)
226 {
227 return STG_E_INVALIDFUNCTION;
228 }
229
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
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
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
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
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
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
336
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
368
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
431
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
478
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
504 RETURN_LONG((LONG)size.QuadPart);
505 }
506 }
507
508
509
510
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
534
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
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
594
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
645
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
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
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
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
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
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
772
773
774
775
776
777