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 7                                                        |
   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         zend_resource *res;
  45 } php_istream;
  46 
  47 static int le_istream;
  48 static void istream_destructor(php_istream *stm);
  49 
  50 static void istream_dtor(zend_resource *rsrc)
  51 {
  52         php_istream *stm = (php_istream *)rsrc->ptr;
  53         istream_destructor(stm);
  54 }
  55 
  56 #define FETCH_STM()     \
  57         php_istream *stm = (php_istream*)This; \
  58         if (GetCurrentThreadId() != stm->engine_thread) \
  59                 return RPC_E_WRONG_THREAD;
  60 
  61 #define FETCH_STM_EX()  \
  62         php_istream *stm = (php_istream*)This;  \
  63         if (GetCurrentThreadId() != stm->engine_thread) \
  64                 return RPC_E_WRONG_THREAD;
  65 
  66 static HRESULT STDMETHODCALLTYPE stm_queryinterface(
  67         IStream *This,
  68         /* [in] */ REFIID riid,
  69         /* [iid_is][out] */ void **ppvObject)
  70 {
  71         FETCH_STM_EX();
  72 
  73         if (IsEqualGUID(&IID_IUnknown, riid) ||
  74                         IsEqualGUID(&IID_IStream, riid)) {
  75                 *ppvObject = This;
  76                 InterlockedIncrement(&stm->refcount);
  77                 return S_OK;
  78         }
  79 
  80         *ppvObject = NULL;
  81         return E_NOINTERFACE;
  82 }
  83 
  84 static ULONG STDMETHODCALLTYPE stm_addref(IStream *This)
  85 {
  86         FETCH_STM_EX();
  87 
  88         return InterlockedIncrement(&stm->refcount);
  89 }
  90 
  91 static ULONG STDMETHODCALLTYPE stm_release(IStream *This)
  92 {
  93         ULONG ret;
  94         FETCH_STM();
  95 
  96         ret = InterlockedDecrement(&stm->refcount);
  97         if (ret == 0) {
  98                 /* destroy it */
  99                 if (stm->res)
 100                         zend_list_delete(stm->res);
 101         }
 102         return ret;
 103 }
 104 
 105 static HRESULT STDMETHODCALLTYPE stm_read(IStream *This, void *pv, ULONG cb, ULONG *pcbRead)
 106 {
 107         ULONG nread;
 108         FETCH_STM();
 109 
 110         nread = (ULONG)php_stream_read(stm->stream, pv, cb);
 111 
 112         if (pcbRead) {
 113                 *pcbRead = nread > 0 ? nread : 0;
 114         }
 115         if (nread > 0) {
 116                 return S_OK;
 117         }
 118         return S_FALSE;
 119 }
 120 
 121 static HRESULT STDMETHODCALLTYPE stm_write(IStream *This, void const *pv, ULONG cb, ULONG *pcbWritten)
 122 {
 123         ULONG nwrote;
 124         FETCH_STM();
 125 
 126         nwrote = (ULONG)php_stream_write(stm->stream, pv, cb);
 127 
 128         if (pcbWritten) {
 129                 *pcbWritten = nwrote > 0 ? nwrote : 0;
 130         }
 131         if (nwrote > 0) {
 132                 return S_OK;
 133         }
 134         return S_FALSE;
 135 }
 136 
 137 static HRESULT STDMETHODCALLTYPE stm_seek(IStream *This, LARGE_INTEGER dlibMove,
 138                 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
 139 {
 140         off_t offset;
 141         int whence;
 142         int ret;
 143         FETCH_STM();
 144 
 145         switch (dwOrigin) {
 146                 case STREAM_SEEK_SET:   whence = SEEK_SET;      break;
 147                 case STREAM_SEEK_CUR:   whence = SEEK_CUR;      break;
 148                 case STREAM_SEEK_END:   whence = SEEK_END;      break;
 149                 default:
 150                         return STG_E_INVALIDFUNCTION;
 151         }
 152 
 153         if (dlibMove.HighPart) {
 154                 /* we don't support 64-bit offsets */
 155                 return STG_E_INVALIDFUNCTION;
 156         }
 157 
 158         offset = (off_t) dlibMove.QuadPart;
 159 
 160         ret = php_stream_seek(stm->stream, offset, whence);
 161 
 162         if (plibNewPosition) {
 163                 plibNewPosition->QuadPart = (ULONGLONG)(ret >= 0 ? ret : 0);
 164         }
 165 
 166         return ret >= 0 ? S_OK : STG_E_INVALIDFUNCTION;
 167 }
 168 
 169 static HRESULT STDMETHODCALLTYPE stm_set_size(IStream *This, ULARGE_INTEGER libNewSize)
 170 {
 171         FETCH_STM();
 172 
 173         if (libNewSize.HighPart) {
 174                 return STG_E_INVALIDFUNCTION;
 175         }
 176 
 177         if (php_stream_truncate_supported(stm->stream)) {
 178                 int ret = php_stream_truncate_set_size(stm->stream, (size_t)libNewSize.QuadPart);
 179 
 180                 if (ret == 0) {
 181                         return S_OK;
 182                 }
 183         }
 184 
 185         return STG_E_INVALIDFUNCTION;
 186 }
 187 
 188 static HRESULT STDMETHODCALLTYPE stm_copy_to(IStream *This, IStream *pstm, ULARGE_INTEGER cb,
 189                 ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
 190 {
 191         FETCH_STM_EX();
 192 
 193         return E_NOTIMPL;
 194 }
 195 
 196 static HRESULT STDMETHODCALLTYPE stm_commit(IStream *This, DWORD grfCommitFlags)
 197 {
 198         FETCH_STM();
 199 
 200         php_stream_flush(stm->stream);
 201 
 202         return S_OK;
 203 }
 204 
 205 static HRESULT STDMETHODCALLTYPE stm_revert(IStream *This)
 206 {
 207         /* NOP */
 208         return S_OK;
 209 }
 210 
 211 static HRESULT STDMETHODCALLTYPE stm_lock_region(IStream *This,
 212         ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD lockType)
 213 {
 214         return STG_E_INVALIDFUNCTION;
 215 }
 216 
 217 static HRESULT STDMETHODCALLTYPE stm_unlock_region(IStream *This,
 218                 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD lockType)
 219 {
 220         return STG_E_INVALIDFUNCTION;
 221 }
 222 
 223 static HRESULT STDMETHODCALLTYPE stm_stat(IStream *This,
 224                 STATSTG *pstatstg, DWORD grfStatFlag)
 225 {
 226         return STG_E_INVALIDFUNCTION;
 227 }
 228 
 229 static HRESULT STDMETHODCALLTYPE stm_clone(IStream *This, IStream **ppstm)
 230 {
 231         return STG_E_INVALIDFUNCTION;
 232 }
 233 
 234 static struct IStreamVtbl php_istream_vtbl = {
 235         stm_queryinterface,
 236         stm_addref,
 237         stm_release,
 238         stm_read,
 239         stm_write,
 240         stm_seek,
 241         stm_set_size,
 242         stm_copy_to,
 243         stm_commit,
 244         stm_revert,
 245         stm_lock_region,
 246         stm_unlock_region,
 247         stm_stat,
 248         stm_clone
 249 };
 250 
 251 static void istream_destructor(php_istream *stm)
 252 {
 253         if (stm->res) {
 254                 zend_resource *res = stm->res;
 255                 stm->res = NULL;
 256                 zend_list_delete(res);
 257                 return;
 258         }
 259 
 260         if (stm->refcount > 0) {
 261                 CoDisconnectObject((IUnknown*)stm, 0);
 262         }
 263 
 264         zend_list_delete(stm->stream->res);
 265 
 266         CoTaskMemFree(stm);
 267 }
 268 /* }}} */
 269 
 270 PHP_COM_DOTNET_API IStream *php_com_wrapper_export_stream(php_stream *stream)
 271 {
 272         php_istream *stm = (php_istream*)CoTaskMemAlloc(sizeof(*stm));
 273         zval *tmp;
 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         GC_REFCOUNT(stream->res)++;
 285         tmp = zend_list_insert(stm, le_istream);
 286         stm->res = Z_RES_P(tmp);
 287 
 288         return (IStream*)stm;
 289 }
 290 
 291 #define CPH_ME(fname, arginfo)  PHP_ME(com_persist, fname, arginfo, ZEND_ACC_PUBLIC)
 292 #define CPH_SME(fname, arginfo) PHP_ME(com_persist, fname, arginfo, ZEND_ACC_ALLOW_STATIC|ZEND_ACC_PUBLIC)
 293 #define CPH_METHOD(fname)               static PHP_METHOD(com_persist, fname)
 294 
 295 #define CPH_FETCH()                             php_com_persist_helper *helper = (php_com_persist_helper*)Z_OBJ_P(getThis());
 296 
 297 #define CPH_NO_OBJ()                    if (helper->unk == NULL) { php_com_throw_exception(E_INVALIDARG, "No COM object is associated with this helper instance"); return; }
 298 
 299 typedef struct {
 300         zend_object                     std;
 301         long codepage;
 302         IUnknown                        *unk;
 303         IPersistStream          *ips;
 304         IPersistStreamInit      *ipsi;
 305         IPersistFile            *ipf;
 306 } php_com_persist_helper;
 307 
 308 static zend_object_handlers helper_handlers;
 309 static zend_class_entry *helper_ce;
 310 
 311 static inline HRESULT get_persist_stream(php_com_persist_helper *helper)
 312 {
 313         if (!helper->ips && helper->unk) {
 314                 return IUnknown_QueryInterface(helper->unk, &IID_IPersistStream, &helper->ips);
 315         }
 316         return helper->ips ? S_OK : E_NOTIMPL;
 317 }
 318 
 319 static inline HRESULT get_persist_stream_init(php_com_persist_helper *helper)
 320 {
 321         if (!helper->ipsi && helper->unk) {
 322                 return IUnknown_QueryInterface(helper->unk, &IID_IPersistStreamInit, &helper->ipsi);
 323         }
 324         return helper->ipsi ? S_OK : E_NOTIMPL;
 325 }
 326 
 327 static inline HRESULT get_persist_file(php_com_persist_helper *helper)
 328 {
 329         if (!helper->ipf && helper->unk) {
 330                 return IUnknown_QueryInterface(helper->unk, &IID_IPersistFile, &helper->ipf);
 331         }
 332         return helper->ipf ? S_OK : E_NOTIMPL;
 333 }
 334 
 335 
 336 /* {{{ proto string COMPersistHelper::GetCurFile()
 337    Determines the filename into which an object will be saved, or false if none is set, via IPersistFile::GetCurFile */
 338 CPH_METHOD(GetCurFileName)
 339 {
 340         HRESULT res;
 341         OLECHAR *olename = NULL;
 342         CPH_FETCH();
 343 
 344         CPH_NO_OBJ();
 345 
 346         res = get_persist_file(helper);
 347         if (helper->ipf) {
 348                 res = IPersistFile_GetCurFile(helper->ipf, &olename);
 349 
 350                 if (res == S_OK) {
 351                         size_t len;
 352                         char *str = php_com_olestring_to_string(olename,
 353                                    &len, helper->codepage);
 354                         RETVAL_STRINGL(str, len);
 355                         // TODO: avoid reallocarion???
 356                         efree(str);
 357                         CoTaskMemFree(olename);
 358                         return;
 359                 } else if (res == S_FALSE) {
 360                         CoTaskMemFree(olename);
 361                         RETURN_FALSE;
 362                 }
 363                 php_com_throw_exception(res, NULL);
 364         } else {
 365                 php_com_throw_exception(res, NULL);
 366         }
 367 }
 368 /* }}} */
 369 
 370 
 371 /* {{{ proto bool COMPersistHelper::SaveToFile(string filename [, bool remember])
 372    Persist object data to file, via IPersistFile::Save */
 373 CPH_METHOD(SaveToFile)
 374 {
 375         HRESULT res;
 376         char *filename, *fullpath = NULL;
 377         size_t filename_len;
 378         zend_bool remember = TRUE;
 379         OLECHAR *olefilename = NULL;
 380         CPH_FETCH();
 381 
 382         CPH_NO_OBJ();
 383 
 384         res = get_persist_file(helper);
 385         if (helper->ipf) {
 386                 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "p!|b",
 387                                         &filename, &filename_len, &remember)) {
 388                         php_com_throw_exception(E_INVALIDARG, "Invalid arguments");
 389                         return;
 390                 }
 391 
 392                 if (filename) {
 393                         fullpath = expand_filepath(filename, NULL);
 394                         if (!fullpath) {
 395                                 RETURN_FALSE;
 396                         }
 397 
 398                         if (php_check_open_basedir(fullpath)) {
 399                                 efree(fullpath);
 400                                 RETURN_FALSE;
 401                         }
 402 
 403                         olefilename = php_com_string_to_olestring(filename, strlen(fullpath), helper->codepage);
 404                         efree(fullpath);
 405                 }
 406                 res = IPersistFile_Save(helper->ipf, olefilename, remember);
 407                 if (SUCCEEDED(res)) {
 408                         if (!olefilename) {
 409                                 res = IPersistFile_GetCurFile(helper->ipf, &olefilename);
 410                                 if (S_OK == res) {
 411                                         IPersistFile_SaveCompleted(helper->ipf, olefilename);
 412                                         CoTaskMemFree(olefilename);
 413                                         olefilename = NULL;
 414                                 }
 415                         } else if (remember) {
 416                                 IPersistFile_SaveCompleted(helper->ipf, olefilename);
 417                         }
 418                 }
 419 
 420                 if (olefilename) {
 421                         efree(olefilename);
 422                 }
 423 
 424                 if (FAILED(res)) {
 425                         php_com_throw_exception(res, NULL);
 426                 }
 427 
 428         } else {
 429                 php_com_throw_exception(res, NULL);
 430         }
 431 }
 432 /* }}} */
 433 
 434 /* {{{ proto bool COMPersistHelper::LoadFromFile(string filename [, int flags])
 435    Load object data from file, via IPersistFile::Load */
 436 CPH_METHOD(LoadFromFile)
 437 {
 438         HRESULT res;
 439         char *filename, *fullpath;
 440         size_t filename_len;
 441         zend_long flags = 0;
 442         OLECHAR *olefilename;
 443         CPH_FETCH();
 444 
 445         CPH_NO_OBJ();
 446 
 447         res = get_persist_file(helper);
 448         if (helper->ipf) {
 449 
 450                 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "p|l",
 451                                         &filename, &filename_len, &flags)) {
 452                         php_com_throw_exception(E_INVALIDARG, "Invalid arguments");
 453                         return;
 454                 }
 455 
 456                 if (!(fullpath = expand_filepath(filename, NULL))) {
 457                         RETURN_FALSE;
 458                 }
 459 
 460                 if (php_check_open_basedir(fullpath)) {
 461                         efree(fullpath);
 462                         RETURN_FALSE;
 463                 }
 464 
 465                 olefilename = php_com_string_to_olestring(fullpath, strlen(fullpath), helper->codepage);
 466                 efree(fullpath);
 467 
 468                 res = IPersistFile_Load(helper->ipf, olefilename, (DWORD)flags);
 469                 efree(olefilename);
 470 
 471                 if (FAILED(res)) {
 472                         php_com_throw_exception(res, NULL);
 473                 }
 474 
 475         } else {
 476                 php_com_throw_exception(res, NULL);
 477         }
 478 }
 479 /* }}} */
 480 
 481 /* {{{ proto int COMPersistHelper::GetMaxStreamSize()
 482    Gets maximum stream size required to store the object data, via IPersistStream::GetSizeMax (or IPersistStreamInit::GetSizeMax) */
 483 CPH_METHOD(GetMaxStreamSize)
 484 {
 485         HRESULT res;
 486         ULARGE_INTEGER size;
 487         CPH_FETCH();
 488 
 489         CPH_NO_OBJ();
 490 
 491         res = get_persist_stream_init(helper);
 492         if (helper->ipsi) {
 493                 res = IPersistStreamInit_GetSizeMax(helper->ipsi, &size);
 494         } else {
 495                 res = get_persist_stream(helper);
 496                 if (helper->ips) {
 497                         res = IPersistStream_GetSizeMax(helper->ips, &size);
 498                 } else {
 499                         php_com_throw_exception(res, NULL);
 500                         return;
 501                 }
 502         }
 503 
 504         if (res != S_OK) {
 505                 php_com_throw_exception(res, NULL);
 506         } else {
 507                 /* TODO: handle 64 bit properly */
 508                 RETURN_LONG((zend_long)size.QuadPart);
 509         }
 510 }
 511 /* }}} */
 512 
 513 /* {{{ proto int COMPersistHelper::InitNew()
 514    Initializes the object to a default state, via IPersistStreamInit::InitNew */
 515 CPH_METHOD(InitNew)
 516 {
 517         HRESULT res;
 518         CPH_FETCH();
 519 
 520         CPH_NO_OBJ();
 521 
 522         res = get_persist_stream_init(helper);
 523         if (helper->ipsi) {
 524                 res = IPersistStreamInit_InitNew(helper->ipsi);
 525 
 526                 if (res != S_OK) {
 527                         php_com_throw_exception(res, NULL);
 528                 } else {
 529                         RETURN_TRUE;
 530                 }
 531         } else {
 532                 php_com_throw_exception(res, NULL);
 533         }
 534 }
 535 /* }}} */
 536 
 537 /* {{{ proto mixed COMPersistHelper::LoadFromStream(resource stream)
 538    Initializes an object from the stream where it was previously saved, via IPersistStream::Load or OleLoadFromStream */
 539 CPH_METHOD(LoadFromStream)
 540 {
 541         zval *zstm;
 542         php_stream *stream;
 543         IStream *stm = NULL;
 544         HRESULT res;
 545         CPH_FETCH();
 546 
 547         if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zstm)) {
 548                 php_com_throw_exception(E_INVALIDARG, "invalid arguments");
 549                 return;
 550         }
 551 
 552         php_stream_from_zval_no_verify(stream, zstm);
 553 
 554         if (stream == NULL) {
 555                 php_com_throw_exception(E_INVALIDARG, "expected a stream");
 556                 return;
 557         }
 558 
 559         stm = php_com_wrapper_export_stream(stream);
 560         if (stm == NULL) {
 561                 php_com_throw_exception(E_UNEXPECTED, "failed to wrap stream");
 562                 return;
 563         }
 564 
 565         res = S_OK;
 566         RETVAL_TRUE;
 567 
 568         if (helper->unk == NULL) {
 569                 IDispatch *disp = NULL;
 570 
 571                 /* we need to create an object and load using OleLoadFromStream */
 572                 res = OleLoadFromStream(stm, &IID_IDispatch, &disp);
 573 
 574                 if (SUCCEEDED(res)) {
 575                         php_com_wrap_dispatch(return_value, disp, COMG(code_page));
 576                 }
 577         } else {
 578                 res = get_persist_stream_init(helper);
 579                 if (helper->ipsi) {
 580                         res = IPersistStreamInit_Load(helper->ipsi, stm);
 581                 } else {
 582                         res = get_persist_stream(helper);
 583                         if (helper->ips) {
 584                                 res = IPersistStreamInit_Load(helper->ipsi, stm);
 585                         }
 586                 }
 587         }
 588         IStream_Release(stm);
 589 
 590         if (FAILED(res)) {
 591                 php_com_throw_exception(res, NULL);
 592                 RETURN_NULL();
 593         }
 594 }
 595 /* }}} */
 596 
 597 /* {{{ proto int COMPersistHelper::SaveToStream(resource stream)
 598    Saves the object to a stream, via IPersistStream::Save */
 599 CPH_METHOD(SaveToStream)
 600 {
 601         zval *zstm;
 602         php_stream *stream;
 603         IStream *stm = NULL;
 604         HRESULT res;
 605         CPH_FETCH();
 606 
 607         CPH_NO_OBJ();
 608 
 609         if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zstm)) {
 610                 php_com_throw_exception(E_INVALIDARG, "invalid arguments");
 611                 return;
 612         }
 613 
 614         php_stream_from_zval_no_verify(stream, zstm);
 615 
 616         if (stream == NULL) {
 617                 php_com_throw_exception(E_INVALIDARG, "expected a stream");
 618                 return;
 619         }
 620 
 621         stm = php_com_wrapper_export_stream(stream);
 622         if (stm == NULL) {
 623                 php_com_throw_exception(E_UNEXPECTED, "failed to wrap stream");
 624                 return;
 625         }
 626 
 627         res = get_persist_stream_init(helper);
 628         if (helper->ipsi) {
 629                 res = IPersistStreamInit_Save(helper->ipsi, stm, TRUE);
 630         } else {
 631                 res = get_persist_stream(helper);
 632                 if (helper->ips) {
 633                         res = IPersistStream_Save(helper->ips, stm, TRUE);
 634                 }
 635         }
 636 
 637         IStream_Release(stm);
 638 
 639         if (FAILED(res)) {
 640                 php_com_throw_exception(res, NULL);
 641                 return;
 642         }
 643 
 644         RETURN_TRUE;
 645 }
 646 /* }}} */
 647 
 648 /* {{{ proto int COMPersistHelper::__construct([object com_object])
 649    Creates a persistence helper object, usually associated with a com_object */
 650 CPH_METHOD(__construct)
 651 {
 652         php_com_dotnet_object *obj = NULL;
 653         zval *zobj = NULL;
 654         CPH_FETCH();
 655 
 656         if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|O!",
 657                                 &zobj, php_com_variant_class_entry)) {
 658                 php_com_throw_exception(E_INVALIDARG, "invalid arguments");
 659                 return;
 660         }
 661 
 662         if (!zobj) {
 663                 return;
 664         }
 665 
 666         obj = CDNO_FETCH(zobj);
 667 
 668         if (V_VT(&obj->v) != VT_DISPATCH || V_DISPATCH(&obj->v) == NULL) {
 669                 php_com_throw_exception(E_INVALIDARG, "parameter must represent an IDispatch COM object");
 670                 return;
 671         }
 672 
 673         /* it is always safe to cast an interface to IUnknown */
 674         helper->unk = (IUnknown*)V_DISPATCH(&obj->v);
 675         IUnknown_AddRef(helper->unk);
 676         helper->codepage = obj->code_page;
 677 }
 678 /* }}} */
 679 
 680 
 681 
 682 
 683 static const zend_function_entry com_persist_helper_methods[] = {
 684         CPH_ME(__construct, NULL)
 685         CPH_ME(GetCurFileName, NULL)
 686         CPH_ME(SaveToFile, NULL)
 687         CPH_ME(LoadFromFile, NULL)
 688         CPH_ME(GetMaxStreamSize, NULL)
 689         CPH_ME(InitNew, NULL)
 690         CPH_ME(LoadFromStream, NULL)
 691         CPH_ME(SaveToStream, NULL)
 692         PHP_FE_END
 693 };
 694 
 695 static void helper_free_storage(zend_object *obj)
 696 {
 697         php_com_persist_helper *object = (php_com_persist_helper*)obj;
 698 
 699         if (object->ipf) {
 700                 IPersistFile_Release(object->ipf);
 701         }
 702         if (object->ips) {
 703                 IPersistStream_Release(object->ips);
 704         }
 705         if (object->ipsi) {
 706                 IPersistStreamInit_Release(object->ipsi);
 707         }
 708         if (object->unk) {
 709                 IUnknown_Release(object->unk);
 710         }
 711         zend_object_std_dtor(&object->std);
 712 }
 713 
 714 
 715 static zend_object* helper_clone(zval *obj)
 716 {
 717         php_com_persist_helper *clone, *object = (php_com_persist_helper*)Z_OBJ_P(obj);
 718 
 719         clone = emalloc(sizeof(*object));
 720         memcpy(clone, object, sizeof(*object));
 721 
 722         zend_object_std_init(&clone->std, object->std.ce);
 723 
 724         if (clone->ipf) {
 725                 IPersistFile_AddRef(clone->ipf);
 726         }
 727         if (clone->ips) {
 728                 IPersistStream_AddRef(clone->ips);
 729         }
 730         if (clone->ipsi) {
 731                 IPersistStreamInit_AddRef(clone->ipsi);
 732         }
 733         if (clone->unk) {
 734                 IUnknown_AddRef(clone->unk);
 735         }
 736         return (zend_object*)clone;
 737 }
 738 
 739 static zend_object* helper_new(zend_class_entry *ce)
 740 {
 741         php_com_persist_helper *helper;
 742 
 743         helper = emalloc(sizeof(*helper));
 744         memset(helper, 0, sizeof(*helper));
 745 
 746         zend_object_std_init(&helper->std, helper_ce);
 747         helper->std.handlers = &helper_handlers;
 748 
 749         return &helper->std;
 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.free_obj = helper_free_storage;
 758         helper_handlers.clone_obj = helper_clone;
 759 
 760         INIT_CLASS_ENTRY(ce, "COMPersistHelper", com_persist_helper_methods);
 761         ce.create_object = helper_new;
 762         helper_ce = zend_register_internal_class(&ce);
 763         helper_ce->ce_flags |= ZEND_ACC_FINAL;
 764 
 765         le_istream = zend_register_list_destructors_ex(istream_dtor,
 766                         NULL, "com_dotnet_istream_wrapper", module_number);
 767 
 768         return SUCCESS;
 769 }
 770 
 771 /*
 772  * Local variables:
 773  * tab-width: 4
 774  * c-basic-offset: 4
 775  * End:
 776  * vim600: noet sw=4 ts=4 fdm=marker
 777  * vim<600: noet sw=4 ts=4
 778  */

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