Back to index

php5  5.3.10
com_persist.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Author: Wez Furlong  <wez@thebrainroom.com>                          |
00016    +----------------------------------------------------------------------+
00017  */
00018 
00019 /* $Id: com_persist.c 321634 2012-01-01 13:15:04Z felipe $ */
00020 
00021 /* Infrastructure for working with persistent COM objects.
00022  * Implements: IStream* wrapper for PHP streams.
00023  * TODO: Magic __wakeup and __sleep handlers for serialization 
00024  * (can wait till 5.1) */
00025 
00026 #ifdef HAVE_CONFIG_H
00027 #include "config.h"
00028 #endif
00029 
00030 #include "php.h"
00031 #include "php_ini.h"
00032 #include "ext/standard/info.h"
00033 #include "php_com_dotnet.h"
00034 #include "php_com_dotnet_internal.h"
00035 #include "Zend/zend_exceptions.h"
00036 
00037 /* {{{ expose php_stream as a COM IStream */
00038 
00039 typedef struct {
00040        CONST_VTBL struct IStreamVtbl *lpVtbl;
00041        DWORD engine_thread;
00042        LONG refcount;
00043        php_stream *stream;
00044        int id;
00045 } php_istream;
00046 
00047 static int le_istream;
00048 static void istream_destructor(php_istream *stm);
00049 
00050 static void istream_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
00051 {
00052        php_istream *stm = (php_istream *)rsrc->ptr;
00053        istream_destructor(stm);
00054 }
00055 
00056 #ifdef ZTS
00057 # define TSRMLS_FIXED()     TSRMLS_FETCH();
00058 #else
00059 # define TSRMLS_FIXED()
00060 #endif
00061 
00062 #define FETCH_STM()  \
00063        TSRMLS_FIXED() \
00064        php_istream *stm = (php_istream*)This; \
00065        if (GetCurrentThreadId() != stm->engine_thread) \
00066               return RPC_E_WRONG_THREAD;
00067 
00068 static HRESULT STDMETHODCALLTYPE stm_queryinterface(
00069        IStream *This,
00070        /* [in] */ REFIID riid,
00071        /* [iid_is][out] */ void **ppvObject)
00072 {
00073        FETCH_STM();
00074 
00075        if (IsEqualGUID(&IID_IUnknown, riid) ||
00076                      IsEqualGUID(&IID_IStream, riid)) {
00077               *ppvObject = This;
00078               InterlockedIncrement(&stm->refcount);
00079               return S_OK;
00080        }
00081 
00082        *ppvObject = NULL;
00083        return E_NOINTERFACE;
00084 }
00085 
00086 static ULONG STDMETHODCALLTYPE stm_addref(IStream *This)
00087 {
00088        FETCH_STM();
00089 
00090        return InterlockedIncrement(&stm->refcount);
00091 }
00092         
00093 static ULONG STDMETHODCALLTYPE stm_release(IStream *This)
00094 {
00095        ULONG ret;
00096        FETCH_STM();
00097 
00098        ret = InterlockedDecrement(&stm->refcount);
00099        if (ret == 0) {
00100               /* destroy it */
00101               if (stm->id)
00102                      zend_list_delete(stm->id);
00103        }
00104        return ret;
00105 }
00106 
00107 static HRESULT STDMETHODCALLTYPE stm_read(IStream *This, void *pv, ULONG cb, ULONG *pcbRead)
00108 {
00109        int nread;
00110        FETCH_STM();
00111 
00112        nread = php_stream_read(stm->stream, pv, cb);
00113 
00114        if (pcbRead) {
00115               *pcbRead = nread > 0 ? nread : 0;
00116        }
00117        if (nread > 0) {
00118               return S_OK;
00119        }
00120        return S_FALSE;
00121 }
00122 
00123 static HRESULT STDMETHODCALLTYPE stm_write(IStream *This, void const *pv, ULONG cb, ULONG *pcbWritten)
00124 {
00125        int nwrote;
00126        FETCH_STM();
00127 
00128        nwrote = php_stream_write(stm->stream, pv, cb);
00129 
00130        if (pcbWritten) {
00131               *pcbWritten = nwrote > 0 ? nwrote : 0;
00132        }
00133        if (nwrote > 0) {
00134               return S_OK;
00135        }
00136        return S_FALSE;
00137 }
00138 
00139 static HRESULT STDMETHODCALLTYPE stm_seek(IStream *This, LARGE_INTEGER dlibMove,
00140               DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
00141 {
00142        off_t offset;
00143        int whence;
00144        int ret;
00145        FETCH_STM();
00146 
00147        switch (dwOrigin) {
00148               case STREAM_SEEK_SET:       whence = SEEK_SET;   break;
00149               case STREAM_SEEK_CUR:       whence = SEEK_CUR;   break;
00150               case STREAM_SEEK_END:       whence = SEEK_END;   break;
00151               default:
00152                      return STG_E_INVALIDFUNCTION;
00153        }
00154        
00155        if (dlibMove.HighPart) {
00156               /* we don't support 64-bit offsets */
00157               return STG_E_INVALIDFUNCTION;
00158        }
00159        
00160        offset = (off_t) dlibMove.QuadPart;
00161 
00162        ret = php_stream_seek(stm->stream, offset, whence);
00163 
00164        if (plibNewPosition) {
00165               plibNewPosition->QuadPart = (ULONGLONG)(ret >= 0 ? ret : 0);
00166        }
00167 
00168        return ret >= 0 ? S_OK : STG_E_INVALIDFUNCTION;
00169 }
00170 
00171 static HRESULT STDMETHODCALLTYPE stm_set_size(IStream *This, ULARGE_INTEGER libNewSize)
00172 {
00173        FETCH_STM();
00174 
00175        if (libNewSize.HighPart) {
00176               return STG_E_INVALIDFUNCTION;
00177        }
00178        
00179        if (php_stream_truncate_supported(stm->stream)) {
00180               int ret = php_stream_truncate_set_size(stm->stream, (size_t)libNewSize.QuadPart);
00181 
00182               if (ret == 0) {
00183                      return S_OK;
00184               }
00185        }
00186 
00187        return STG_E_INVALIDFUNCTION;
00188 }
00189 
00190 static HRESULT STDMETHODCALLTYPE stm_copy_to(IStream *This, IStream *pstm, ULARGE_INTEGER cb,
00191               ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
00192 {
00193        FETCH_STM();
00194 
00195        return E_NOTIMPL;
00196 }
00197 
00198 static HRESULT STDMETHODCALLTYPE stm_commit(IStream *This, DWORD grfCommitFlags)
00199 {
00200        FETCH_STM();
00201 
00202        php_stream_flush(stm->stream);
00203 
00204        return S_OK;
00205 }
00206 
00207 static HRESULT STDMETHODCALLTYPE stm_revert(IStream *This)
00208 {
00209        /* NOP */
00210        return S_OK;
00211 }
00212 
00213 static HRESULT STDMETHODCALLTYPE stm_lock_region(IStream *This,
00214        ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD lockType)
00215 {
00216        return STG_E_INVALIDFUNCTION;
00217 }
00218 
00219 static HRESULT STDMETHODCALLTYPE stm_unlock_region(IStream *This,
00220               ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD lockType)
00221 {
00222        return STG_E_INVALIDFUNCTION;
00223 }
00224 
00225 static HRESULT STDMETHODCALLTYPE stm_stat(IStream *This,
00226               STATSTG *pstatstg, DWORD grfStatFlag)
00227 {
00228        return STG_E_INVALIDFUNCTION;
00229 }
00230 
00231 static HRESULT STDMETHODCALLTYPE stm_clone(IStream *This, IStream **ppstm)
00232 {
00233        return STG_E_INVALIDFUNCTION;
00234 }
00235 
00236 static struct IStreamVtbl php_istream_vtbl = {
00237        stm_queryinterface,
00238        stm_addref,
00239        stm_release,
00240        stm_read,
00241        stm_write,
00242        stm_seek,
00243        stm_set_size,
00244        stm_copy_to,
00245        stm_commit,
00246        stm_revert,
00247        stm_lock_region,
00248        stm_unlock_region,
00249        stm_stat,
00250        stm_clone
00251 };
00252 
00253 static void istream_destructor(php_istream *stm)
00254 {
00255        TSRMLS_FETCH();
00256 
00257        if (stm->id) {
00258               int id = stm->id;
00259               stm->id = 0;
00260               zend_list_delete(id);
00261               return;
00262        }
00263 
00264        if (stm->refcount > 0) {
00265               CoDisconnectObject((IUnknown*)stm, 0);
00266        }
00267 
00268        zend_list_delete(stm->stream->rsrc_id);
00269 
00270        CoTaskMemFree(stm);
00271 }
00272 /* }}} */
00273 
00274 PHPAPI IStream *php_com_wrapper_export_stream(php_stream *stream TSRMLS_DC)
00275 {
00276        php_istream *stm = (php_istream*)CoTaskMemAlloc(sizeof(*stm));
00277 
00278        if (stm == NULL)
00279               return NULL;
00280 
00281        memset(stm, 0, sizeof(*stm));
00282        stm->engine_thread = GetCurrentThreadId();
00283        stm->lpVtbl = &php_istream_vtbl;
00284        stm->refcount = 1;
00285        stm->stream = stream;
00286 
00287        zend_list_addref(stream->rsrc_id);
00288        stm->id = zend_list_insert(stm, le_istream);
00289 
00290        return (IStream*)stm;
00291 }
00292 
00293 #define CPH_ME(fname, arginfo)     PHP_ME(com_persist, fname, arginfo, ZEND_ACC_PUBLIC)
00294 #define CPH_SME(fname, arginfo)    PHP_ME(com_persist, fname, arginfo, ZEND_ACC_ALLOW_STATIC|ZEND_ACC_PUBLIC)
00295 #define CPH_METHOD(fname)          static PHP_METHOD(com_persist, fname)
00296        
00297 #define CPH_FETCH()                       php_com_persist_helper *helper = (php_com_persist_helper*)zend_object_store_get_object(getThis() TSRMLS_CC);
00298 
00299 #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; }
00300 
00301 typedef struct {
00302        zend_object                 std;
00303        long codepage;
00304        IUnknown                    *unk;
00305        IPersistStream              *ips;
00306        IPersistStreamInit   *ipsi;
00307        IPersistFile         *ipf;
00308 } php_com_persist_helper;
00309 
00310 static zend_object_handlers helper_handlers;
00311 static zend_class_entry *helper_ce;
00312 
00313 static inline HRESULT get_persist_stream(php_com_persist_helper *helper)
00314 {
00315        if (!helper->ips && helper->unk) {
00316               return IUnknown_QueryInterface(helper->unk, &IID_IPersistStream, &helper->ips);
00317        }
00318        return helper->ips ? S_OK : E_NOTIMPL;
00319 }
00320 
00321 static inline HRESULT get_persist_stream_init(php_com_persist_helper *helper)
00322 {
00323        if (!helper->ipsi && helper->unk) {
00324               return IUnknown_QueryInterface(helper->unk, &IID_IPersistStreamInit, &helper->ipsi);
00325        }
00326        return helper->ipsi ? S_OK : E_NOTIMPL;
00327 }
00328 
00329 static inline HRESULT get_persist_file(php_com_persist_helper *helper)
00330 {
00331        if (!helper->ipf && helper->unk) {
00332               return IUnknown_QueryInterface(helper->unk, &IID_IPersistFile, &helper->ipf);
00333        }
00334        return helper->ipf ? S_OK : E_NOTIMPL;
00335 }
00336 
00337 
00338 /* {{{ proto string COMPersistHelper::GetCurFile()
00339    Determines the filename into which an object will be saved, or false if none is set, via IPersistFile::GetCurFile */
00340 CPH_METHOD(GetCurFileName)
00341 {
00342        HRESULT res;
00343        OLECHAR *olename = NULL;
00344        CPH_FETCH();
00345 
00346        CPH_NO_OBJ();
00347        
00348        res = get_persist_file(helper);
00349        if (helper->ipf) {
00350               res = IPersistFile_GetCurFile(helper->ipf, &olename);
00351 
00352               if (res == S_OK) {
00353                      Z_TYPE_P(return_value) = IS_STRING;
00354                      Z_STRVAL_P(return_value) = php_com_olestring_to_string(olename,
00355                                &Z_STRLEN_P(return_value), helper->codepage TSRMLS_CC);
00356                      CoTaskMemFree(olename);
00357                      return;
00358               } else if (res == S_FALSE) {
00359                      CoTaskMemFree(olename);
00360                      RETURN_FALSE;
00361               }
00362               php_com_throw_exception(res, NULL TSRMLS_CC);
00363        } else {
00364               php_com_throw_exception(res, NULL TSRMLS_CC);
00365        }
00366 }
00367 /* }}} */
00368 
00369 
00370 /* {{{ proto bool COMPersistHelper::SaveToFile(string filename [, bool remember])
00371    Persist object data to file, via IPersistFile::Save */
00372 CPH_METHOD(SaveToFile)
00373 {
00374        HRESULT res;
00375        char *filename, *fullpath = NULL;
00376        int filename_len;
00377        zend_bool remember = TRUE;
00378        OLECHAR *olefilename = NULL;
00379        CPH_FETCH();
00380        
00381        CPH_NO_OBJ();
00382 
00383        res = get_persist_file(helper);
00384        if (helper->ipf) {
00385               if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s!|b",
00386                                    &filename, &filename_len, &remember)) {
00387                      php_com_throw_exception(E_INVALIDARG, "Invalid arguments" TSRMLS_CC);
00388                      return;
00389               }
00390 
00391               if (filename) {
00392                      if (strlen(filename) != filename_len) {
00393                             RETURN_FALSE;
00394                      }
00395                      fullpath = expand_filepath(filename, NULL TSRMLS_CC);
00396                      if (!fullpath) {
00397                             RETURN_FALSE;
00398                      }
00399        
00400                      if ((PG(safe_mode) && (!php_checkuid(fullpath, NULL, CHECKUID_CHECK_FILE_AND_DIR))) || 
00401                                    php_check_open_basedir(fullpath TSRMLS_CC)) {
00402                             efree(fullpath);
00403                             RETURN_FALSE;
00404                      }
00405 
00406                      olefilename = php_com_string_to_olestring(filename, strlen(fullpath), helper->codepage TSRMLS_CC);
00407                      efree(fullpath);
00408               }
00409               res = IPersistFile_Save(helper->ipf, olefilename, remember);
00410               if (SUCCEEDED(res)) {
00411                      if (!olefilename) {
00412                             res = IPersistFile_GetCurFile(helper->ipf, &olefilename);
00413                             if (S_OK == res) {
00414                                    IPersistFile_SaveCompleted(helper->ipf, olefilename);
00415                                    CoTaskMemFree(olefilename);
00416                                    olefilename = NULL;
00417                             }
00418                      } else if (remember) {
00419                             IPersistFile_SaveCompleted(helper->ipf, olefilename);
00420                      }
00421               }
00422                      
00423               if (olefilename) {
00424                      efree(olefilename);
00425               }
00426 
00427               if (FAILED(res)) {
00428                      php_com_throw_exception(res, NULL TSRMLS_CC);
00429               }
00430 
00431        } else {
00432               php_com_throw_exception(res, NULL TSRMLS_CC);
00433        }
00434 }
00435 /* }}} */
00436 
00437 /* {{{ proto bool COMPersistHelper::LoadFromFile(string filename [, int flags])
00438    Load object data from file, via IPersistFile::Load */
00439 CPH_METHOD(LoadFromFile)
00440 {
00441        HRESULT res;
00442        char *filename, *fullpath;
00443        int filename_len;
00444        long flags = 0;
00445        OLECHAR *olefilename;
00446        CPH_FETCH();
00447        
00448        CPH_NO_OBJ();
00449 
00450        res = get_persist_file(helper);
00451        if (helper->ipf) {
00452 
00453               if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l",
00454                                    &filename, &filename_len, &flags)) {
00455                      php_com_throw_exception(E_INVALIDARG, "Invalid arguments" TSRMLS_CC);
00456                      return;
00457               }
00458 
00459               if (strlen(filename) != filename_len) {
00460                      RETURN_FALSE;
00461               }
00462 
00463               if (!(fullpath = expand_filepath(filename, NULL TSRMLS_CC))) {
00464                      RETURN_FALSE;
00465               }
00466 
00467               if ((PG(safe_mode) && (!php_checkuid(fullpath, NULL, CHECKUID_CHECK_FILE_AND_DIR))) ||
00468                             php_check_open_basedir(fullpath TSRMLS_CC)) {
00469                      efree(fullpath);
00470                      RETURN_FALSE;
00471               }
00472 
00473               olefilename = php_com_string_to_olestring(fullpath, strlen(fullpath), helper->codepage TSRMLS_CC);
00474               efree(fullpath);
00475                      
00476               res = IPersistFile_Load(helper->ipf, olefilename, flags);
00477               efree(olefilename);
00478 
00479               if (FAILED(res)) {
00480                      php_com_throw_exception(res, NULL TSRMLS_CC);
00481               }
00482               
00483        } else {
00484               php_com_throw_exception(res, NULL TSRMLS_CC);
00485        }
00486 }
00487 /* }}} */
00488 
00489 /* {{{ proto int COMPersistHelper::GetMaxStreamSize()
00490    Gets maximum stream size required to store the object data, via IPersistStream::GetSizeMax (or IPersistStreamInit::GetSizeMax) */
00491 CPH_METHOD(GetMaxStreamSize)
00492 {
00493        HRESULT res;
00494        ULARGE_INTEGER size;
00495        CPH_FETCH();
00496        
00497        CPH_NO_OBJ();
00498        
00499        res = get_persist_stream_init(helper);
00500        if (helper->ipsi) {
00501               res = IPersistStreamInit_GetSizeMax(helper->ipsi, &size);
00502        } else {
00503               res = get_persist_stream(helper);
00504               if (helper->ips) {
00505                      res = IPersistStream_GetSizeMax(helper->ips, &size);
00506               } else {
00507                      php_com_throw_exception(res, NULL TSRMLS_CC);
00508                      return;
00509               }
00510        }
00511 
00512        if (res != S_OK) {
00513               php_com_throw_exception(res, NULL TSRMLS_CC);
00514        } else {
00515               /* TODO: handle 64 bit properly */
00516               RETURN_LONG((LONG)size.QuadPart);
00517        }
00518 }
00519 /* }}} */
00520 
00521 /* {{{ proto int COMPersistHelper::InitNew()
00522    Initializes the object to a default state, via IPersistStreamInit::InitNew */
00523 CPH_METHOD(InitNew)
00524 {
00525        HRESULT res;
00526        CPH_FETCH();
00527        
00528        CPH_NO_OBJ();
00529 
00530        res = get_persist_stream_init(helper);
00531        if (helper->ipsi) {
00532               res = IPersistStreamInit_InitNew(helper->ipsi);
00533 
00534               if (res != S_OK) {
00535                      php_com_throw_exception(res, NULL TSRMLS_CC);
00536               } else {
00537                      RETURN_TRUE;
00538               }
00539        } else {
00540               php_com_throw_exception(res, NULL TSRMLS_CC);
00541        }
00542 }
00543 /* }}} */
00544 
00545 /* {{{ proto mixed COMPersistHelper::LoadFromStream(resource stream)
00546    Initializes an object from the stream where it was previously saved, via IPersistStream::Load or OleLoadFromStream */
00547 CPH_METHOD(LoadFromStream)
00548 {
00549        zval *zstm;
00550        php_stream *stream;
00551        IStream *stm = NULL;
00552        HRESULT res;
00553        CPH_FETCH();
00554        
00555        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zstm)) {
00556               php_com_throw_exception(E_INVALIDARG, "invalid arguments" TSRMLS_CC);
00557               return;
00558        }
00559 
00560        php_stream_from_zval_no_verify(stream, &zstm);
00561        
00562        if (stream == NULL) {
00563               php_com_throw_exception(E_INVALIDARG, "expected a stream" TSRMLS_CC);
00564               return;
00565        }
00566 
00567        stm = php_com_wrapper_export_stream(stream TSRMLS_CC);
00568        if (stm == NULL) {
00569               php_com_throw_exception(E_UNEXPECTED, "failed to wrap stream" TSRMLS_CC);
00570               return;
00571        }
00572        
00573        res = S_OK;
00574        RETVAL_TRUE;
00575 
00576        if (helper->unk == NULL) {
00577               IDispatch *disp = NULL;
00578 
00579               /* we need to create an object and load using OleLoadFromStream */
00580               res = OleLoadFromStream(stm, &IID_IDispatch, &disp);
00581 
00582               if (SUCCEEDED(res)) {
00583                      php_com_wrap_dispatch(return_value, disp, COMG(code_page) TSRMLS_CC); 
00584               }
00585        } else {
00586               res = get_persist_stream_init(helper);
00587               if (helper->ipsi) {
00588                      res = IPersistStreamInit_Load(helper->ipsi, stm);
00589               } else {
00590                      res = get_persist_stream(helper);
00591                      if (helper->ips) {
00592                             res = IPersistStreamInit_Load(helper->ipsi, stm);
00593                      }
00594               }
00595        }
00596        IStream_Release(stm);
00597 
00598        if (FAILED(res)) {
00599               php_com_throw_exception(res, NULL TSRMLS_CC);
00600               RETURN_NULL();
00601        }
00602 }
00603 /* }}} */
00604 
00605 /* {{{ proto int COMPersistHelper::SaveToStream(resource stream)
00606    Saves the object to a stream, via IPersistStream::Save */
00607 CPH_METHOD(SaveToStream)
00608 {
00609        zval *zstm;
00610        php_stream *stream;
00611        IStream *stm = NULL;
00612        HRESULT res;
00613        CPH_FETCH();
00614        
00615        CPH_NO_OBJ();
00616        
00617        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zstm)) {
00618               php_com_throw_exception(E_INVALIDARG, "invalid arguments" TSRMLS_CC);
00619               return;
00620        }
00621 
00622        php_stream_from_zval_no_verify(stream, &zstm);
00623        
00624        if (stream == NULL) {
00625               php_com_throw_exception(E_INVALIDARG, "expected a stream" TSRMLS_CC);
00626               return;
00627        }
00628 
00629        stm = php_com_wrapper_export_stream(stream TSRMLS_CC);
00630        if (stm == NULL) {
00631               php_com_throw_exception(E_UNEXPECTED, "failed to wrap stream" TSRMLS_CC);
00632               return;
00633        }
00634        
00635        res = get_persist_stream_init(helper);
00636        if (helper->ipsi) {
00637               res = IPersistStreamInit_Save(helper->ipsi, stm, TRUE);
00638        } else {
00639               res = get_persist_stream(helper);
00640               if (helper->ips) {
00641                      res = IPersistStream_Save(helper->ips, stm, TRUE);
00642               }
00643        }
00644        
00645        IStream_Release(stm);
00646 
00647        if (FAILED(res)) {
00648               php_com_throw_exception(res, NULL TSRMLS_CC);
00649               return;
00650        }
00651 
00652        RETURN_TRUE;
00653 }
00654 /* }}} */
00655 
00656 /* {{{ proto int COMPersistHelper::__construct([object com_object])
00657    Creates a persistence helper object, usually associated with a com_object */
00658 CPH_METHOD(__construct)
00659 {
00660        php_com_dotnet_object *obj = NULL;
00661        zval *zobj = NULL;
00662        CPH_FETCH();
00663 
00664        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|O!",
00665                             &zobj, php_com_variant_class_entry)) {
00666               php_com_throw_exception(E_INVALIDARG, "invalid arguments" TSRMLS_CC);
00667               return;
00668        }
00669 
00670        if (!zobj) {
00671               return;
00672        }
00673        
00674        obj = CDNO_FETCH(zobj);
00675 
00676        if (V_VT(&obj->v) != VT_DISPATCH || V_DISPATCH(&obj->v) == NULL) {
00677               php_com_throw_exception(E_INVALIDARG, "parameter must represent an IDispatch COM object" TSRMLS_CC);
00678               return;
00679        }
00680 
00681        /* it is always safe to cast an interface to IUnknown */
00682        helper->unk = (IUnknown*)V_DISPATCH(&obj->v);
00683        IUnknown_AddRef(helper->unk);
00684        helper->codepage = obj->code_page;
00685 }
00686 /* }}} */
00687 
00688 
00689 
00690 
00691 static const zend_function_entry com_persist_helper_methods[] = {
00692        CPH_ME(__construct, NULL)
00693        CPH_ME(GetCurFileName, NULL)
00694        CPH_ME(SaveToFile, NULL)
00695        CPH_ME(LoadFromFile, NULL)
00696        CPH_ME(GetMaxStreamSize, NULL)
00697        CPH_ME(InitNew, NULL)
00698        CPH_ME(LoadFromStream, NULL)
00699        CPH_ME(SaveToStream, NULL)
00700        PHP_FE_END
00701 };
00702 
00703 static void helper_free_storage(void *obj TSRMLS_DC)
00704 {
00705        php_com_persist_helper *object = (php_com_persist_helper*)obj;
00706 
00707        if (object->ipf) {
00708               IPersistFile_Release(object->ipf);
00709        }
00710        if (object->ips) {
00711               IPersistStream_Release(object->ips);
00712        }
00713        if (object->ipsi) {
00714               IPersistStreamInit_Release(object->ipsi);
00715        }
00716        if (object->unk) {
00717               IUnknown_Release(object->unk);
00718        }
00719        zend_object_std_dtor(&object->std TSRMLS_CC);
00720        efree(object);
00721 }
00722 
00723 
00724 static void helper_clone(void *obj, void **clone_ptr TSRMLS_DC)
00725 {
00726        php_com_persist_helper *clone, *object = (php_com_persist_helper*)obj;
00727 
00728        clone = emalloc(sizeof(*object));
00729        memcpy(clone, object, sizeof(*object));
00730        *clone_ptr = clone;
00731 
00732        zend_object_std_init(&clone->std, object->std.ce TSRMLS_CC);
00733 
00734        if (clone->ipf) {
00735               IPersistFile_AddRef(clone->ipf);
00736        }
00737        if (clone->ips) {
00738               IPersistStream_AddRef(clone->ips);
00739        }
00740        if (clone->ipsi) {
00741               IPersistStreamInit_AddRef(clone->ipsi);
00742        }
00743        if (clone->unk) {
00744               IUnknown_AddRef(clone->unk);
00745        }
00746 }
00747 
00748 static zend_object_value helper_new(zend_class_entry *ce TSRMLS_DC)
00749 {
00750        php_com_persist_helper *helper;
00751        zend_object_value retval;
00752 
00753        helper = emalloc(sizeof(*helper));
00754        memset(helper, 0, sizeof(*helper));
00755 
00756        zend_object_std_init(&helper->std, helper_ce TSRMLS_CC);
00757        
00758        retval.handle = zend_objects_store_put(helper, NULL, helper_free_storage, helper_clone TSRMLS_CC);
00759        retval.handlers = &helper_handlers;
00760 
00761        return retval;
00762 }
00763 
00764 int php_com_persist_minit(INIT_FUNC_ARGS)
00765 {
00766        zend_class_entry ce;
00767 
00768        memcpy(&helper_handlers, zend_get_std_object_handlers(), sizeof(helper_handlers));
00769        helper_handlers.clone_obj = NULL;
00770 
00771        INIT_CLASS_ENTRY(ce, "COMPersistHelper", com_persist_helper_methods);
00772        ce.create_object = helper_new;
00773        helper_ce = zend_register_internal_class(&ce TSRMLS_CC);
00774        helper_ce->ce_flags |= ZEND_ACC_FINAL;
00775 
00776        le_istream = zend_register_list_destructors_ex(istream_dtor,
00777                      NULL, "com_dotnet_istream_wrapper", module_number);
00778        
00779        return SUCCESS;
00780 }
00781 
00782 /*
00783  * Local variables:
00784  * tab-width: 4
00785  * c-basic-offset: 4
00786  * End:
00787  * vim600: noet sw=4 ts=4 fdm=marker
00788  * vim<600: noet sw=4 ts=4
00789  */