root/ext/com_dotnet/com_persist.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. istream_dtor
  2. stm_queryinterface
  3. stm_addref
  4. stm_release
  5. stm_read
  6. stm_write
  7. stm_seek
  8. stm_set_size
  9. stm_copy_to
  10. stm_commit
  11. stm_revert
  12. stm_lock_region
  13. stm_unlock_region
  14. stm_stat
  15. stm_clone
  16. istream_destructor
  17. php_com_wrapper_export_stream
  18. get_persist_stream
  19. get_persist_stream_init
  20. get_persist_file
  21. CPH_METHOD
  22. CPH_METHOD
  23. CPH_METHOD
  24. CPH_METHOD
  25. CPH_METHOD
  26. CPH_METHOD
  27. CPH_METHOD
  28. CPH_METHOD
  29. helper_free_storage
  30. helper_clone
  31. helper_new
  32. php_com_persist_minit

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 5                                                        |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1997-2016 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 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         /* [in] */ REFIID riid,
  70         /* [iid_is][out] */ 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                 /* destroy it */
 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                 /* we don't support 64-bit offsets */
 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         /* NOP */
 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 /* {{{ proto string COMPersistHelper::GetCurFile()
 336    Determines the filename into which an object will be saved, or false if none is set, via IPersistFile::GetCurFile */
 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 /* {{{ proto bool COMPersistHelper::SaveToFile(string filename [, bool remember])
 368    Persist object data to file, via IPersistFile::Save */
 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 /* {{{ proto bool COMPersistHelper::LoadFromFile(string filename [, int flags])
 431    Load object data from file, via IPersistFile::Load */
 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 /* {{{ proto int COMPersistHelper::GetMaxStreamSize()
 478    Gets maximum stream size required to store the object data, via IPersistStream::GetSizeMax (or IPersistStreamInit::GetSizeMax) */
 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                 /* TODO: handle 64 bit properly */
 504                 RETURN_LONG((LONG)size.QuadPart);
 505         }
 506 }
 507 /* }}} */
 508 
 509 /* {{{ proto int COMPersistHelper::InitNew()
 510    Initializes the object to a default state, via IPersistStreamInit::InitNew */
 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 /* {{{ proto mixed COMPersistHelper::LoadFromStream(resource stream)
 534    Initializes an object from the stream where it was previously saved, via IPersistStream::Load or OleLoadFromStream */
 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                 /* we need to create an object and load using OleLoadFromStream */
 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 /* {{{ proto int COMPersistHelper::SaveToStream(resource stream)
 594    Saves the object to a stream, via IPersistStream::Save */
 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 /* {{{ proto int COMPersistHelper::__construct([object com_object])
 645    Creates a persistence helper object, usually associated with a com_object */
 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         /* it is always safe to cast an interface to IUnknown */
 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  * Local variables:
 772  * tab-width: 4
 773  * c-basic-offset: 4
 774  * End:
 775  * vim600: noet sw=4 ts=4 fdm=marker
 776  * vim<600: noet sw=4 ts=4
 777  */

/* [<][>][^][v][top][bottom][index][help] */