Annotation of embedaddon/php/ext/com_dotnet/com_persist.c, revision 1.1.1.2

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | PHP Version 5                                                        |
                      4:    +----------------------------------------------------------------------+
                      5:    | Copyright (c) 1997-2012 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: 
1.1.1.2 ! misho      19: /* $Id$ */
1.1       misho      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;
1.1.1.2 ! misho      48: static void istream_destructor(php_istream *stm TSRMLS_DC);
1.1       misho      49: 
                     50: static void istream_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
                     51: {
                     52:        php_istream *stm = (php_istream *)rsrc->ptr;
1.1.1.2 ! misho      53:        istream_destructor(stm TSRMLS_CC);
1.1       misho      54: }
                     55: 
                     56: #define FETCH_STM()    \
                     57:        php_istream *stm = (php_istream*)This; \
1.1.1.2 ! misho      58:        TSRMLS_FETCH(); \
1.1       misho      59:        if (GetCurrentThreadId() != stm->engine_thread) \
                     60:                return RPC_E_WRONG_THREAD;
1.1.1.2 ! misho      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;
1.1       misho      66: 
                     67: static HRESULT STDMETHODCALLTYPE stm_queryinterface(
                     68:        IStream *This,
                     69:        /* [in] */ REFIID riid,
                     70:        /* [iid_is][out] */ void **ppvObject)
                     71: {
1.1.1.2 ! misho      72:        FETCH_STM_EX();
1.1       misho      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: {
1.1.1.2 ! misho      87:        FETCH_STM_EX();
1.1       misho      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: {
1.1.1.2 ! misho     192:        FETCH_STM_EX();
1.1       misho     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: 
1.1.1.2 ! misho     252: static void istream_destructor(php_istream *stm TSRMLS_DC)
1.1       misho     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: PHPAPI 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);
1.1.1.2 ! misho     285:        stm->id = zend_list_insert(stm, le_istream TSRMLS_CC);
1.1       misho     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) {
1.1.1.2 ! misho     382:                if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p!|b",
1.1       misho     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:        
1.1.1.2 ! misho     394:                        if (php_check_open_basedir(fullpath TSRMLS_CC)) {
1.1       misho     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: 
1.1.1.2 ! misho     446:                if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p|l",
1.1       misho     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: 
1.1.1.2 ! misho     456:                if (php_check_open_basedir(fullpath TSRMLS_CC)) {
1.1       misho     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:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>