mirror of
https://github.com/php/php-src.git
synced 2024-12-20 07:20:33 +08:00
778 lines
18 KiB
C
778 lines
18 KiB
C
/*
|
|
+----------------------------------------------------------------------+
|
|
| PHP Version 5 |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 1997-2013 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: |
|
|
| http://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> |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
/* $Id$ */
|
|
|
|
/* 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"
|
|
|
|
/* {{{ expose php_stream as a COM IStream */
|
|
|
|
typedef struct {
|
|
CONST_VTBL struct IStreamVtbl *lpVtbl;
|
|
DWORD engine_thread;
|
|
LONG refcount;
|
|
php_stream *stream;
|
|
int id;
|
|
} php_istream;
|
|
|
|
static int le_istream;
|
|
static void istream_destructor(php_istream *stm TSRMLS_DC);
|
|
|
|
static void istream_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
|
|
{
|
|
php_istream *stm = (php_istream *)rsrc->ptr;
|
|
istream_destructor(stm TSRMLS_CC);
|
|
}
|
|
|
|
#define FETCH_STM() \
|
|
php_istream *stm = (php_istream*)This; \
|
|
TSRMLS_FETCH(); \
|
|
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->id)
|
|
zend_list_delete(stm->id);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static HRESULT STDMETHODCALLTYPE stm_read(IStream *This, void *pv, ULONG cb, ULONG *pcbRead)
|
|
{
|
|
int nread;
|
|
FETCH_STM();
|
|
|
|
nread = 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)
|
|
{
|
|
int nwrote;
|
|
FETCH_STM();
|
|
|
|
nwrote = php_stream_write(stm->stream, pv, cb);
|
|
|
|
if (pcbWritten) {
|
|
*pcbWritten = nwrote > 0 ? 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 TSRMLS_DC)
|
|
{
|
|
if (stm->id) {
|
|
int id = stm->id;
|
|
stm->id = 0;
|
|
zend_list_delete(id);
|
|
return;
|
|
}
|
|
|
|
if (stm->refcount > 0) {
|
|
CoDisconnectObject((IUnknown*)stm, 0);
|
|
}
|
|
|
|
zend_list_delete(stm->stream->rsrc_id);
|
|
|
|
CoTaskMemFree(stm);
|
|
}
|
|
/* }}} */
|
|
|
|
PHP_COM_DOTNET_API IStream *php_com_wrapper_export_stream(php_stream *stream TSRMLS_DC)
|
|
{
|
|
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;
|
|
|
|
zend_list_addref(stream->rsrc_id);
|
|
stm->id = zend_list_insert(stm, le_istream TSRMLS_CC);
|
|
|
|
return (IStream*)stm;
|
|
}
|
|
|
|
#define CPH_ME(fname, arginfo) PHP_ME(com_persist, fname, arginfo, ZEND_ACC_PUBLIC)
|
|
#define CPH_SME(fname, arginfo) PHP_ME(com_persist, fname, arginfo, ZEND_ACC_ALLOW_STATIC|ZEND_ACC_PUBLIC)
|
|
#define CPH_METHOD(fname) static PHP_METHOD(com_persist, fname)
|
|
|
|
#define CPH_FETCH() php_com_persist_helper *helper = (php_com_persist_helper*)zend_object_store_get_object(getThis() TSRMLS_CC);
|
|
|
|
#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; }
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
/* {{{ proto string COMPersistHelper::GetCurFile()
|
|
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();
|
|
|
|
CPH_NO_OBJ();
|
|
|
|
res = get_persist_file(helper);
|
|
if (helper->ipf) {
|
|
res = IPersistFile_GetCurFile(helper->ipf, &olename);
|
|
|
|
if (res == S_OK) {
|
|
Z_TYPE_P(return_value) = IS_STRING;
|
|
Z_STRVAL_P(return_value) = php_com_olestring_to_string(olename,
|
|
&Z_STRLEN_P(return_value), helper->codepage TSRMLS_CC);
|
|
CoTaskMemFree(olename);
|
|
return;
|
|
} else if (res == S_FALSE) {
|
|
CoTaskMemFree(olename);
|
|
RETURN_FALSE;
|
|
}
|
|
php_com_throw_exception(res, NULL TSRMLS_CC);
|
|
} else {
|
|
php_com_throw_exception(res, NULL TSRMLS_CC);
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
|
|
/* {{{ proto bool COMPersistHelper::SaveToFile(string filename [, bool remember])
|
|
Persist object data to file, via IPersistFile::Save */
|
|
CPH_METHOD(SaveToFile)
|
|
{
|
|
HRESULT res;
|
|
char *filename, *fullpath = NULL;
|
|
int filename_len;
|
|
zend_bool remember = TRUE;
|
|
OLECHAR *olefilename = NULL;
|
|
CPH_FETCH();
|
|
|
|
CPH_NO_OBJ();
|
|
|
|
res = get_persist_file(helper);
|
|
if (helper->ipf) {
|
|
if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p!|b",
|
|
&filename, &filename_len, &remember)) {
|
|
php_com_throw_exception(E_INVALIDARG, "Invalid arguments" TSRMLS_CC);
|
|
return;
|
|
}
|
|
|
|
if (filename) {
|
|
fullpath = expand_filepath(filename, NULL TSRMLS_CC);
|
|
if (!fullpath) {
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if (php_check_open_basedir(fullpath TSRMLS_CC)) {
|
|
efree(fullpath);
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
olefilename = php_com_string_to_olestring(filename, strlen(fullpath), helper->codepage TSRMLS_CC);
|
|
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 TSRMLS_CC);
|
|
}
|
|
|
|
} else {
|
|
php_com_throw_exception(res, NULL TSRMLS_CC);
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool COMPersistHelper::LoadFromFile(string filename [, int flags])
|
|
Load object data from file, via IPersistFile::Load */
|
|
CPH_METHOD(LoadFromFile)
|
|
{
|
|
HRESULT res;
|
|
char *filename, *fullpath;
|
|
int filename_len;
|
|
long flags = 0;
|
|
OLECHAR *olefilename;
|
|
CPH_FETCH();
|
|
|
|
CPH_NO_OBJ();
|
|
|
|
res = get_persist_file(helper);
|
|
if (helper->ipf) {
|
|
|
|
if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p|l",
|
|
&filename, &filename_len, &flags)) {
|
|
php_com_throw_exception(E_INVALIDARG, "Invalid arguments" TSRMLS_CC);
|
|
return;
|
|
}
|
|
|
|
if (!(fullpath = expand_filepath(filename, NULL TSRMLS_CC))) {
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if (php_check_open_basedir(fullpath TSRMLS_CC)) {
|
|
efree(fullpath);
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
olefilename = php_com_string_to_olestring(fullpath, strlen(fullpath), helper->codepage TSRMLS_CC);
|
|
efree(fullpath);
|
|
|
|
res = IPersistFile_Load(helper->ipf, olefilename, flags);
|
|
efree(olefilename);
|
|
|
|
if (FAILED(res)) {
|
|
php_com_throw_exception(res, NULL TSRMLS_CC);
|
|
}
|
|
|
|
} else {
|
|
php_com_throw_exception(res, NULL TSRMLS_CC);
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto int COMPersistHelper::GetMaxStreamSize()
|
|
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();
|
|
|
|
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 TSRMLS_CC);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (res != S_OK) {
|
|
php_com_throw_exception(res, NULL TSRMLS_CC);
|
|
} else {
|
|
/* TODO: handle 64 bit properly */
|
|
RETURN_LONG((LONG)size.QuadPart);
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto int COMPersistHelper::InitNew()
|
|
Initializes the object to a default state, via IPersistStreamInit::InitNew */
|
|
CPH_METHOD(InitNew)
|
|
{
|
|
HRESULT res;
|
|
CPH_FETCH();
|
|
|
|
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 TSRMLS_CC);
|
|
} else {
|
|
RETURN_TRUE;
|
|
}
|
|
} else {
|
|
php_com_throw_exception(res, NULL TSRMLS_CC);
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto mixed COMPersistHelper::LoadFromStream(resource stream)
|
|
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() TSRMLS_CC, "r", &zstm)) {
|
|
php_com_throw_exception(E_INVALIDARG, "invalid arguments" TSRMLS_CC);
|
|
return;
|
|
}
|
|
|
|
php_stream_from_zval_no_verify(stream, &zstm);
|
|
|
|
if (stream == NULL) {
|
|
php_com_throw_exception(E_INVALIDARG, "expected a stream" TSRMLS_CC);
|
|
return;
|
|
}
|
|
|
|
stm = php_com_wrapper_export_stream(stream TSRMLS_CC);
|
|
if (stm == NULL) {
|
|
php_com_throw_exception(E_UNEXPECTED, "failed to wrap stream" TSRMLS_CC);
|
|
return;
|
|
}
|
|
|
|
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) TSRMLS_CC);
|
|
}
|
|
} 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 TSRMLS_CC);
|
|
RETURN_NULL();
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto int COMPersistHelper::SaveToStream(resource stream)
|
|
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() TSRMLS_CC, "r", &zstm)) {
|
|
php_com_throw_exception(E_INVALIDARG, "invalid arguments" TSRMLS_CC);
|
|
return;
|
|
}
|
|
|
|
php_stream_from_zval_no_verify(stream, &zstm);
|
|
|
|
if (stream == NULL) {
|
|
php_com_throw_exception(E_INVALIDARG, "expected a stream" TSRMLS_CC);
|
|
return;
|
|
}
|
|
|
|
stm = php_com_wrapper_export_stream(stream TSRMLS_CC);
|
|
if (stm == NULL) {
|
|
php_com_throw_exception(E_UNEXPECTED, "failed to wrap stream" TSRMLS_CC);
|
|
return;
|
|
}
|
|
|
|
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 TSRMLS_CC);
|
|
return;
|
|
}
|
|
|
|
RETURN_TRUE;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto int COMPersistHelper::__construct([object com_object])
|
|
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() TSRMLS_CC, "|O!",
|
|
&zobj, php_com_variant_class_entry)) {
|
|
php_com_throw_exception(E_INVALIDARG, "invalid arguments" TSRMLS_CC);
|
|
return;
|
|
}
|
|
|
|
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" TSRMLS_CC);
|
|
return;
|
|
}
|
|
|
|
/* 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 const zend_function_entry com_persist_helper_methods[] = {
|
|
CPH_ME(__construct, NULL)
|
|
CPH_ME(GetCurFileName, NULL)
|
|
CPH_ME(SaveToFile, NULL)
|
|
CPH_ME(LoadFromFile, NULL)
|
|
CPH_ME(GetMaxStreamSize, NULL)
|
|
CPH_ME(InitNew, NULL)
|
|
CPH_ME(LoadFromStream, NULL)
|
|
CPH_ME(SaveToStream, NULL)
|
|
PHP_FE_END
|
|
};
|
|
|
|
static void helper_free_storage(void *obj TSRMLS_DC)
|
|
{
|
|
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 TSRMLS_CC);
|
|
efree(object);
|
|
}
|
|
|
|
|
|
static void helper_clone(void *obj, void **clone_ptr TSRMLS_DC)
|
|
{
|
|
php_com_persist_helper *clone, *object = (php_com_persist_helper*)obj;
|
|
|
|
clone = emalloc(sizeof(*object));
|
|
memcpy(clone, object, sizeof(*object));
|
|
*clone_ptr = clone;
|
|
|
|
zend_object_std_init(&clone->std, object->std.ce TSRMLS_CC);
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
static zend_object_value helper_new(zend_class_entry *ce TSRMLS_DC)
|
|
{
|
|
php_com_persist_helper *helper;
|
|
zend_object_value retval;
|
|
|
|
helper = emalloc(sizeof(*helper));
|
|
memset(helper, 0, sizeof(*helper));
|
|
|
|
zend_object_std_init(&helper->std, helper_ce TSRMLS_CC);
|
|
|
|
retval.handle = zend_objects_store_put(helper, NULL, helper_free_storage, helper_clone TSRMLS_CC);
|
|
retval.handlers = &helper_handlers;
|
|
|
|
return retval;
|
|
}
|
|
|
|
int php_com_persist_minit(INIT_FUNC_ARGS)
|
|
{
|
|
zend_class_entry ce;
|
|
|
|
memcpy(&helper_handlers, zend_get_std_object_handlers(), sizeof(helper_handlers));
|
|
helper_handlers.clone_obj = NULL;
|
|
|
|
INIT_CLASS_ENTRY(ce, "COMPersistHelper", com_persist_helper_methods);
|
|
ce.create_object = helper_new;
|
|
helper_ce = zend_register_internal_class(&ce TSRMLS_CC);
|
|
helper_ce->ce_flags |= ZEND_ACC_FINAL;
|
|
|
|
le_istream = zend_register_list_destructors_ex(istream_dtor,
|
|
NULL, "com_dotnet_istream_wrapper", module_number);
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Local variables:
|
|
* tab-width: 4
|
|
* c-basic-offset: 4
|
|
* End:
|
|
* vim600: noet sw=4 ts=4 fdm=marker
|
|
* vim<600: noet sw=4 ts=4
|
|
*/
|