123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735 |
- /*
- +----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Author: Wez Furlong <wez@thebrainroom.com> |
- +----------------------------------------------------------------------+
- */
- /* Infrastructure for working with persistent COM objects.
- * Implements: IStream* wrapper for PHP streams.
- * TODO: Magic __wakeup and __sleep handlers for serialization
- * (can wait till 5.1) */
- #ifdef HAVE_CONFIG_H
- #include "config.h"
- #endif
- #include "php.h"
- #include "php_ini.h"
- #include "ext/standard/info.h"
- #include "php_com_dotnet.h"
- #include "php_com_dotnet_internal.h"
- #include "Zend/zend_exceptions.h"
- #include "com_persist_arginfo.h"
- /* {{{ expose php_stream as a COM IStream */
- typedef struct {
- CONST_VTBL struct IStreamVtbl *lpVtbl;
- DWORD engine_thread;
- LONG refcount;
- php_stream *stream;
- zend_resource *res;
- } php_istream;
- static int le_istream;
- static void istream_destructor(php_istream *stm);
- static void istream_dtor(zend_resource *rsrc)
- {
- php_istream *stm = (php_istream *)rsrc->ptr;
- istream_destructor(stm);
- }
- #define FETCH_STM() \
- php_istream *stm = (php_istream*)This; \
- if (GetCurrentThreadId() != stm->engine_thread) \
- return RPC_E_WRONG_THREAD;
- #define FETCH_STM_EX() \
- php_istream *stm = (php_istream*)This; \
- if (GetCurrentThreadId() != stm->engine_thread) \
- return RPC_E_WRONG_THREAD;
- static HRESULT STDMETHODCALLTYPE stm_queryinterface(
- IStream *This,
- /* [in] */ REFIID riid,
- /* [iid_is][out] */ void **ppvObject)
- {
- FETCH_STM_EX();
- if (IsEqualGUID(&IID_IUnknown, riid) ||
- IsEqualGUID(&IID_IStream, riid)) {
- *ppvObject = This;
- InterlockedIncrement(&stm->refcount);
- return S_OK;
- }
- *ppvObject = NULL;
- return E_NOINTERFACE;
- }
- static ULONG STDMETHODCALLTYPE stm_addref(IStream *This)
- {
- FETCH_STM_EX();
- return InterlockedIncrement(&stm->refcount);
- }
- static ULONG STDMETHODCALLTYPE stm_release(IStream *This)
- {
- ULONG ret;
- FETCH_STM();
- ret = InterlockedDecrement(&stm->refcount);
- if (ret == 0) {
- /* destroy it */
- if (stm->res)
- zend_list_delete(stm->res);
- }
- return ret;
- }
- static HRESULT STDMETHODCALLTYPE stm_read(IStream *This, void *pv, ULONG cb, ULONG *pcbRead)
- {
- ULONG nread;
- FETCH_STM();
- nread = (ULONG)php_stream_read(stm->stream, pv, cb);
- if (pcbRead) {
- *pcbRead = nread > 0 ? nread : 0;
- }
- if (nread > 0) {
- return S_OK;
- }
- return S_FALSE;
- }
- static HRESULT STDMETHODCALLTYPE stm_write(IStream *This, void const *pv, ULONG cb, ULONG *pcbWritten)
- {
- ssize_t nwrote;
- FETCH_STM();
- nwrote = php_stream_write(stm->stream, pv, cb);
- if (pcbWritten) {
- *pcbWritten = nwrote > 0 ? (ULONG)nwrote : 0;
- }
- if (nwrote > 0) {
- return S_OK;
- }
- return S_FALSE;
- }
- static HRESULT STDMETHODCALLTYPE stm_seek(IStream *This, LARGE_INTEGER dlibMove,
- DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
- {
- off_t offset;
- int whence;
- int ret;
- FETCH_STM();
- switch (dwOrigin) {
- case STREAM_SEEK_SET: whence = SEEK_SET; break;
- case STREAM_SEEK_CUR: whence = SEEK_CUR; break;
- case STREAM_SEEK_END: whence = SEEK_END; break;
- default:
- return STG_E_INVALIDFUNCTION;
- }
- if (dlibMove.HighPart) {
- /* we don't support 64-bit offsets */
- return STG_E_INVALIDFUNCTION;
- }
- offset = (off_t) dlibMove.QuadPart;
- ret = php_stream_seek(stm->stream, offset, whence);
- if (plibNewPosition) {
- plibNewPosition->QuadPart = (ULONGLONG)(ret >= 0 ? ret : 0);
- }
- return ret >= 0 ? S_OK : STG_E_INVALIDFUNCTION;
- }
- static HRESULT STDMETHODCALLTYPE stm_set_size(IStream *This, ULARGE_INTEGER libNewSize)
- {
- FETCH_STM();
- if (libNewSize.HighPart) {
- return STG_E_INVALIDFUNCTION;
- }
- if (php_stream_truncate_supported(stm->stream)) {
- int ret = php_stream_truncate_set_size(stm->stream, (size_t)libNewSize.QuadPart);
- if (ret == 0) {
- return S_OK;
- }
- }
- return STG_E_INVALIDFUNCTION;
- }
- static HRESULT STDMETHODCALLTYPE stm_copy_to(IStream *This, IStream *pstm, ULARGE_INTEGER cb,
- ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
- {
- FETCH_STM_EX();
- return E_NOTIMPL;
- }
- static HRESULT STDMETHODCALLTYPE stm_commit(IStream *This, DWORD grfCommitFlags)
- {
- FETCH_STM();
- php_stream_flush(stm->stream);
- return S_OK;
- }
- static HRESULT STDMETHODCALLTYPE stm_revert(IStream *This)
- {
- /* NOP */
- return S_OK;
- }
- static HRESULT STDMETHODCALLTYPE stm_lock_region(IStream *This,
- ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD lockType)
- {
- return STG_E_INVALIDFUNCTION;
- }
- static HRESULT STDMETHODCALLTYPE stm_unlock_region(IStream *This,
- ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD lockType)
- {
- return STG_E_INVALIDFUNCTION;
- }
- static HRESULT STDMETHODCALLTYPE stm_stat(IStream *This,
- STATSTG *pstatstg, DWORD grfStatFlag)
- {
- return STG_E_INVALIDFUNCTION;
- }
- static HRESULT STDMETHODCALLTYPE stm_clone(IStream *This, IStream **ppstm)
- {
- return STG_E_INVALIDFUNCTION;
- }
- static struct IStreamVtbl php_istream_vtbl = {
- 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
- };
- static void istream_destructor(php_istream *stm)
- {
- if (stm->refcount > 0) {
- CoDisconnectObject((IUnknown*)stm, 0);
- }
- zend_list_delete(stm->stream->res);
- CoTaskMemFree(stm);
- }
- /* }}} */
- PHP_COM_DOTNET_API IStream *php_com_wrapper_export_stream(php_stream *stream)
- {
- php_istream *stm = (php_istream*)CoTaskMemAlloc(sizeof(*stm));
- if (stm == NULL)
- return NULL;
- memset(stm, 0, sizeof(*stm));
- stm->engine_thread = GetCurrentThreadId();
- stm->lpVtbl = &php_istream_vtbl;
- stm->refcount = 1;
- stm->stream = stream;
- GC_ADDREF(stream->res);
- stm->res = zend_register_resource(stm, le_istream);
- return (IStream*)stm;
- }
- #define CPH_METHOD(fname) PHP_METHOD(COMPersistHelper, fname)
- #define CPH_FETCH() php_com_persist_helper *helper = (php_com_persist_helper*)Z_OBJ_P(getThis());
- #define CPH_NO_OBJ() if (helper->unk == NULL) { php_com_throw_exception(E_INVALIDARG, "No COM object is associated with this helper instance"); RETURN_THROWS(); }
- typedef struct {
- zend_object std;
- long codepage;
- IUnknown *unk;
- IPersistStream *ips;
- IPersistStreamInit *ipsi;
- IPersistFile *ipf;
- } php_com_persist_helper;
- static zend_object_handlers helper_handlers;
- static zend_class_entry *helper_ce;
- static inline HRESULT get_persist_stream(php_com_persist_helper *helper)
- {
- if (!helper->ips && helper->unk) {
- return IUnknown_QueryInterface(helper->unk, &IID_IPersistStream, &helper->ips);
- }
- return helper->ips ? S_OK : E_NOTIMPL;
- }
- static inline HRESULT get_persist_stream_init(php_com_persist_helper *helper)
- {
- if (!helper->ipsi && helper->unk) {
- return IUnknown_QueryInterface(helper->unk, &IID_IPersistStreamInit, &helper->ipsi);
- }
- return helper->ipsi ? S_OK : E_NOTIMPL;
- }
- static inline HRESULT get_persist_file(php_com_persist_helper *helper)
- {
- if (!helper->ipf && helper->unk) {
- return IUnknown_QueryInterface(helper->unk, &IID_IPersistFile, &helper->ipf);
- }
- return helper->ipf ? S_OK : E_NOTIMPL;
- }
- /* {{{ Determines the filename into which an object will be saved, or false if none is set, via IPersistFile::GetCurFile */
- CPH_METHOD(GetCurFileName)
- {
- HRESULT res;
- OLECHAR *olename = NULL;
- CPH_FETCH();
- if (zend_parse_parameters_none() == FAILURE) {
- RETURN_THROWS();
- }
- CPH_NO_OBJ();
- res = get_persist_file(helper);
- if (helper->ipf) {
- res = IPersistFile_GetCurFile(helper->ipf, &olename);
- if (res == S_OK) {
- size_t len;
- char *str = php_com_olestring_to_string(olename,
- &len, helper->codepage);
- RETVAL_STRINGL(str, len);
- // TODO: avoid reallocarion???
- efree(str);
- CoTaskMemFree(olename);
- return;
- } else if (res == S_FALSE) {
- CoTaskMemFree(olename);
- RETURN_FALSE;
- }
- php_com_throw_exception(res, NULL);
- } else {
- php_com_throw_exception(res, NULL);
- }
- }
- /* }}} */
- /* {{{ Persist object data to file, via IPersistFile::Save */
- CPH_METHOD(SaveToFile)
- {
- HRESULT res;
- char *filename, *fullpath = NULL;
- size_t filename_len;
- bool remember = TRUE;
- OLECHAR *olefilename = NULL;
- CPH_FETCH();
- if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "p!|b",
- &filename, &filename_len, &remember)) {
- RETURN_THROWS();
- }
- CPH_NO_OBJ();
- res = get_persist_file(helper);
- if (helper->ipf) {
- if (filename) {
- fullpath = expand_filepath(filename, NULL);
- if (!fullpath) {
- RETURN_FALSE;
- }
- if (php_check_open_basedir(fullpath)) {
- efree(fullpath);
- RETURN_FALSE;
- }
- olefilename = php_com_string_to_olestring(fullpath, strlen(fullpath), helper->codepage);
- efree(fullpath);
- }
- res = IPersistFile_Save(helper->ipf, olefilename, remember);
- if (SUCCEEDED(res)) {
- if (!olefilename) {
- res = IPersistFile_GetCurFile(helper->ipf, &olefilename);
- if (S_OK == res) {
- IPersistFile_SaveCompleted(helper->ipf, olefilename);
- CoTaskMemFree(olefilename);
- olefilename = NULL;
- }
- } else if (remember) {
- IPersistFile_SaveCompleted(helper->ipf, olefilename);
- }
- }
- if (olefilename) {
- efree(olefilename);
- }
- if (FAILED(res)) {
- php_com_throw_exception(res, NULL);
- }
- } else {
- php_com_throw_exception(res, NULL);
- }
- }
- /* }}} */
- /* {{{ Load object data from file, via IPersistFile::Load */
- CPH_METHOD(LoadFromFile)
- {
- HRESULT res;
- char *filename, *fullpath;
- size_t filename_len;
- zend_long flags = 0;
- OLECHAR *olefilename;
- CPH_FETCH();
- if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "p|l",
- &filename, &filename_len, &flags)) {
- RETURN_THROWS();
- }
- CPH_NO_OBJ();
- res = get_persist_file(helper);
- if (helper->ipf) {
- if (!(fullpath = expand_filepath(filename, NULL))) {
- RETURN_FALSE;
- }
- if (php_check_open_basedir(fullpath)) {
- efree(fullpath);
- RETURN_FALSE;
- }
- olefilename = php_com_string_to_olestring(fullpath, strlen(fullpath), helper->codepage);
- efree(fullpath);
- res = IPersistFile_Load(helper->ipf, olefilename, (DWORD)flags);
- efree(olefilename);
- if (FAILED(res)) {
- php_com_throw_exception(res, NULL);
- }
- } else {
- php_com_throw_exception(res, NULL);
- }
- }
- /* }}} */
- /* {{{ Gets maximum stream size required to store the object data, via IPersistStream::GetSizeMax (or IPersistStreamInit::GetSizeMax) */
- CPH_METHOD(GetMaxStreamSize)
- {
- HRESULT res;
- ULARGE_INTEGER size;
- CPH_FETCH();
- if (zend_parse_parameters_none() == FAILURE) {
- RETURN_THROWS();
- }
- CPH_NO_OBJ();
- res = get_persist_stream_init(helper);
- if (helper->ipsi) {
- res = IPersistStreamInit_GetSizeMax(helper->ipsi, &size);
- } else {
- res = get_persist_stream(helper);
- if (helper->ips) {
- res = IPersistStream_GetSizeMax(helper->ips, &size);
- } else {
- php_com_throw_exception(res, NULL);
- RETURN_THROWS();
- }
- }
- if (res != S_OK) {
- php_com_throw_exception(res, NULL);
- } else {
- /* TODO: handle 64 bit properly */
- RETURN_LONG((zend_long)size.QuadPart);
- }
- }
- /* }}} */
- /* {{{ Initializes the object to a default state, via IPersistStreamInit::InitNew */
- CPH_METHOD(InitNew)
- {
- HRESULT res;
- CPH_FETCH();
- if (zend_parse_parameters_none() == FAILURE) {
- RETURN_THROWS();
- }
- CPH_NO_OBJ();
- res = get_persist_stream_init(helper);
- if (helper->ipsi) {
- res = IPersistStreamInit_InitNew(helper->ipsi);
- if (res != S_OK) {
- php_com_throw_exception(res, NULL);
- } else {
- RETURN_TRUE;
- }
- } else {
- php_com_throw_exception(res, NULL);
- }
- }
- /* }}} */
- /* {{{ Initializes an object from the stream where it was previously saved, via IPersistStream::Load or OleLoadFromStream */
- CPH_METHOD(LoadFromStream)
- {
- zval *zstm;
- php_stream *stream;
- IStream *stm = NULL;
- HRESULT res;
- CPH_FETCH();
- if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zstm)) {
- RETURN_THROWS();
- }
- php_stream_from_zval_no_verify(stream, zstm);
- if (stream == NULL) {
- php_com_throw_exception(E_INVALIDARG, "expected a stream");
- RETURN_THROWS();
- }
- stm = php_com_wrapper_export_stream(stream);
- if (stm == NULL) {
- php_com_throw_exception(E_UNEXPECTED, "failed to wrap stream");
- RETURN_THROWS();
- }
- res = S_OK;
- RETVAL_TRUE;
- if (helper->unk == NULL) {
- IDispatch *disp = NULL;
- /* we need to create an object and load using OleLoadFromStream */
- res = OleLoadFromStream(stm, &IID_IDispatch, &disp);
- if (SUCCEEDED(res)) {
- php_com_wrap_dispatch(return_value, disp, COMG(code_page));
- }
- } else {
- res = get_persist_stream_init(helper);
- if (helper->ipsi) {
- res = IPersistStreamInit_Load(helper->ipsi, stm);
- } else {
- res = get_persist_stream(helper);
- if (helper->ips) {
- res = IPersistStreamInit_Load(helper->ipsi, stm);
- }
- }
- }
- IStream_Release(stm);
- if (FAILED(res)) {
- php_com_throw_exception(res, NULL);
- RETURN_THROWS();
- }
- }
- /* }}} */
- /* {{{ Saves the object to a stream, via IPersistStream::Save */
- CPH_METHOD(SaveToStream)
- {
- zval *zstm;
- php_stream *stream;
- IStream *stm = NULL;
- HRESULT res;
- CPH_FETCH();
- CPH_NO_OBJ();
- if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zstm)) {
- RETURN_THROWS();
- }
- php_stream_from_zval_no_verify(stream, zstm);
- if (stream == NULL) {
- php_com_throw_exception(E_INVALIDARG, "expected a stream");
- RETURN_THROWS();
- }
- stm = php_com_wrapper_export_stream(stream);
- if (stm == NULL) {
- php_com_throw_exception(E_UNEXPECTED, "failed to wrap stream");
- RETURN_THROWS();
- }
- res = get_persist_stream_init(helper);
- if (helper->ipsi) {
- res = IPersistStreamInit_Save(helper->ipsi, stm, TRUE);
- } else {
- res = get_persist_stream(helper);
- if (helper->ips) {
- res = IPersistStream_Save(helper->ips, stm, TRUE);
- }
- }
- IStream_Release(stm);
- if (FAILED(res)) {
- php_com_throw_exception(res, NULL);
- RETURN_THROWS();
- }
- RETURN_TRUE;
- }
- /* }}} */
- /* {{{ Creates a persistence helper object, usually associated with a com_object */
- CPH_METHOD(__construct)
- {
- php_com_dotnet_object *obj = NULL;
- zval *zobj = NULL;
- CPH_FETCH();
- if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|O!",
- &zobj, php_com_variant_class_entry)) {
- RETURN_THROWS();
- }
- if (!zobj) {
- return;
- }
- obj = CDNO_FETCH(zobj);
- if (V_VT(&obj->v) != VT_DISPATCH || V_DISPATCH(&obj->v) == NULL) {
- php_com_throw_exception(E_INVALIDARG, "parameter must represent an IDispatch COM object");
- RETURN_THROWS();
- }
- /* it is always safe to cast an interface to IUnknown */
- helper->unk = (IUnknown*)V_DISPATCH(&obj->v);
- IUnknown_AddRef(helper->unk);
- helper->codepage = obj->code_page;
- }
- /* }}} */
- static void helper_free_storage(zend_object *obj)
- {
- php_com_persist_helper *object = (php_com_persist_helper*)obj;
- if (object->ipf) {
- IPersistFile_Release(object->ipf);
- }
- if (object->ips) {
- IPersistStream_Release(object->ips);
- }
- if (object->ipsi) {
- IPersistStreamInit_Release(object->ipsi);
- }
- if (object->unk) {
- IUnknown_Release(object->unk);
- }
- zend_object_std_dtor(&object->std);
- }
- static zend_object* helper_clone(zend_object *obj)
- {
- php_com_persist_helper *clone, *object = (php_com_persist_helper*) obj;
- clone = emalloc(sizeof(*object));
- memcpy(clone, object, sizeof(*object));
- zend_object_std_init(&clone->std, object->std.ce);
- if (clone->ipf) {
- IPersistFile_AddRef(clone->ipf);
- }
- if (clone->ips) {
- IPersistStream_AddRef(clone->ips);
- }
- if (clone->ipsi) {
- IPersistStreamInit_AddRef(clone->ipsi);
- }
- if (clone->unk) {
- IUnknown_AddRef(clone->unk);
- }
- return (zend_object*)clone;
- }
- static zend_object* helper_new(zend_class_entry *ce)
- {
- php_com_persist_helper *helper;
- helper = emalloc(sizeof(*helper));
- memset(helper, 0, sizeof(*helper));
- zend_object_std_init(&helper->std, helper_ce);
- helper->std.handlers = &helper_handlers;
- return &helper->std;
- }
- int php_com_persist_minit(INIT_FUNC_ARGS)
- {
- memcpy(&helper_handlers, &std_object_handlers, sizeof(helper_handlers));
- helper_handlers.free_obj = helper_free_storage;
- helper_handlers.clone_obj = helper_clone;
- helper_ce = register_class_COMPersistHelper();
- helper_ce->create_object = helper_new;
- le_istream = zend_register_list_destructors_ex(istream_dtor,
- NULL, "com_dotnet_istream_wrapper", module_number);
- return SUCCESS;
- }
|