| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| #if defined(_MSC_VER) && (_MSC_VER > 1310) |
| #pragma warning(disable : 4917 4555) |
| #endif |
| |
| #include "embeddoc.hxx" |
| #include <com/sun/star/uno/Any.h> |
| #include <com/sun/star/uno/Exception.hpp> |
| #include <com/sun/star/lang/XMultiServiceFactory.hpp> |
| #include <com/sun/star/lang/XComponent.hpp> |
| #include <com/sun/star/io/XInputStream.hpp> |
| #include <com/sun/star/io/XOutputStream.hpp> |
| #include <com/sun/star/io/XSeekable.hpp> |
| #include <com/sun/star/frame/XModel.hpp> |
| #include <com/sun/star/frame/XLoadable.hpp> |
| #include <com/sun/star/util/XModifiable.hpp> |
| #include <com/sun/star/frame/XStorable.hpp> |
| #include <com/sun/star/frame/XComponentLoader.hpp> |
| #include <com/sun/star/util/XUrlTransformer.hpp> |
| |
| |
| #include <osl/mutex.hxx> |
| #include <osl/diagnose.h> |
| |
| #include <string.h> |
| |
| #define EXT_STREAM_LENGTH 16 |
| |
| using namespace ::com::sun::star; |
| |
| extern ::rtl::OUString getStorageTypeFromGUID_Impl( GUID* guid ); |
| extern ::rtl::OUString getServiceNameFromGUID_Impl( GUID* ); |
| extern ::rtl::OUString getFilterNameFromGUID_Impl( GUID* ); |
| // extern CLIPFORMAT getClipFormatFromGUID_Impl( GUID* ); |
| ::rtl::OUString getTestFileURLFromGUID_Impl( GUID* guid ); |
| |
| const ::rtl::OUString aOfficeEmbedStreamName( RTL_CONSTASCII_USTRINGPARAM ( "package_stream" ) ); |
| const ::rtl::OUString aExtentStreamName( RTL_CONSTASCII_USTRINGPARAM ( "properties_stream" ) ); |
| |
| uno::Reference< io::XInputStream > createTempXInStreamFromIStream( |
| uno::Reference< lang::XMultiServiceFactory > xFactory, |
| IStream *pStream ) |
| { |
| uno::Reference< io::XInputStream > xResult; |
| |
| if ( !pStream ) |
| return xResult; |
| |
| const ::rtl::OUString aServiceName ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.io.TempFile" ) ); |
| uno::Reference < io::XOutputStream > xTempOut = uno::Reference < io::XOutputStream > ( |
| xFactory->createInstance ( aServiceName ), |
| uno::UNO_QUERY ); |
| if ( xTempOut.is() ) |
| { |
| ULARGE_INTEGER nNewPos; |
| LARGE_INTEGER aZero = { 0L, 0L }; |
| HRESULT hr = pStream->Seek( aZero, STREAM_SEEK_SET, &nNewPos ); |
| if ( FAILED( hr ) ) return xResult; |
| |
| STATSTG aStat; |
| hr = pStream->Stat( &aStat, STATFLAG_NONAME ); |
| if ( FAILED( hr ) ) return xResult; |
| |
| sal_uInt32 nSize = (sal_uInt32)aStat.cbSize.QuadPart; |
| sal_uInt32 nCopied = 0; |
| uno::Sequence< sal_Int8 > aBuffer( nConstBufferSize ); |
| try |
| { |
| sal_uInt32 nRead = 0; |
| do |
| { |
| pStream->Read( (void*)aBuffer.getArray(), nConstBufferSize, &nRead ); |
| |
| if ( nRead < nConstBufferSize ) |
| aBuffer.realloc( nRead ); |
| |
| xTempOut->writeBytes( aBuffer ); |
| nCopied += nRead; |
| } while( nRead == nConstBufferSize ); |
| |
| if ( nCopied == nSize ) |
| { |
| uno::Reference < io::XSeekable > xTempSeek ( xTempOut, uno::UNO_QUERY ); |
| if ( xTempSeek.is() ) |
| { |
| xTempSeek->seek ( 0 ); |
| xResult = uno::Reference< io::XInputStream >( xTempOut, uno::UNO_QUERY ); |
| } |
| } |
| } |
| catch( uno::Exception& ) |
| { |
| } |
| } |
| |
| return xResult; |
| } |
| |
| HRESULT copyXTempOutToIStream( uno::Reference< io::XOutputStream > xTempOut, IStream* pStream ) |
| { |
| if ( !xTempOut.is() || !pStream ) |
| return E_FAIL; |
| |
| uno::Reference < io::XSeekable > xTempSeek ( xTempOut, uno::UNO_QUERY ); |
| if ( !xTempSeek.is() ) |
| return E_FAIL; |
| |
| xTempSeek->seek ( 0 ); |
| |
| uno::Reference< io::XInputStream > xTempIn ( xTempOut, uno::UNO_QUERY ); |
| if ( !xTempSeek.is() ) |
| return E_FAIL; |
| |
| // Seek to zero and truncate the stream |
| ULARGE_INTEGER nNewPos; |
| LARGE_INTEGER aZero = { 0L, 0L }; |
| HRESULT hr = pStream->Seek( aZero, STREAM_SEEK_SET, &nNewPos ); |
| if ( FAILED( hr ) ) return E_FAIL; |
| ULARGE_INTEGER aUZero = { 0L, 0L }; |
| hr = pStream->SetSize( aUZero ); |
| if ( FAILED( hr ) ) return E_FAIL; |
| |
| uno::Sequence< sal_Int8 > aBuffer( nConstBufferSize ); |
| sal_uInt32 nReadBytes = 0; |
| |
| do |
| { |
| try { |
| nReadBytes = xTempIn->readBytes( aBuffer, nConstBufferSize ); |
| } |
| catch( uno::Exception& ) |
| { |
| return E_FAIL; |
| } |
| |
| sal_uInt32 nWritten = 0; |
| HRESULT hr = pStream->Write( (void*)aBuffer.getArray(), nReadBytes, &nWritten ); |
| if ( !SUCCEEDED( hr ) || nWritten != nReadBytes ) |
| return E_FAIL; |
| |
| } while( nReadBytes == nConstBufferSize ); |
| |
| return S_OK; |
| } |
| |
| |
| //=============================================================================== |
| // EmbedDocument_Impl |
| //=============================================================================== |
| |
| EmbedDocument_Impl::EmbedDocument_Impl( const uno::Reference< lang::XMultiServiceFactory >& xFactory, const GUID* guid ) |
| : m_refCount( 0L ) |
| , m_xFactory( xFactory ) |
| , m_guid( *guid ) |
| , m_bIsDirty( sal_False ) |
| , m_nAdviseNum( 0 ) |
| , m_bIsInVerbHandling( sal_False ) |
| //, m_bLoadedFromFile( sal_False ) |
| { |
| m_xOwnAccess = new EmbeddedDocumentInstanceAccess_Impl( this ); |
| m_pDocHolder = new DocumentHolder( xFactory, m_xOwnAccess ); |
| m_pDocHolder->acquire(); |
| } |
| |
| EmbedDocument_Impl::~EmbedDocument_Impl() |
| { |
| m_pDocHolder->FreeOffice(); |
| |
| if ( m_pDocHolder->HasFrame() && m_pDocHolder->IsLink() ) |
| { |
| // a link with frame should be only disconnected, not closed |
| m_pDocHolder->DisconnectFrameDocument( sal_True ); |
| } |
| else |
| { |
| m_pDocHolder->CloseDocument(); |
| m_pDocHolder->CloseFrame(); |
| } |
| |
| m_pDocHolder->release(); |
| } |
| |
| uno::Sequence< beans::PropertyValue > EmbedDocument_Impl::fillArgsForLoading_Impl( uno::Reference< io::XInputStream > xStream, DWORD /*nStreamMode*/, LPCOLESTR pFilePath ) |
| { |
| uno::Sequence< beans::PropertyValue > aArgs( 3 ); |
| |
| sal_Int32 nInd = 0; // must not be bigger than the preset size |
| aArgs[nInd].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "FilterName" ) ); |
| aArgs[nInd++].Value <<= getFilterNameFromGUID_Impl( &m_guid ); |
| |
| if ( xStream.is() ) |
| { |
| aArgs[nInd].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "InputStream" ) ); |
| aArgs[nInd++].Value <<= xStream; |
| aArgs[nInd].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "URL" ) ); |
| aArgs[nInd++].Value <<= ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "private:stream" ) ); |
| } |
| else |
| { |
| aArgs[nInd].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "URL" ) ); |
| |
| rtl::OUString sDocUrl; |
| if ( pFilePath ) |
| { |
| ::rtl::OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.util.URLTransformer" ) ); |
| uno::Reference< util::XURLTransformer > aTransformer( m_xFactory->createInstance( aServiceName ), |
| uno::UNO_QUERY ); |
| if ( aTransformer.is() ) |
| { |
| util::URL aURL; |
| |
| aURL.Complete = ::rtl::OUString( reinterpret_cast<const sal_Unicode*>(pFilePath) ); |
| |
| if ( aTransformer->parseSmart( aURL, ::rtl::OUString() ) ) |
| sDocUrl = aURL.Complete; |
| } |
| } |
| |
| aArgs[nInd++].Value <<= sDocUrl; |
| } |
| |
| aArgs.realloc( nInd ); |
| |
| // aArgs[].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "ReadOnly" ) ); |
| // aArgs[].Value <<= sal_False; //( ( nStreamMode & ( STGM_READWRITE | STGM_WRITE ) ) ? sal_True : sal_False ); |
| |
| return aArgs; |
| } |
| |
| uno::Sequence< beans::PropertyValue > EmbedDocument_Impl::fillArgsForStoring_Impl( uno::Reference< io::XOutputStream > xStream) |
| { |
| uno::Sequence< beans::PropertyValue > aArgs( xStream.is() ? 2 : 1 ); |
| |
| aArgs[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "FilterName" ) ); |
| aArgs[0].Value <<= getFilterNameFromGUID_Impl( &m_guid ); |
| |
| if ( xStream.is() ) |
| { |
| aArgs[1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "OutputStream" ) ); |
| aArgs[1].Value <<= xStream; |
| } |
| |
| return aArgs; |
| } |
| |
| HRESULT EmbedDocument_Impl::SaveTo_Impl( IStorage* pStg ) |
| { |
| if ( !pStg || pStg == m_pMasterStorage ) |
| return E_FAIL; |
| |
| // for saveto operation the master storage |
| // should not enter NoScribble mode |
| CComPtr< IStream > pOrigOwn = m_pOwnStream; |
| CComPtr< IStream > pOrigExt = m_pExtStream; |
| HRESULT hr = Save( pStg, sal_False ); |
| pStg->Commit( STGC_ONLYIFCURRENT ); |
| m_pOwnStream = pOrigOwn; |
| m_pExtStream = pOrigExt; |
| |
| return hr; |
| } |
| |
| //------------------------------------------------------------------------------- |
| // IUnknown |
| |
| STDMETHODIMP EmbedDocument_Impl::QueryInterface( REFIID riid, void FAR* FAR* ppv ) |
| { |
| if(IsEqualIID(riid, IID_IUnknown)) |
| { |
| AddRef(); |
| *ppv = (IUnknown*) (IPersistStorage*) this; |
| return S_OK; |
| } |
| else if (IsEqualIID(riid, IID_IPersist)) |
| { |
| AddRef(); |
| *ppv = (IPersist*) (IPersistStorage*) this; |
| return S_OK; |
| } |
| else if (IsEqualIID(riid, IID_IExternalConnection)) |
| { |
| AddRef(); |
| *ppv = (IExternalConnection*) this; |
| return S_OK; |
| } |
| else if (IsEqualIID(riid, IID_IPersistStorage)) |
| { |
| AddRef(); |
| *ppv = (IPersistStorage*) this; |
| return S_OK; |
| } |
| else if (IsEqualIID(riid, IID_IDataObject)) |
| { |
| AddRef(); |
| *ppv = (IDataObject*) this; |
| return S_OK; |
| } |
| else if (IsEqualIID(riid, IID_IOleObject)) |
| { |
| AddRef(); |
| *ppv = (IOleObject*) this; |
| return S_OK; |
| } |
| else if (IsEqualIID(riid, IID_IOleWindow)) |
| { |
| AddRef(); |
| *ppv = (IOleWindow*) this; |
| return S_OK; |
| } |
| else if (IsEqualIID(riid, IID_IOleInPlaceObject)) |
| { |
| AddRef(); |
| *ppv = (IOleInPlaceObject*) this; |
| return S_OK; |
| } |
| else if (IsEqualIID(riid, IID_IPersistFile)) |
| { |
| AddRef(); |
| *ppv = (IPersistFile*) this; |
| return S_OK; |
| } |
| else if (IsEqualIID(riid, IID_IDispatch)) |
| { |
| AddRef(); |
| *ppv = (IDispatch*) this; |
| return S_OK; |
| } |
| |
| *ppv = NULL; |
| return ResultFromScode(E_NOINTERFACE); |
| } |
| |
| STDMETHODIMP_(ULONG) EmbedDocument_Impl::AddRef() |
| { |
| return osl_incrementInterlockedCount( &m_refCount); |
| } |
| |
| STDMETHODIMP_(ULONG) EmbedDocument_Impl::Release() |
| { |
| // if there is a time when the last reference is destructed, that means that only internal pointers are alive |
| // after the following call either the refcount is increased or the pointers are empty |
| if ( m_refCount == 1 ) |
| m_xOwnAccess->ClearEmbedDocument(); |
| |
| sal_Int32 nCount = osl_decrementInterlockedCount( &m_refCount ); |
| if ( nCount == 0 ) |
| delete this; |
| return nCount; |
| } |
| |
| //------------------------------------------------------------------------------- |
| // IPersist |
| |
| STDMETHODIMP EmbedDocument_Impl::GetClassID( CLSID* pClassId ) |
| { |
| *pClassId = *&m_guid; |
| return S_OK; |
| } |
| |
| //------------------------------------------------------------------------------- |
| // IPersistStorage |
| |
| STDMETHODIMP EmbedDocument_Impl::IsDirty() |
| { |
| // the link modified state is controlled by the document |
| if ( m_bIsDirty && !m_aFileName.getLength() ) |
| return S_OK; |
| |
| uno::Reference< util::XModifiable > xMod( m_pDocHolder->GetDocument(), uno::UNO_QUERY ); |
| if ( xMod.is() ) |
| return xMod->isModified() ? S_OK : S_FALSE; |
| return S_FALSE; |
| } |
| |
| STDMETHODIMP EmbedDocument_Impl::InitNew( IStorage *pStg ) |
| { |
| HRESULT hr = CO_E_ALREADYINITIALIZED; |
| |
| if ( !m_pDocHolder->GetDocument().is() ) |
| { |
| |
| STATSTG aStat; |
| hr = pStg->Stat( &aStat, STATFLAG_NONAME ); |
| if ( FAILED( hr ) ) return E_FAIL; |
| |
| DWORD nStreamMode = aStat.grfMode; |
| |
| hr = E_FAIL; |
| if ( m_xFactory.is() && pStg ) |
| { |
| uno::Reference< frame::XModel > aDocument( |
| m_xFactory->createInstance( getServiceNameFromGUID_Impl( &m_guid ) ), |
| uno::UNO_QUERY ); |
| if ( aDocument.is() ) |
| { |
| m_pDocHolder->SetDocument( aDocument ); |
| |
| uno::Reference< frame::XLoadable > xLoadable( m_pDocHolder->GetDocument(), uno::UNO_QUERY ); |
| if( xLoadable.is() ) |
| { |
| try |
| { |
| xLoadable->initNew(); |
| // xLoadable->load( fillArgsForLoading_Impl( uno::Reference< io::XInputStream >(), nStreamMode ) ); |
| hr = S_OK; |
| } |
| catch( uno::Exception& ) |
| { |
| } |
| } |
| |
| if ( hr == S_OK ) |
| { |
| ::rtl::OUString aCurType = getStorageTypeFromGUID_Impl( &m_guid ); // ??? |
| CLIPFORMAT cf = (CLIPFORMAT)RegisterClipboardFormatA( "Embedded Object" ); |
| hr = WriteFmtUserTypeStg( pStg, |
| cf, // ??? |
| reinterpret_cast<LPWSTR>(( sal_Unicode* )aCurType.getStr()) ); |
| |
| if ( hr == S_OK ) |
| { |
| hr = pStg->CreateStream( reinterpret_cast<LPCWSTR>(aOfficeEmbedStreamName.getStr()), |
| STGM_CREATE | ( nStreamMode & 0x73 ), |
| 0, |
| 0, |
| &m_pOwnStream ); |
| |
| if ( hr == S_OK && m_pOwnStream ) |
| { |
| hr = pStg->CreateStream( reinterpret_cast<LPCWSTR>(aExtentStreamName.getStr()), |
| STGM_CREATE | ( nStreamMode & 0x73 ), |
| 0, |
| 0, |
| &m_pExtStream ); |
| |
| if ( hr == S_OK && m_pExtStream ) |
| { |
| |
| m_pMasterStorage = pStg; |
| m_bIsDirty = sal_True; |
| } |
| else |
| hr = E_FAIL; |
| } |
| else |
| hr = E_FAIL; |
| } |
| else |
| hr = E_FAIL; |
| } |
| |
| if ( hr != S_OK ) |
| m_pDocHolder->CloseDocument(); |
| } |
| } |
| } |
| |
| return hr; |
| } |
| |
| STDMETHODIMP EmbedDocument_Impl::Load( IStorage *pStg ) |
| { |
| if ( m_pDocHolder->GetDocument().is() ) |
| return CO_E_ALREADYINITIALIZED; |
| |
| if ( !m_xFactory.is() || !pStg ) |
| return E_FAIL; |
| |
| HRESULT hr = E_FAIL; |
| |
| STATSTG aStat; |
| hr = pStg->Stat( &aStat, STATFLAG_NONAME ); |
| if ( FAILED( hr ) ) return E_FAIL; |
| |
| DWORD nStreamMode = aStat.grfMode; |
| hr = pStg->OpenStream( reinterpret_cast<LPCWSTR>(aOfficeEmbedStreamName.getStr()), |
| 0, |
| nStreamMode & 0x73, |
| 0, |
| &m_pOwnStream ); |
| if ( !m_pOwnStream ) hr = E_FAIL; |
| |
| if ( SUCCEEDED( hr ) ) |
| { |
| hr = pStg->OpenStream( reinterpret_cast<LPCWSTR>(aExtentStreamName.getStr()), |
| 0, |
| nStreamMode & 0x73, |
| 0, |
| &m_pExtStream ); |
| if ( !m_pExtStream ) hr = E_FAIL; |
| } |
| |
| // RECTL aRectToSet; |
| SIZEL aSizeToSet; |
| if ( SUCCEEDED( hr ) ) |
| { |
| ULARGE_INTEGER nNewPos; |
| LARGE_INTEGER aZero = { 0L, 0L }; |
| hr = m_pExtStream->Seek( aZero, STREAM_SEEK_SET, &nNewPos ); |
| if ( SUCCEEDED( hr ) ) |
| { |
| sal_uInt32 nRead; |
| sal_Int8 aInf[EXT_STREAM_LENGTH]; |
| hr = m_pExtStream->Read( (void*)aInf, EXT_STREAM_LENGTH, &nRead ); |
| if ( nRead != EXT_STREAM_LENGTH ) hr = E_FAIL; |
| |
| if ( SUCCEEDED( hr ) ) |
| { |
| // aRectToSet.left = *((sal_Int32*)aInf); |
| // aRectToSet.top = *((sal_Int32*)&aInf[4]); |
| // aRectToSet.right = *((sal_Int32*)&aInf[8]); |
| // aRectToSet.bottom = *((sal_Int32*)&aInf[12]); |
| aSizeToSet.cx = *((sal_Int32*)&aInf[8]) - *((sal_Int32*)aInf); |
| aSizeToSet.cy = *((sal_Int32*)&aInf[12]) - *((sal_Int32*)&aInf[4]); |
| } |
| } |
| } |
| |
| if ( SUCCEEDED( hr ) ) |
| { |
| hr = E_FAIL; |
| |
| uno::Reference < io::XInputStream > xTempIn = createTempXInStreamFromIStream( m_xFactory, m_pOwnStream ); |
| if ( xTempIn.is() ) |
| { |
| uno::Reference< frame::XModel > aDocument( |
| m_xFactory->createInstance( getServiceNameFromGUID_Impl( &m_guid ) ), |
| uno::UNO_QUERY ); |
| if ( aDocument.is() ) |
| { |
| m_pDocHolder->SetDocument( aDocument ); |
| |
| uno::Reference< frame::XLoadable > xLoadable( m_pDocHolder->GetDocument(), uno::UNO_QUERY ); |
| if( xLoadable.is() ) |
| { |
| try |
| { |
| xLoadable->load( fillArgsForLoading_Impl( xTempIn, nStreamMode ) ); |
| m_pMasterStorage = pStg; |
| hr = m_pDocHolder->SetExtent( &aSizeToSet ); |
| // hr = m_pDocHolder->SetVisArea( &aRectToSet ); |
| } |
| catch( uno::Exception& ) |
| { |
| } |
| } |
| |
| if ( FAILED( hr ) ) |
| m_pDocHolder->CloseDocument(); |
| } |
| } |
| } |
| |
| if ( FAILED( hr ) ) |
| { |
| m_pOwnStream = CComPtr< IStream >(); |
| m_pExtStream = CComPtr< IStream >(); |
| hr = pStg->DestroyElement( reinterpret_cast<LPCWSTR>(aOfficeEmbedStreamName.getStr()) ); |
| hr = pStg->DestroyElement( reinterpret_cast<LPCWSTR>(aExtentStreamName.getStr()) ); |
| |
| OSL_ENSURE( SUCCEEDED( hr ), "Can not destroy created stream!\n" ); |
| if ( FAILED( hr ) ) |
| hr = E_FAIL; |
| } |
| |
| return hr; |
| } |
| |
| STDMETHODIMP EmbedDocument_Impl::Save( IStorage *pStgSave, BOOL fSameAsLoad ) |
| { |
| if ( !m_pDocHolder->GetDocument().is() || !m_xFactory.is() || !pStgSave || !m_pOwnStream || !m_pExtStream ) |
| return E_FAIL; |
| |
| CComPtr< IStream > pTargetStream; |
| CComPtr< IStream > pNewExtStream; |
| |
| if ( !fSameAsLoad && pStgSave != m_pMasterStorage ) |
| { |
| OSL_ENSURE( m_pMasterStorage, "How could the document be initialized without storage!??\n" ); |
| HRESULT hr = m_pMasterStorage->CopyTo( NULL, NULL, NULL, pStgSave ); |
| if ( FAILED( hr ) ) return E_FAIL; |
| |
| STATSTG aStat; |
| hr = pStgSave->Stat( &aStat, STATFLAG_NONAME ); |
| if ( FAILED( hr ) ) return E_FAIL; |
| |
| DWORD nStreamMode = aStat.grfMode; |
| hr = pStgSave->CreateStream( reinterpret_cast<LPCWSTR>(aOfficeEmbedStreamName.getStr()), |
| STGM_CREATE | ( nStreamMode & 0x73 ), |
| 0, |
| 0, |
| &pTargetStream ); |
| if ( FAILED( hr ) || !pTargetStream ) return E_FAIL; |
| |
| hr = pStgSave->CreateStream( reinterpret_cast<LPCWSTR>(aExtentStreamName.getStr()), |
| STGM_CREATE | ( nStreamMode & 0x73 ), |
| 0, |
| 0, |
| &pNewExtStream ); |
| if ( FAILED( hr ) || !pNewExtStream ) return E_FAIL; |
| } |
| else |
| { |
| pTargetStream = m_pOwnStream; |
| pNewExtStream = m_pExtStream; |
| } |
| |
| HRESULT hr = E_FAIL; |
| |
| const ::rtl::OUString aServiceName ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.io.TempFile" ) ); |
| uno::Reference < io::XOutputStream > xTempOut = uno::Reference < io::XOutputStream > ( |
| m_xFactory->createInstance ( aServiceName ), |
| uno::UNO_QUERY ); |
| |
| if ( xTempOut.is() ) |
| { |
| uno::Reference< frame::XStorable > xStorable( m_pDocHolder->GetDocument(), uno::UNO_QUERY ); |
| if( xStorable.is() ) |
| { |
| try |
| { |
| xStorable->storeToURL( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "private:stream" ) ), |
| fillArgsForStoring_Impl( xTempOut ) ); |
| hr = copyXTempOutToIStream( xTempOut, pTargetStream ); |
| if ( SUCCEEDED( hr ) ) |
| { |
| // no need to truncate the stream, the size of the stream is always the same |
| ULARGE_INTEGER nNewPos; |
| LARGE_INTEGER aZero = { 0L, 0L }; |
| hr = pNewExtStream->Seek( aZero, STREAM_SEEK_SET, &nNewPos ); |
| if ( SUCCEEDED( hr ) ) |
| { |
| SIZEL aSize; |
| hr = m_pDocHolder->GetExtent( &aSize ); |
| |
| if ( SUCCEEDED( hr ) ) |
| { |
| sal_uInt32 nWritten; |
| sal_Int8 aInf[EXT_STREAM_LENGTH]; |
| *((sal_Int32*)aInf) = 0; |
| *((sal_Int32*)&aInf[4]) = 0; |
| *((sal_Int32*)&aInf[8]) = aSize.cx; |
| *((sal_Int32*)&aInf[12]) = aSize.cy; |
| |
| hr = pNewExtStream->Write( (void*)aInf, EXT_STREAM_LENGTH, &nWritten ); |
| if ( nWritten != EXT_STREAM_LENGTH ) hr = E_FAIL; |
| |
| if ( SUCCEEDED( hr ) ) |
| { |
| m_pOwnStream = CComPtr< IStream >(); |
| m_pExtStream = CComPtr< IStream >(); |
| if ( fSameAsLoad || pStgSave == m_pMasterStorage ) |
| { |
| uno::Reference< util::XModifiable > xMod( m_pDocHolder->GetDocument(), uno::UNO_QUERY ); |
| if ( xMod.is() ) |
| xMod->setModified( sal_False ); |
| m_bIsDirty = sal_False; |
| } |
| } |
| } |
| } |
| } |
| } |
| catch( uno::Exception& ) |
| { |
| } |
| } |
| } |
| |
| return hr; |
| } |
| |
| STDMETHODIMP EmbedDocument_Impl::SaveCompleted( IStorage *pStgNew ) |
| { |
| // m_pOwnStream == NULL && m_pMasterStorage != NULL means the object is in NoScribble mode |
| // m_pOwnStream == NULL && m_pMasterStorage == NULL means the object is in HandsOff mode |
| |
| if ( m_pOwnStream || m_pExtStream ) |
| return E_UNEXPECTED; |
| |
| if ( !m_pMasterStorage && !pStgNew ) |
| return E_INVALIDARG; |
| |
| if ( pStgNew ) |
| m_pMasterStorage = pStgNew; |
| |
| STATSTG aStat; |
| HRESULT hr = m_pMasterStorage->Stat( &aStat, STATFLAG_NONAME ); |
| if ( FAILED( hr ) ) return E_OUTOFMEMORY; |
| |
| DWORD nStreamMode = aStat.grfMode; |
| hr = m_pMasterStorage->OpenStream( reinterpret_cast<LPCWSTR>(aOfficeEmbedStreamName.getStr()), |
| 0, |
| nStreamMode & 0x73, |
| 0, |
| &m_pOwnStream ); |
| if ( FAILED( hr ) || !m_pOwnStream ) return E_OUTOFMEMORY; |
| |
| hr = m_pMasterStorage->OpenStream( reinterpret_cast<LPCWSTR>(aExtentStreamName.getStr()), |
| 0, |
| nStreamMode & 0x73, |
| 0, |
| &m_pExtStream ); |
| if ( FAILED( hr ) || !m_pExtStream ) return E_OUTOFMEMORY; |
| |
| sal_Bool bModified = sal_False; |
| uno::Reference< util::XModifiable > xMod( m_pDocHolder->GetDocument(), uno::UNO_QUERY ); |
| if ( xMod.is() ) |
| bModified = xMod->isModified(); |
| |
| for ( AdviseSinkHashMapIterator iAdvise = m_aAdviseHashMap.begin(); iAdvise != m_aAdviseHashMap.end(); iAdvise++ ) |
| { |
| if ( iAdvise->second ) |
| iAdvise->second->OnSave(); |
| } |
| |
| if ( xMod.is() ) |
| bModified = xMod->isModified(); |
| |
| return S_OK; |
| } |
| |
| STDMETHODIMP EmbedDocument_Impl::HandsOffStorage() |
| { |
| m_pMasterStorage = CComPtr< IStorage >(); |
| m_pOwnStream = CComPtr< IStream >(); |
| m_pExtStream = CComPtr< IStream >(); |
| |
| return S_OK; |
| } |
| |
| //------------------------------------------------------------------------------- |
| // IPersistFile |
| |
| STDMETHODIMP EmbedDocument_Impl::Load( LPCOLESTR pszFileName, DWORD /*dwMode*/ ) |
| { |
| if ( m_pDocHolder->GetDocument().is() ) |
| return CO_E_ALREADYINITIALIZED; |
| |
| if ( !m_xFactory.is() ) |
| return E_FAIL; |
| |
| DWORD nStreamMode = STGM_CREATE | STGM_READWRITE | STGM_DELETEONRELEASE | STGM_SHARE_EXCLUSIVE; |
| HRESULT hr = StgCreateDocfile( NULL, |
| nStreamMode , |
| 0, |
| &m_pMasterStorage ); |
| |
| if ( FAILED( hr ) || !m_pMasterStorage ) return E_FAIL; |
| |
| ::rtl::OUString aCurType = getServiceNameFromGUID_Impl( &m_guid ); // ??? |
| CLIPFORMAT cf = (CLIPFORMAT)RegisterClipboardFormatA( "Embedded Object" ); |
| hr = WriteFmtUserTypeStg( m_pMasterStorage, |
| cf, // ??? |
| reinterpret_cast<LPWSTR>(( sal_Unicode* )aCurType.getStr()) ); |
| if ( FAILED( hr ) ) return E_FAIL; |
| |
| hr = m_pMasterStorage->SetClass( m_guid ); |
| if ( FAILED( hr ) ) return E_FAIL; |
| |
| hr = m_pMasterStorage->CreateStream( reinterpret_cast<LPCWSTR>(aOfficeEmbedStreamName.getStr()), |
| STGM_CREATE | ( nStreamMode & 0x73 ), |
| 0, |
| 0, |
| &m_pOwnStream ); |
| if ( FAILED( hr ) || !m_pOwnStream ) return E_FAIL; |
| |
| hr = m_pMasterStorage->CreateStream( reinterpret_cast<LPCWSTR>(aExtentStreamName.getStr()), |
| STGM_CREATE | ( nStreamMode & 0x73 ), |
| 0, |
| 0, |
| &m_pExtStream ); |
| if ( FAILED( hr ) || !m_pExtStream ) return E_FAIL; |
| |
| |
| uno::Reference< frame::XModel > aDocument( |
| m_xFactory->createInstance( getServiceNameFromGUID_Impl( &m_guid ) ), |
| uno::UNO_QUERY ); |
| if ( aDocument.is() ) |
| { |
| m_pDocHolder->SetDocument( aDocument, sal_True ); |
| |
| uno::Reference< frame::XLoadable > xLoadable( m_pDocHolder->GetDocument(), uno::UNO_QUERY ); |
| if( xLoadable.is() ) |
| { |
| try |
| { |
| xLoadable->load( fillArgsForLoading_Impl( uno::Reference< io::XInputStream >(), |
| STGM_READWRITE, |
| pszFileName ) ); |
| hr = S_OK; |
| |
| m_aFileName = ::rtl::OUString( reinterpret_cast<const sal_Unicode*>(pszFileName) ); |
| } |
| catch( uno::Exception& ) |
| { |
| } |
| } |
| |
| if ( hr == S_OK ) |
| { |
| ::rtl::OUString aCurType = getServiceNameFromGUID_Impl( &m_guid ); // ??? |
| CLIPFORMAT cf = (CLIPFORMAT)RegisterClipboardFormatA( "Embedded Object" ); |
| hr = WriteFmtUserTypeStg( m_pMasterStorage, |
| cf, // ??? |
| reinterpret_cast<LPWSTR>(( sal_Unicode* )aCurType.getStr()) ); |
| |
| if ( SUCCEEDED( hr ) ) |
| { |
| // no need to truncate the stream, the size of the stream is always the same |
| ULARGE_INTEGER nNewPos; |
| LARGE_INTEGER aZero = { 0L, 0L }; |
| hr = m_pExtStream->Seek( aZero, STREAM_SEEK_SET, &nNewPos ); |
| if ( SUCCEEDED( hr ) ) |
| { |
| SIZEL aSize; |
| hr = m_pDocHolder->GetExtent( &aSize ); |
| |
| if ( SUCCEEDED( hr ) ) |
| { |
| sal_uInt32 nWritten; |
| sal_Int8 aInf[EXT_STREAM_LENGTH]; |
| *((sal_Int32*)aInf) = 0; |
| *((sal_Int32*)&aInf[4]) = 0; |
| *((sal_Int32*)&aInf[8]) = aSize.cx; |
| *((sal_Int32*)&aInf[12]) = aSize.cy; |
| |
| hr = m_pExtStream->Write( (void*)aInf, EXT_STREAM_LENGTH, &nWritten ); |
| if ( nWritten != EXT_STREAM_LENGTH ) hr = E_FAIL; |
| } |
| } |
| } |
| |
| if ( SUCCEEDED( hr ) ) |
| m_bIsDirty = sal_True; |
| else |
| hr = E_FAIL; |
| } |
| |
| if ( FAILED( hr ) ) |
| { |
| m_pDocHolder->CloseDocument(); |
| m_pOwnStream = NULL; |
| m_pExtStream = NULL; |
| m_pMasterStorage = NULL; |
| } |
| } |
| |
| return hr; |
| } |
| |
| STDMETHODIMP EmbedDocument_Impl::Save( LPCOLESTR pszFileName, BOOL fRemember ) |
| { |
| if ( !m_pDocHolder->GetDocument().is() || !m_xFactory.is() ) |
| return E_FAIL; |
| |
| HRESULT hr = E_FAIL; |
| |
| // TODO/LATER: currently there is no hands off state implemented |
| try |
| { |
| uno::Reference< frame::XStorable > xStorable( m_pDocHolder->GetDocument(), uno::UNO_QUERY_THROW ); |
| |
| if ( !pszFileName ) |
| xStorable->store(); |
| else |
| { |
| util::URL aURL; |
| aURL.Complete = ::rtl::OUString( reinterpret_cast<const sal_Unicode*>( pszFileName ) ); |
| |
| ::rtl::OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.util.URLTransformer" ) ); |
| uno::Reference< util::XURLTransformer > aTransformer( m_xFactory->createInstance( aServiceName ), |
| uno::UNO_QUERY_THROW ); |
| |
| if ( aTransformer->parseSmart( aURL, ::rtl::OUString() ) && aURL.Complete.getLength() ) |
| { |
| if ( fRemember ) |
| { |
| xStorable->storeAsURL( aURL.Complete, fillArgsForStoring_Impl( uno::Reference< io::XOutputStream >() ) ); |
| m_aFileName = aURL.Complete; |
| } |
| else |
| xStorable->storeToURL( aURL.Complete, fillArgsForStoring_Impl( uno::Reference< io::XOutputStream >() ) ); |
| } |
| } |
| |
| hr = S_OK; |
| } |
| catch( uno::Exception& ) |
| { |
| } |
| |
| return hr; |
| } |
| |
| STDMETHODIMP EmbedDocument_Impl::SaveCompleted( LPCOLESTR pszFileName ) |
| { |
| // the different file name would mean error here |
| m_aFileName = ::rtl::OUString( reinterpret_cast<const sal_Unicode*>(pszFileName) ); |
| return S_OK; |
| } |
| |
| STDMETHODIMP EmbedDocument_Impl::GetCurFile( LPOLESTR *ppszFileName ) |
| { |
| CComPtr<IMalloc> pMalloc; |
| |
| HRESULT hr = CoGetMalloc( 1, &pMalloc ); |
| if ( FAILED( hr ) || !pMalloc ) return E_FAIL; |
| |
| *ppszFileName = (LPOLESTR)( pMalloc->Alloc( sizeof( sal_Unicode ) * ( m_aFileName.getLength() + 1 ) ) ); |
| wcsncpy( *ppszFileName, reinterpret_cast<LPCWSTR>(m_aFileName.getStr()), m_aFileName.getLength() + 1 ); |
| |
| return m_aFileName.getLength() ? S_OK : S_FALSE; |
| } |
| |
| // =============================================== |
| |
| LockedEmbedDocument_Impl EmbeddedDocumentInstanceAccess_Impl::GetEmbedDocument() |
| { |
| ::osl::MutexGuard aGuard( m_aMutex ); |
| return LockedEmbedDocument_Impl( m_pEmbedDocument ); |
| } |
| |
| void EmbeddedDocumentInstanceAccess_Impl::ClearEmbedDocument() |
| { |
| ::osl::MutexGuard aGuard( m_aMutex ); |
| m_pEmbedDocument = NULL; |
| } |
| |
| // =============================================== |
| |
| LockedEmbedDocument_Impl::LockedEmbedDocument_Impl() |
| : m_pEmbedDocument( NULL ) |
| {} |
| |
| LockedEmbedDocument_Impl::LockedEmbedDocument_Impl( EmbedDocument_Impl* pEmbedDocument ) |
| : m_pEmbedDocument( pEmbedDocument ) |
| { |
| if ( m_pEmbedDocument ) |
| m_pEmbedDocument->AddRef(); |
| } |
| |
| LockedEmbedDocument_Impl::LockedEmbedDocument_Impl( const LockedEmbedDocument_Impl& aDocLock ) |
| : m_pEmbedDocument( aDocLock.m_pEmbedDocument ) |
| { |
| if ( m_pEmbedDocument ) |
| m_pEmbedDocument->AddRef(); |
| } |
| |
| LockedEmbedDocument_Impl& LockedEmbedDocument_Impl::operator=( const LockedEmbedDocument_Impl& aDocLock ) |
| { |
| if ( m_pEmbedDocument ) |
| m_pEmbedDocument->Release(); |
| |
| m_pEmbedDocument = aDocLock.m_pEmbedDocument; |
| if ( m_pEmbedDocument ) |
| m_pEmbedDocument->AddRef(); |
| |
| return *this; |
| } |
| |
| LockedEmbedDocument_Impl::~LockedEmbedDocument_Impl() |
| { |
| if ( m_pEmbedDocument ) |
| m_pEmbedDocument->Release(); |
| } |
| |
| void LockedEmbedDocument_Impl::ExecuteMethod( sal_Int16 nId ) |
| { |
| if ( m_pEmbedDocument ) |
| { |
| if ( nId == OLESERV_SAVEOBJECT ) |
| m_pEmbedDocument->SaveObject(); |
| else if ( nId == OLESERV_CLOSE ) |
| m_pEmbedDocument->Close( 0 ); |
| else if ( nId == OLESERV_NOTIFY ) |
| m_pEmbedDocument->notify(); |
| else if ( nId == OLESERV_NOTIFYCLOSING ) |
| m_pEmbedDocument->OLENotifyClosing(); |
| else if ( nId == OLESERV_SHOWOBJECT ) |
| m_pEmbedDocument->ShowObject(); |
| else if ( nId == OLESERV_DEACTIVATE ) |
| m_pEmbedDocument->Deactivate(); |
| } |
| } |
| |
| // Fix strange warnings about some |
| // ATL::CAxHostWindow::QueryInterface|AddRef|Releae functions. |
| // warning C4505: 'xxx' : unreferenced local function has been removed |
| #if defined(_MSC_VER) |
| #pragma warning(disable: 4505) |
| #endif |
| |